2010. 3. 11. 17:48

Problem AtlGetObjectSourceInterface with Delphi ActiveX

AtlGetObjectSourceInterface는 IProvideClassInfo2 와 IPersist interface를 이용하여 source interface를 얻어온다. 하지만 Delphi로 만든 ActiveX 중에는 이 2가지 interface를 지원하지 않는 경우가 있으며 이 경우 위 함수가 실패하여 event에 대한 정보를 얻는데 문제가 발생한다.

아래코드가 대안이 될 수 있다.




Try out the following code :

int main()
{
   ITypeLib* pITypeLib = NULL;
   HRESULT   hrRet = S_OK;

   hrRet = LoadTypeLibEx
   ( 
      (LPCOLESTR)(L"C:\\WINDOWS\\system32\\FM20.DLL"), 
      (ITypeLib**)&pITypeLib
   );

   if (pITypeLib)
   {
      ITypeInfo *pITypeInfo_Coclass = NULL;
      CLSID      clsid;

      CLSIDFromString
      (
         L"{8BD21D40-EC42-11CE-9E0D-00AA006002F3}",
         &clsid
      );
      
      pITypeLib -> GetTypeInfoOfGuid(clsid, &pITypeInfo_Coclass);

      if (pITypeInfo_Coclass)
      {
         TYPEATTR*     pTYPEATTR = NULL ;

         pITypeInfo_Coclass -> GetTypeAttr (&pTYPEATTR);

         // For each implemented interface in this coclass, get its name and determine if it is the default interface.
         int i ;
         for (i = 0 ; i < (pTYPEATTR->cImplTypes); i ++) 
         {
            HREFTYPE hRefType = NULL;
     
            pITypeInfo_Coclass->GetRefTypeOfImplType (i, &hRefType);

            if (hRefType)
            {
        ITypeInfo*     pRefTypeInfo = NULL;
        BSTR          bstrName = NULL;

               pITypeInfo_Coclass->GetRefTypeInfo (hRefType, &pRefTypeInfo);

               if (pRefTypeInfo)
        {
                  pRefTypeInfo->GetDocumentation(MEMBERID_NIL, &bstrName, NULL, NULL, NULL);

           int iImplTypeFlags = 0;

                  pITypeInfo_Coclass->GetImplTypeFlags
           (
              i,
              &iImplTypeFlags
           );

                  if (iImplTypeFlags & IMPLTYPEFLAG_FDEFAULT)
           {
                     if (iImplTypeFlags & IMPLTYPEFLAG_FSOURCE)
              {
          printf ("[default, source] interface is [%s].\r\n", (LPCTSTR)_bstr_t(bstrName));
              }
              else
              {
          printf ("[default] interface is [%s].\r\n", (LPCTSTR)_bstr_t(bstrName));
              }
           }

           pRefTypeInfo->Release();
           pRefTypeInfo = NULL;
               }

               if (bstrName)
        {
           ::SysFreeString(bstrName);
           bstrName = NULL;
        }
            }
         }

         pITypeInfo_Coclass->ReleaseTypeAttr(pTYPEATTR);
         pTYPEATTR = NULL;

         pITypeInfo_Coclass->Release();
         pITypeInfo_Coclass = NULL;
      }

      pITypeLib->Release();
      pITypeLib = NULL;
   }

   return 0;
}


Note that there could be two default interfaces : one being the default incoming interface (i.e. [default]) and the other a default source interface (i.e. [default, source]. 

The important method to use is ITypeInfo::GetImplTypeFlags(). Call it on the ITypeInfo interface of the coclass that you are interested in e.g. :

pITypeInfo_Coclass->GetImplTypeFlags
(
   i,
   &iImplTypeFlags
);

This method will return a IMPLTYPEFLAGS. The code to obtain the default interface should be self-explanatory.

The calls to GetRefTypeOfImplType() and GetRefTypeInfo() are so that we can get the ITypeInfo interface on each of the interfaces of the coclass.