Microsoft KB Archive/237771

= BUG: "0x80070057 (E_INVALIDARG - The parameter is incorrect)" error message when you use an ATL to catch an event when an enum is used as a parameter of the event =

Article ID: 237771

Article Last Modified on 9/1/2005

-

APPLIES TO

 Microsoft ActiveX Template Library 3.0, when used with:  Microsoft Visual C++ 6.0 Enterprise Edition

 Microsoft Visual C++ 6.0 Professional Edition

 Microsoft Visual C++ 6.0 Standard Edition 

-

<div class="notice_section">

This article was previously published under Q237771

<div class="symptoms_section">

SYMPTOMS
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.

<div class="cause_section">

CAUSE
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.

<div class="resolution_section">

RESOLUTION
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 classes

If you are using IDispEventImpl<> for the sink, you can override the virtual function GetFuncInfoFromID. A simple override is 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); if (SUCCEEDED(hr)) {       // is this the correct event interface if (InlineIsEqualGUID(iid, DIID__IEnumEventEvents)) {           //check for dispid of event with enum param switch(dispidMember) {               case 1: // 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[0] == VT_USERDEFINED) info.pVarTypes[0] = VT_I4; break; }       }    }    return hr; } 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. if (pta && pta->typekind == TKIND_ENUM) {   vt = VT_I4; }

<div class="status_section">

STATUS
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.

<div class="references_section">