An ATL event sink defined with SINK_ENTRY or SINK_ENTRY_EX will fail to catch an event when an enum is used as one of the parameters for the event. The failure code returned by IDispatch::Invoke is "0x80070057 (E_INVALIDARG - The parameter is incorrect)." The event will succeed in another container, such as Visual Basic.
IDispEventImpl's GetFuncInfoFromID method checks the type of the event parameters and, on encountering type VT_USERDEFINED, calls GetUserDefinedType. This method currently checks only for TKIND_ALIAS ("typedef struct" data types) and not TKIND_ENUM.
There are several ways to work around this problem. One method is to use the SINK_ENTRY_INFO macro and define an _ATL_FUNC_INFO structure to provide type information for the event method. Use a VT_I4 type for the enum parameter. For more information about SINK_ENTRY_INFO, click the following article number to view the article in the Microsoft Knowledge Base:
194179 AtlEvnt.exe sample shows how to create ATL sinks by using the ATL IDispEventImpl and IDispEventSimpleImpl classesIf you are using IDispEventImpl<> for the sink, you can override the virtual function GetFuncInfoFromID. A simple override is as follows.
The most direct approach when using IDispEventImpl<>is to change the implementation of GetUserDefinedType in Atlcom.h. At line 3968, after the code block that begins "if(pta && pta->typekind == TKIND_ALIAS)", a second if statement could be inserted that would set the correct VARTYPE for enumerations. This block could be written as follows.
HRESULT GetFuncInfoFromId(const IID& iid, DISPID dispidMember,LCID lcid, _ATL_FUNC_INFO& info)
// class base class implementation
HRESULT hr = IDispEventImpl<IDC_OBJ, CSinkObj, &DIID__IEnumEventEvents, &LIBID_TESTUNKARTICLELib, 1, 0>::GetFuncInfoFromId(iid, dispidMember,lcid, info);
// is this the correct event interface
if (InlineIsEqualGUID(iid, DIID__IEnumEventEvents))
//check for dispid of event with enum param
// the enumeration parameter is change to VT_I4
// info.pVarTypes represents the type of params
// params are stored in reverse order, with 0 base index
if (info.pVarTypes == VT_USERDEFINED)
info.pVarTypes = VT_I4;
if (pta && pta->typekind == TKIND_ENUM)
vt = VT_I4;
Microsoft has confirmed that this is a bug in the Microsoft products that are listed in the "Applies to" section.This problem was corrected in Microsoft Visual C++ .NET.
For more information, click the following article numbers to view the articles in the Microsoft Knowledge Base:
194179 AtlEvnt.exe sample shows how to creates ATL sinks by using the ATL IDispEventImpl and IDispEventSimpleImpl classes
181277 The AtlSink.exe sample demonstrates how to implement a dispinterface sink by using the Active Template Library (ATL) in Visual C++See also the ATL Articles in the Visual C++ documentation, specifically "ATL Collections and Enumerators" and "Event Handling in ATL."
Article ID: 237771 - Last Review: Sep 1, 2005 - Revision: 1