BUG: ATL Connection Point Wizard-Generated Code for Event with [out]VARIANT* or [out]long* Argument Gives C4305 Warning (264985)
The information in this article applies to:
- Microsoft Visual C++, 32-bit Enterprise Edition 6.0
- Microsoft Visual C++, 32-bit Professional Edition 6.0
- Microsoft Visual C++, 32-bit Learning Edition 6.0
- The Microsoft Active Template Library (ATL) 3.0
This article was previously published under Q264985 SYMPTOMS
The ATL Connection Point wizard generates a proxy class that implements a connection point for an outgoing interface. If an outgoing interface has an event that takes an argument of type [out]VARIANT* or [out]long*, the wizard generates incorrect code in the outgoing call ( Fire_ method) for that event. The Visual C++ compiler gives the following two warnings when you call this Fire_ method in your code:
warning C4305: 'argument' : truncation from 'struct tagVARIANT *' to 'bool'
warning C4800: 'struct tagVARIANT *' : forcing value to bool 'true' or 'false' (performance warning)
warning C4305: 'argument' : truncation from 'long *' to 'bool'
warning C4800: 'long *' : forcing value to bool 'true' or 'false' (performance warning)
CAUSE
When you use the Connection Point Wizard, incorrect code is generated in the Fire_ method for the event that takes [out]VARIANT* or [out]long* as a parameter. For Event1, with VARIANT* and long* parameters pVar and pLongVal, it generates the following code in the Fire_Event1 method of the proxy class:
pvars[0] = pVar;
pvars[1] = pLongVal;
You receive this error because ATL-generated code directly assigns a VARIANT* and a long* to a CComVariant type. Therefore, the compiler assumes that a CComVariant overloaded operator for these data types is defined; when the compiler does not find one, it considers these values as Boolean and the warning is generated.
RESOLUTION
The following are two workarounds for this problem:
- Change the wizard-generated code from the following
pvars[0] = pVar;
pvars[1] = pLongVal;
to the following:
pvars[0].vt = VT_BYREF|VT_VARIANT;
pvars[0].pvarVal = pVar;
pvars[1].vt = VT_BYREF|VT_I4;
pvars[1].plVal = pLongVal;
The drawback of this approach is that every time that you add a method to your connection point interface and ask the wizard to implement the connection points, the earlier changes that you made will be overwritten and you will lose your changes. Make sure you back up your changes before allowing the wizard to implement the interface.
-
Modify the CComVariant class in the AtlBase.h file, and provide overloaded "=" operators for VARIANT* and long*. A sample implementation might resemble the following:
CComVariant& operator=(long* nSrc)
{
if (vt != VT_I4)
{
InternalClear();
vt = VT_BYREF|VT_I4;
}
plVal = nSrc;
return *this;
}
CComVariant& operator=(const VARIANT* nSrc)
{
InternalCopy(nSrc);
return *this;
}
Make these modifications to a copy of the AtlBase.h file (for instance, FixAtlBase.h). Then, in Stdafx.h, comment out AtlBase.h and use FixAtlBase.h instead, as follows:
// #include <atlbase.h>
#include "FixAtlBase.h"
This technique works only in Debug or ReleaseMinDependency builds. This technique does not work in ReleaseMinSize builds because the ATL.dll file is used, not the code in FixAtlBase.h.
STATUSMicrosoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article. REFERENCES
For more information, see the "Adding Connection Points to an ATL Object" topic on the Microsoft Developer Network (MSDN) Web site:
For additional information, click the article number below
to view the article in the Microsoft Knowledge Base:
250847 ATL Connection Point Wizard Generated Code for Event with VARIANT Argument Gives C4305 Warning
Modification Type: | Major | Last Reviewed: | 12/11/2003 |
---|
Keywords: | kbBug kbConnPts kbpending KB264985 |
---|
|