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



The information in this article applies to:

  • The Microsoft Active Template Library (ATL) 3.0, when used with:
    • 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

This article was previously published under Q266713

SYMPTOMS

The way that ATL implements the IDispatch::GetIDsOfNames function may result in E_FAIL being returned, even when the call succeeds.

CAUSE

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.

RESOLUTION

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"
				

STATUS

Microsoft has confirmed that this is a bug in the Microsoft products that are listed in the "Applies to" section.

Modification Type:MinorLast Reviewed:9/26/2005
Keywords:kbHotfixServer kbQFE kbBug kbpending KB266713 kbAudDeveloper