BUG: IDispatch:GetIDsOfNames function may return E_FAIL even when the call succeeds

This article has been archived. It is offered "as is" and will no longer be updated.
The way that ATL implements the IDispatch::GetIDsOfNames function may result in E_FAIL being returned, even when the call succeeds.
When multiple threads call into an object's IDispatch::GetIDsOfNames function, the CComTypeInfoHolder::GetTI function is eventually called to load the type library and get the ITypeInfo interface. Because loading the type library and retrieving the interface are protected by a critical section, the second thread waits for the first thread to finish. Once the first thread releases the critical section, the second thread enters the critical section, finds m_pInfo is non-NULL (set by the first thread), and returns the hRes, which is set to E_FAIL. The IDispatch::GetIDsNames function eventually returns this E_FAIL.
To work around this problem, the CComTypeInfoHolder::GetTI function in the Atlcom.h file must be modified as follows (all changes are marked with the comments "ADD" and "END ADD"):
inline HRESULT CComTypeInfoHolder::GetTI(LCID lcid){   // If this assert occurs, probably didn't initialize properly.   ATLASSERT(m_plibid != NULL && m_pguid != NULL);   ATLASSERT(!InlineIsEqualGUID(*m_plibid, GUID_NULL)       && "Did you forget to pass the LIBID to CComModule::Init?");   if (m_pInfo != NULL)      return S_OK;   HRESULT hRes = E_FAIL;   EnterCriticalSection(&_Module.m_csTypeInfoHolder);   if (m_pInfo == NULL)   {      ITypeLib* pTypeLib;      hRes = LoadRegTypeLib(*m_plibid, m_wMajor, m_wMinor, lcid, &pTypeLib);      if (SUCCEEDED(hRes))      {	 CComPtr<ITypeInfo> spTypeInfo;	 hRes = pTypeLib->GetTypeInfoOfGuid(*m_pguid, &spTypeInfo);	 if (SUCCEEDED(hRes))	 {	    CComPtr<ITypeInfo> spInfo(spTypeInfo);	    CComPtr<ITypeInfo2> spTypeInfo2;	    if (SUCCEEDED(spTypeInfo->QueryInterface(&spTypeInfo2)))	        spInfo = spTypeInfo2;  	    LoadNameCache(spInfo);	    m_pInfo = spInfo.Detach();	 }	 pTypeLib->Release();      }    }    //ADD    else    { 	hRes = S_OK;    }    //END ADD    LeaveCriticalSection(&_Module.m_csTypeInfoHolder);    _Module.AddTermFunc(Cleanup, (DWORD)this);    return hRes;}				
Make these modifications to a copy of the Atlcom.h file (for example, Fixatlcom.h). Comment out Atlcom.h in the Stdafx.h file, and then use Fixatlcom.h instead, as follows:
//#include <atlcom.h>#include "FixAtlCom.h"				
Microsoft has confirmed that this is a bug in the Microsoft products that are listed in the "Applies to" section.
IDispatch Invoke 0x80004005 80004005

Article ID: 266713 - Last Review: 01/11/2015 03:43:11 - Revision: 4.0

  • Microsoft ActiveX Template Library 3.0
  • kbnosurvey kbarchive kbhotfixserver kbqfe kbbug kbpending KB266713