天天看點

COM元件的類廠(COM技術内幕筆記之四)

 在上一篇中,介紹了怎麼樣用動态連結庫去實作COM,但元件對我們來說仍是不透明的,我們需要知道實作元件DLL的位置,必須自己來加載元件的CreateInstance函數來獲得元件的指針.在書中第一篇就曾經提到過:COM元件可以透明地在網絡上(或本地)被重新配置設定位置,而不會影響本地客戶程式.是以,由用戶端來調用DLL并不是什麼好主意.必須有一種更好的辦法讓元件的實作更透明,更靈活!

    于是,就引入了類廠的概念.什麼是類廠,類廠也是一個接口,它的職責是幫我們創造元件的對象.并傳回給客戶程式一個接口的指針.每個元件都必須有一個與之相關的類廠,這個類廠知道怎麼樣建立元件.當客戶請求一個元件對象的執行個體時,實際上這個請求交給了類廠,由類廠建立元件執行個體,然後把執行個體指針交給客戶程式。這麼說有點難明白.先看一個僞執行個體.

 1.實作二個接口IX,IY        (上二節中有詳細介紹)

 2.實作一個元件CA,實作了IX,IY接口.    (上二節中有詳細介紹)

 3.對于這個元件進行注冊,把元件的資訊加入到系統資料庫中.

     實作DllRegisterServer和DllUnregisterServer函數.函數具體功能就是把本元件的CLSID,ProgID,DLL的位置放入系統資料庫中.這樣程式就可以通過查詢系統資料庫來獲得元件的位置.

 4.建立本元件類廠的執行個體

class CFactory:public IClassFactory

{

 virtual HRESULT __stdcall QueryInterface(const IID& iid,void** ppv);

 virtual ULONG   __stdcall AddRef();

 virtual ULONG   __stdcall Release();

 virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,

  const IID& iid,

  void** ppv);

}

 在類廠執行個體中,主要的功能就是CreateInstance了,這個函數就是建立元件的相應執行個體.看它的實作:

HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,const IID& iid,void** ppv)

{

   //...

 CA* pA = new CA;

 if(pA == NULL)

  return E_OUTOFMEMORY;

 HRESULT hr = pA->QueryInterface(iid,ppv);

 pA->Release();

 return hr;

}

 5.在這個元件的DLL中導出DllGetClassObject函數.這個函數的功能就是建立類廠的執行個體對象并查詢接口.看其實作:

STDAPI DllGetClassObject(const CLSID& clsid,

       const IID& iid,

       void** ppv)

{

 //....

 CFactory* pFactory = new CFactory();

 if(pFactory == NULL)

  return E_OUTOFMEMORY;

 HRESULT hr = pFactory->QueryInterface(iid,ppv);

 pFactory->Release();

 return hr;

}

元件的實作差不多就這麼多,下面在用戶端怎麼調用元件呢?這就需要用到COM函數庫了,由COM函數庫去查找系統資料庫,調用元件的類廠,建立元件執行個體,傳回接口.如下所示:

IUnknown* pUnk = NULL;

IX* iX = NULL;

CoInitialize(NULL);

CoCreateInstance(CLSID_Component1,CLSCTX_INPROC_SERVER,IID_IUnknown,(void**)&pUnk);

pUnk->QueryInterface(IID_IX,(void**)&iX);

pUnk->Release();

iX->Fx();

iX->Release();

CoUninitialize();

至于客戶是通過CoCreateInstance怎麼獲得元件的類廠,建立元件執行個體的.下面摘錄的一篇文章很清晰的說明了這一切:

-------------------------------------------------------------------------------------

這部分我們将構造一個建立COM元件的最小架構結構,然後看一看其内部處理流程是怎樣的

COM元件的運作機制,即COM是怎麼跑起來的。

    IUnknown *pUnk=NULL;

    IObject *pObject=NULL;

    CoInitialize(NULL);

    CoCreateInstance(CLSID_Object, CLSCTX_INPROC_SERVER, NULL, IID_IUnknown, (void**)&pUnk);

    pUnk->QueryInterface(IID_IOjbect, (void**)&pObject);

    pUnk->Release();

    pObject->Func();

    pObject->Release();

    CoUninitialize();

  CoCreateInstance身上,讓我們來看看它内部做了一些什麼事情。以下是它内部實作的一個僞代碼:

    CoCreateInstance(....)

    {

      .......

      IClassFactory *pClassFactory=NULL;

      CoGetClassObject(CLSID_Object, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void **)&pClassFactory);

      pClassFactory->CreateInstance(NULL, IID_IUnknown, (void**)&pUnk);

      pClassFactory->Release();

      ........

    }

  這段話的意思就是先得到類廠對象,再通過類廠建立元件進而得到IUnknown指針。

  繼續深入一步,看看CoGetClassObject的内部僞碼:

    CoGetClassObject(.....)

    {

      //通過查系統資料庫CLSID_Object,得知元件DLL的位置、檔案名

      //裝入DLL庫

      //使用函數GetProcAddress(...)得到DLL庫中函數DllGetClassObject的函數指針。

      //調用DllGetClassObject

    } 

  DllGetClassObject是幹什麼的,它是用來獲得類廠對象的。隻有先得到類廠才能去建立元件.

  下面是DllGetClassObject的僞碼:

   DllGetClassObject(...)

   {

      ......

      CFactory* pFactory= new CFactory; //類廠對象

      pFactory->QueryInterface(IID_IClassFactory, (void**)&pClassFactory);

      //查詢IClassFactory指針

      pFactory->Release();

      ......

   }

CoGetClassObject的流程已經到此為止,現在傳回CoCreateInstance,看看CreateInstance的僞碼:

   CFactory::CreateInstance(.....)

   {

      ...........

      CObject *pObject = new CObject; //元件對象

      pObject->QueryInterface(IID_IUnknown, (void**)&pUnk);

      pObject->Release();

      ...........

   } 

  下圖是從COM+技術内幕中COPY來的一個例圖,從圖中可以清楚的看到CoCreateInstance的整個流程。

COM元件的類廠(COM技術内幕筆記之四)

接下來就寫下完全的源代碼,說明類廠的概念:

Component實作:(FacInterFace.dll)

COM元件的類廠(COM技術内幕筆記之四)

// In FACE.H

COM元件的類廠(COM技術内幕筆記之四)

#ifndef _IFACE_H

COM元件的類廠(COM技術内幕筆記之四)

#define  _IFACE_H

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// interfaces

COM元件的類廠(COM技術内幕筆記之四)

interface IX:IUnknown

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    virtual void __stdcall Fx() = 0;

COM元件的類廠(COM技術内幕筆記之四)

};

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

interface IY: IUnknown

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    virtual void __stdcall Fy() = 0;

COM元件的類廠(COM技術内幕筆記之四)

};

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

interface IZ: IUnknown

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    virtual void __stdcall Fz() = 0;

COM元件的類廠(COM技術内幕筆記之四)

};

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// Forward references for GUIDs

COM元件的類廠(COM技術内幕筆記之四)

extern   " C "

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    extern const IID IID_IX;

COM元件的類廠(COM技術内幕筆記之四)

    extern const IID IID_IY;

COM元件的類廠(COM技術内幕筆記之四)

    extern const IID IID_IZ;

COM元件的類廠(COM技術内幕筆記之四)

    extern const CLSID CLSID_Component1;

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

extern   " C " 

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

// {A33D4226-0F56-4e34-91F3-BF4F85761101}

COM元件的類廠(COM技術内幕筆記之四)

static const IID IID_IX = 

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{ 0xa33d4226, 0xf56, 0x4e34, 

COM元件的類廠(COM技術内幕筆記之四)

{ 0x91, 0xf3, 0xbf, 0x4f, 0x85, 0x76, 0x11, 0x1 } };

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// {41A5F090-B33A-4ae8-A1BB-EF2D0B4F8B0E}

COM元件的類廠(COM技術内幕筆記之四)

static const IID IID_IY = 

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{ 0x41a5f090, 0xb33a, 0x4ae8, 

COM元件的類廠(COM技術内幕筆記之四)

{ 0xa1, 0xbb, 0xef, 0x2d, 0xb, 0x4f, 0x8b, 0xe } };

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// {65411881-4E05-4b71-9CB5-943D5E0787C4}

COM元件的類廠(COM技術内幕筆記之四)

static const IID IID_IZ = 

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{ 0x65411881, 0x4e05, 0x4b71, 

COM元件的類廠(COM技術内幕筆記之四)

{ 0x9c, 0xb5, 0x94, 0x3d, 0x5e, 0x7, 0x87, 0xc4 } };

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

//元件的CLSID,每個元件都有唯一的CLSID,需要把此CLSID添加到系統資料庫中去.如何添加,見Register.cpp檔案.

COM元件的類廠(COM技術内幕筆記之四)

//  {282D8F98-BC89-43d5-9225-0B1BB479CBDE}

COM元件的類廠(COM技術内幕筆記之四)

static   const  CLSID CLSID_Component1  = 

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{ 0x282d8f98, 0xbc89, 0x43d5, 

COM元件的類廠(COM技術内幕筆記之四)

{ 0x92, 0x25, 0xb, 0x1b, 0xb4, 0x79, 0xcb, 0xde } };

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

#endif

元件的注冊:

COM元件的類廠(COM技術内幕筆記之四)

// In Register.h

COM元件的類廠(COM技術内幕筆記之四)

HRESULT RegisterServer(HMODULE hModule,                const  CLSID &  clsid,                const   char *  szFriendlyName,            const   char *  szVerIndProgID,            const   char *  szProgID);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

HRESULT UnRegisterServer( const  CLSID &  clsid,          const   char *  szVerIndProgID,          const   char *  szProgID);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// In Register.cpp

COM元件的類廠(COM技術内幕筆記之四)

// 此檔案是如何注冊元件的代碼實作,是把CLSID,ProgID,Version,Dll位置添加到

COM元件的類廠(COM技術内幕筆記之四)

// HKEY_CLASSES_ROOT/CLSID,HKEY_CLASSES_ROOT的子鍵中去.

COM元件的類廠(COM技術内幕筆記之四)

#include  < objbase.h >

COM元件的類廠(COM技術内幕筆記之四)

#include  < assert.h >

COM元件的類廠(COM技術内幕筆記之四)

#include  " Register.h "

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// set the given key and its value;

COM元件的類廠(COM技術内幕筆記之四)

BOOL setKeyAndValue( const   char *  pszPath,

COM元件的類廠(COM技術内幕筆記之四)

                     const   char *  szSubkey,

COM元件的類廠(COM技術内幕筆記之四)

                     const   char *  szValue);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// Convert a CLSID into a char string

COM元件的類廠(COM技術内幕筆記之四)

void  CLSIDtochar( const  CLSID &  clsid,

COM元件的類廠(COM技術内幕筆記之四)

                  char *  szCLSID,

COM元件的類廠(COM技術内幕筆記之四)

                  int  length);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// Delete szKeyChild and all of its descendents

COM元件的類廠(COM技術内幕筆記之四)

LONG recursiveDeleteKey(HKEY hKeyParent, const   char *  szKeyChild);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// size of a CLSID as a string

COM元件的類廠(COM技術内幕筆記之四)

const   int  CLSID_STRING_SIZE  =   39 ;

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// Register the component in the registry

COM元件的類廠(COM技術内幕筆記之四)

HRESULT RegisterServer(HMODULE hModule,

COM元件的類廠(COM技術内幕筆記之四)

                        const  CLSID &  clsid,

COM元件的類廠(COM技術内幕筆記之四)

                        const   char *  szFriendlyName,

COM元件的類廠(COM技術内幕筆記之四)

                        const   char *  szVerIndProgID,

COM元件的類廠(COM技術内幕筆記之四)

                        const   char *  szProgID)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    //Get the Server location

COM元件的類廠(COM技術内幕筆記之四)

    char szModule[512];

COM元件的類廠(COM技術内幕筆記之四)

    DWORD dwResult = ::GetModuleFileName(hModule,szModule,sizeof(szModule)/sizeof(char));

COM元件的類廠(COM技術内幕筆記之四)

    assert(dwResult!=0);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Convert the CLSID into a char

COM元件的類廠(COM技術内幕筆記之四)

    char szCLSID[CLSID_STRING_SIZE];

COM元件的類廠(COM技術内幕筆記之四)

    CLSIDtochar(clsid,szCLSID,sizeof(szCLSID));

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Build the key CLSID//{}

COM元件的類廠(COM技術内幕筆記之四)

    char szKey[64];

COM元件的類廠(COM技術内幕筆記之四)

    strcpy(szKey,"CLSID//");

COM元件的類廠(COM技術内幕筆記之四)

    strcat(szKey,szCLSID);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Add the CLSID to the registry

COM元件的類廠(COM技術内幕筆記之四)

    setKeyAndValue(szKey,NULL,szFriendlyName);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Add the Server filename subkey under the CLSID key

COM元件的類廠(COM技術内幕筆記之四)

    setKeyAndValue(szKey,"InprocServer32",szModule);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    setKeyAndValue(szKey,"ProgID",szProgID);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    setKeyAndValue(szKey,"VersionIndependentProgID",szVerIndProgID);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Add the version-independent ProgID subkey under HKEY_CLASSES_ROOT

COM元件的類廠(COM技術内幕筆記之四)

    setKeyAndValue(szVerIndProgID,NULL,szFriendlyName);

COM元件的類廠(COM技術内幕筆記之四)

    setKeyAndValue(szVerIndProgID,"CLSID",szCLSID);

COM元件的類廠(COM技術内幕筆記之四)

    setKeyAndValue(szVerIndProgID,"CurVer",szProgID);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Add the versioned ProgID subkey under HKEY_CLASSES_ROOT

COM元件的類廠(COM技術内幕筆記之四)

    setKeyAndValue(szProgID,NULL,szFriendlyName);

COM元件的類廠(COM技術内幕筆記之四)

    setKeyAndValue(szProgID,"CLSID",szCLSID);

COM元件的類廠(COM技術内幕筆記之四)

    return S_OK;

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

//

COM元件的類廠(COM技術内幕筆記之四)

// Remove the component from the register

COM元件的類廠(COM技術内幕筆記之四)

//

COM元件的類廠(COM技術内幕筆記之四)

HRESULT UnRegisterServer( const  CLSID &  clsid,            //  Class ID

COM元件的類廠(COM技術内幕筆記之四)

                          const   char *  szVerIndProgID,    //  Programmatic

COM元件的類廠(COM技術内幕筆記之四)

                          const   char *  szProgID)            //  IDs

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    //Convert the CLSID into a char.

COM元件的類廠(COM技術内幕筆記之四)

    char szCLSID[CLSID_STRING_SIZE];

COM元件的類廠(COM技術内幕筆記之四)

    CLSIDtochar(clsid,szCLSID,sizeof(szCLSID));

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Build the key CLSID//{

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)

    char szKey[64];

COM元件的類廠(COM技術内幕筆記之四)

    strcpy(szKey,"CLSID//");

COM元件的類廠(COM技術内幕筆記之四)

    strcat(szKey,szCLSID);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Delete the CLSID key - CLSID/{

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)

    LONG lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT,szKey);

COM元件的類廠(COM技術内幕筆記之四)

    assert((lResult == ERROR_SUCCESS) || (lResult == ERROR_FILE_NOT_FOUND));

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Delete the version-independent ProgID Key

COM元件的類廠(COM技術内幕筆記之四)

    lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT,szVerIndProgID);

COM元件的類廠(COM技術内幕筆記之四)

    assert((lResult == ERROR_SUCCESS) || (lResult == ERROR_FILE_NOT_FOUND));

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Delete the ProgID key.

COM元件的類廠(COM技術内幕筆記之四)

    lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT,szProgID);

COM元件的類廠(COM技術内幕筆記之四)

    assert((lResult == ERROR_SUCCESS) || (lResult == ERROR_FILE_NOT_FOUND));

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    return S_OK;

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// Convert a CLSID to a char string

COM元件的類廠(COM技術内幕筆記之四)

void  CLSIDtochar( const  CLSID &  clsid,

COM元件的類廠(COM技術内幕筆記之四)

                  char *  szCLSID,

COM元件的類廠(COM技術内幕筆記之四)

                  int  length)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    assert(length>=CLSID_STRING_SIZE);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Get CLSID

COM元件的類廠(COM技術内幕筆記之四)

    LPOLESTR wszCLSID = NULL;

COM元件的類廠(COM技術内幕筆記之四)

    HRESULT hr = StringFromCLSID(clsid,&wszCLSID);

COM元件的類廠(COM技術内幕筆記之四)

    assert(SUCCEEDED(hr));

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Convert from wide characters to non_wide

COM元件的類廠(COM技術内幕筆記之四)

    wcstombs(szCLSID,wszCLSID,length);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Free memory

COM元件的類廠(COM技術内幕筆記之四)

    CoTaskMemFree(wszCLSID);

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

//

COM元件的類廠(COM技術内幕筆記之四)

//  Delete a Key and all of its descendents

COM元件的類廠(COM技術内幕筆記之四)

//

COM元件的類廠(COM技術内幕筆記之四)

LONG recursiveDeleteKey(HKEY hKeyParent, const   char *  lpszKeyChild)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    //Open the child.

COM元件的類廠(COM技術内幕筆記之四)

    HKEY hKeyChild;

COM元件的類廠(COM技術内幕筆記之四)

    LONG lRes = RegOpenKeyEx(hKeyParent,lpszKeyChild,0,KEY_ALL_ACCESS,&hKeyChild);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    if(lRes != ERROR_SUCCESS)

COM元件的類廠(COM技術内幕筆記之四)

        return lRes;

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Enumerate all of the decendents of this child

COM元件的類廠(COM技術内幕筆記之四)

    FILETIME time;

COM元件的類廠(COM技術内幕筆記之四)

    char szBuffer[256];

COM元件的類廠(COM技術内幕筆記之四)

    DWORD dwSize = 256 ;

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    while(RegEnumKeyEx(hKeyChild,0,szBuffer,&dwSize,NULL,

COM元件的類廠(COM技術内幕筆記之四)

        NULL,NULL,&time) == S_OK)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        //Delete the decendents of this child.

COM元件的類廠(COM技術内幕筆記之四)

        lRes = recursiveDeleteKey(hKeyChild,szBuffer);

COM元件的類廠(COM技術内幕筆記之四)

        if(lRes != ERROR_SUCCESS)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

            RegCloseKey(hKeyChild);

COM元件的類廠(COM技術内幕筆記之四)

            return lRes;

COM元件的類廠(COM技術内幕筆記之四)

        }

COM元件的類廠(COM技術内幕筆記之四)

        dwSize = 256;

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)

    RegCloseKey(hKeyChild);

COM元件的類廠(COM技術内幕筆記之四)

    return RegDeleteKey(hKeyParent,lpszKeyChild);

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

BOOL setKeyAndValue( const   char *  szKey,

COM元件的類廠(COM技術内幕筆記之四)

                     const   char *  szSubkey,

COM元件的類廠(COM技術内幕筆記之四)

                     const   char *  szValue)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    HKEY hKey;

COM元件的類廠(COM技術内幕筆記之四)

    char szKeyBuf[1024];

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Copy keyname into buffer.

COM元件的類廠(COM技術内幕筆記之四)

    strcpy(szKeyBuf,szKey);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Add subkey name to buffer.

COM元件的類廠(COM技術内幕筆記之四)

    if(szSubkey!=NULL)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        strcat(szKeyBuf,"//");

COM元件的類廠(COM技術内幕筆記之四)

        strcat(szKeyBuf,szSubkey);

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    // Create and open key and subkey.

COM元件的類廠(COM技術内幕筆記之四)

    long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT ,

COM元件的類廠(COM技術内幕筆記之四)

                                  szKeyBuf, 

COM元件的類廠(COM技術内幕筆記之四)

                                  0, NULL, REG_OPTION_NON_VOLATILE,

COM元件的類廠(COM技術内幕筆記之四)

                                  KEY_ALL_ACCESS, NULL, 

COM元件的類廠(COM技術内幕筆記之四)

                                  &hKey, NULL) ;

COM元件的類廠(COM技術内幕筆記之四)

    if (lResult != ERROR_SUCCESS)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        return FALSE ;

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    // Set the Value.

COM元件的類廠(COM技術内幕筆記之四)

    if (szValue != NULL)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        RegSetValueEx(hKey, NULL, 0, REG_SZ, 

COM元件的類廠(COM技術内幕筆記之四)

                      (BYTE *)szValue, 

COM元件的類廠(COM技術内幕筆記之四)

                      strlen(szValue)+1) ;

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    RegCloseKey(hKey) ;

COM元件的類廠(COM技術内幕筆記之四)

    return TRUE ;

COM元件的類廠(COM技術内幕筆記之四)

}

元件的實作:

COM元件的類廠(COM技術内幕筆記之四)

// CMPNT.cpp

COM元件的類廠(COM技術内幕筆記之四)

// 此檔案是元件CA,元件類廠CFactory的實作,CA的實作與前面講述的是一樣的,關鍵在于多引入了

COM元件的類廠(COM技術内幕筆記之四)

// 一個CFactory,還有一個是全局函數DllGetClassObject,另外,除了要導出DllGetClassObject之

COM元件的類廠(COM技術内幕筆記之四)

// 外,還要導出三個函數,分别是DllCanUnloadNow / DllRegisterServer / DllUnregisterServer.

COM元件的類廠(COM技術内幕筆記之四)

// 還有一項工作就是在DllMain中儲存子產品的資訊.

COM元件的類廠(COM技術内幕筆記之四)

#include  < iostream.h >

COM元件的類廠(COM技術内幕筆記之四)

#include  < objbase.h >

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

#include  " ../MYIF2/IFACE.h "

COM元件的類廠(COM技術内幕筆記之四)

#include  " Register.h "

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// #ifndef EXPORTAPI 

COM元件的類廠(COM技術内幕筆記之四)

// #define EXPORTAPI extern "C" __declspec(dllexport)

COM元件的類廠(COM技術内幕筆記之四)

// #endif

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

void  trace( const   char *  msg)

COM元件的類廠(COM技術内幕筆記之四)

{cout<<msg<<endl;}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// Gobal variables

COM元件的類廠(COM技術内幕筆記之四)

static  HMODULE g_hModule  =  NULL ; 

COM元件的類廠(COM技術内幕筆記之四)

static   long  g_cComponents     =      0 ;             // Count of active components

COM元件的類廠(COM技術内幕筆記之四)

static   long  g_cServerLocks     =      0 ;             // Count of locks

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// Friendly name of component

COM元件的類廠(COM技術内幕筆記之四)

const   char  g_szFriendlyName[]  =   " Inside COM.Chapter 7 Example " ;

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// Version-independent ProgID

COM元件的類廠(COM技術内幕筆記之四)

const   char  g_szVerIndProgID[]  =   " InsideCOM.Chap07 " ;

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// ProgID

COM元件的類廠(COM技術内幕筆記之四)

const   char  g_szProgID[]  =   " InsideCOM.Chap07.1 " ;

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// Component

COM元件的類廠(COM技術内幕筆記之四)

class  CA: public  IX, public  IY

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

public:

COM元件的類廠(COM技術内幕筆記之四)

    //IUnknown

COM元件的類廠(COM技術内幕筆記之四)

    virtual HRESULT __stdcall QueryInterface(const IID& iid,void** ppv);

COM元件的類廠(COM技術内幕筆記之四)

    virtual ULONG   __stdcall AddRef();

COM元件的類廠(COM技術内幕筆記之四)

    virtual ULONG   __stdcall Release();

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Interface IX

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    virtual void   __stdcall Fx()

COM元件的類廠(COM技術内幕筆記之四)

{cout<<"Fx function"<<endl;}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Interface IY

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    virtual void   __stdcall Fy()

COM元件的類廠(COM技術内幕筆記之四)

{cout<<"Fy function"<<endl;}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Constructor

COM元件的類廠(COM技術内幕筆記之四)

    CA();

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Destructor

COM元件的類廠(COM技術内幕筆記之四)

    ~CA();

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

private:

COM元件的類廠(COM技術内幕筆記之四)

    long m_cRef;

COM元件的類廠(COM技術内幕筆記之四)

} ;

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

CA::CA():m_cRef( 1 )

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    InterlockedIncrement(&g_cComponents);

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

CA:: ~ CA()

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    InterlockedDecrement(&g_cComponents);

COM元件的類廠(COM技術内幕筆記之四)

    trace("Component:/t/tDestory self");

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// IUnknown implementation

COM元件的類廠(COM技術内幕筆記之四)

HRESULT __stdcall CA::QueryInterface( const  IID &  iid, void **  ppv)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    if(iid == IID_IUnknown)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        *ppv = static_cast<IX*>(this);

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)

    else if(iid == IID_IX)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        *ppv = static_cast<IX*>(this);

COM元件的類廠(COM技術内幕筆記之四)

        trace("Component:/tReturn pointer to IX.");

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)

    else if(iid == IID_IY)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        *ppv = static_cast<IY*>(this);

COM元件的類廠(COM技術内幕筆記之四)

        trace("Component:/tReturn pointer to IY.");

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)

    else

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        *ppv = NULL;

COM元件的類廠(COM技術内幕筆記之四)

        trace("Component:/tCannot Get pointer to IX/IY");

COM元件的類廠(COM技術内幕筆記之四)

        return E_NOINTERFACE;

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)

    reinterpret_cast<IUnknown*>(*ppv)->AddRef();

COM元件的類廠(COM技術内幕筆記之四)

    return S_OK;

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

ULONG __stdcall CA::AddRef()

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    return InterlockedIncrement(&m_cRef);

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

ULONG __stdcall CA::Release()

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    if(InterlockedDecrement(&m_cRef)==0)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        delete this;

COM元件的類廠(COM技術内幕筆記之四)

        return 0;

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)

    return m_cRef;

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

///

COM元件的類廠(COM技術内幕筆記之四)

// class factory

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

///

COM元件的類廠(COM技術内幕筆記之四)

class  CFactory: public  IClassFactory

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

public:

COM元件的類廠(COM技術内幕筆記之四)

    //IUnknown

COM元件的類廠(COM技術内幕筆記之四)

    virtual HRESULT __stdcall QueryInterface(const IID& iid,void** ppv);

COM元件的類廠(COM技術内幕筆記之四)

    virtual ULONG   __stdcall AddRef();

COM元件的類廠(COM技術内幕筆記之四)

    virtual ULONG   __stdcall Release();

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Interface IClassFactory

COM元件的類廠(COM技術内幕筆記之四)

    virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,

COM元件的類廠(COM技術内幕筆記之四)

        const IID& iid,

COM元件的類廠(COM技術内幕筆記之四)

        void** ppv);

COM元件的類廠(COM技術内幕筆記之四)

    virtual HRESULT __stdcall LockServer(BOOL bLock);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Constructor

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    CFactory():m_cRef(1)

COM元件的類廠(COM技術内幕筆記之四)

{}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Destructor

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    ~CFactory() 

COM元件的類廠(COM技術内幕筆記之四)

{trace("Class factory:/t/tDestory self.");}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

private:

COM元件的類廠(COM技術内幕筆記之四)

    long m_cRef;

COM元件的類廠(COM技術内幕筆記之四)

} ;

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

HRESULT __stdcall CFactory::QueryInterface( const  IID &  iid, void **  ppv)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    if((iid == IID_IUnknown) || (iid == IID_IClassFactory))

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        *ppv= static_cast<IClassFactory*>(this);

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)

    else

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        *ppv = NULL;

COM元件的類廠(COM技術内幕筆記之四)

        return E_NOINTERFACE;

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)

    reinterpret_cast<IUnknown*>(*ppv)->AddRef();

COM元件的類廠(COM技術内幕筆記之四)

    return S_OK;

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

ULONG __stdcall CFactory::AddRef()

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    return InterlockedIncrement(&m_cRef);

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

ULONG __stdcall CFactory::Release()

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    if(InterlockedDecrement(&m_cRef)==0)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        delete this;

COM元件的類廠(COM技術内幕筆記之四)

        return 0;

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)

    else

COM元件的類廠(COM技術内幕筆記之四)

        return m_cRef;

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

HRESULT __stdcall CFactory::CreateInstance(IUnknown *  pUnknownOuter, const  IID &  iid, void **  ppv)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    trace("Class factory:/t/tCreate component.");

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    // Cannot aggregate.

COM元件的類廠(COM技術内幕筆記之四)

    if (pUnknownOuter != NULL)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        return CLASS_E_NOAGGREGATION ;

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)

    //if(pUnknownOuter!=NULL)

COM元件的類廠(COM技術内幕筆記之四)

    //    return CLASS_E_NOA

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    CA* pA = new CA;

COM元件的類廠(COM技術内幕筆記之四)

    if(pA == NULL)

COM元件的類廠(COM技術内幕筆記之四)

        return E_OUTOFMEMORY;

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Get the request interface

COM元件的類廠(COM技術内幕筆記之四)

    HRESULT hr = pA->QueryInterface(iid,ppv);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    pA->Release();

COM元件的類廠(COM技術内幕筆記之四)

    return hr;

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// LockServer

COM元件的類廠(COM技術内幕筆記之四)

HRESULT __stdcall CFactory::LockServer(BOOL bLock)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    if(bLock)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        InterlockedIncrement(&g_cServerLocks);

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)

    else

COM元件的類廠(COM技術内幕筆記之四)

        InterlockedDecrement(&g_cServerLocks);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    return S_OK;

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// Can Dll unload now?

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

int  AddNum( int  a, int  b)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    return a+b;

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

STDAPI DllCanUnloadNow()

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    if((g_cComponents ==0 ) && (g_cServerLocks==0))

COM元件的類廠(COM技術内幕筆記之四)

        return S_OK;

COM元件的類廠(COM技術内幕筆記之四)

    else

COM元件的類廠(COM技術内幕筆記之四)

        return S_FALSE;

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

STDAPI DllGetClassObject( const  CLSID &  clsid,

COM元件的類廠(COM技術内幕筆記之四)

                          const  IID &  iid,

COM元件的類廠(COM技術内幕筆記之四)

                          void **  ppv)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    trace("DllGetClassObject:/tCreate Class factory");

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    if(clsid != CLSID_Component1)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        return CLASS_E_CLASSNOTAVAILABLE;

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    CFactory* pFactory = new CFactory();

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    if(pFactory == NULL)

COM元件的類廠(COM技術内幕筆記之四)

        return E_OUTOFMEMORY;

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    //Get request interfaces

COM元件的類廠(COM技術内幕筆記之四)

    HRESULT hr = pFactory->QueryInterface(iid,ppv);

COM元件的類廠(COM技術内幕筆記之四)

    pFactory->Release();

COM元件的類廠(COM技術内幕筆記之四)

    return hr;

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// Server registration

COM元件的類廠(COM技術内幕筆記之四)

STDAPI DllRegisterServer()

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    return RegisterServer(g_hModule,CLSID_Component1,g_szFriendlyName,

COM元件的類廠(COM技術内幕筆記之四)

        g_szVerIndProgID,g_szProgID);

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

// Server unregistration

COM元件的類廠(COM技術内幕筆記之四)

STDAPI DllUnregisterServer()

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    return UnRegisterServer(CLSID_Component1,g_szVerIndProgID,g_szProgID);

COM元件的類廠(COM技術内幕筆記之四)

}

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

BOOL APIENTRY DllMain(HANDLE hModule,

COM元件的類廠(COM技術内幕筆記之四)

                      DWORD dwReason,

COM元件的類廠(COM技術内幕筆記之四)

                       void *  lpReserved)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    if (dwReason == DLL_PROCESS_ATTACH)

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        g_hModule = (HMODULE)hModule ;

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)

    return TRUE ;

COM元件的類廠(COM技術内幕筆記之四)

}

以上是元件的實作。下面是用戶端的代碼實作:

COM元件的類廠(COM技術内幕筆記之四)

// In Client.cpp

COM元件的類廠(COM技術内幕筆記之四)

int  main()

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

    HRESULT hr;

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    ::CoInitialize(NULL);

COM元件的類廠(COM技術内幕筆記之四)

    trace("Call CoCreateInstance to Create");

COM元件的類廠(COM技術内幕筆記之四)

    trace(" componet and get interface IX");

COM元件的類廠(COM技術内幕筆記之四)

    IX* pIX = NULL;

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    hr = ::CoCreateInstance(CLSID_Component1,

COM元件的類廠(COM技術内幕筆記之四)

        NULL,

COM元件的類廠(COM技術内幕筆記之四)

        CLSCTX_INPROC_SERVER,

COM元件的類廠(COM技術内幕筆記之四)

        IID_IX,

COM元件的類廠(COM技術内幕筆記之四)

        (void**)&pIX);

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    if(SUCCEEDED(hr))

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

        trace("Succeeded getting IX");

COM元件的類廠(COM技術内幕筆記之四)

        pIX->Fx();

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

        trace("Ask for Interface IY");

COM元件的類廠(COM技術内幕筆記之四)

        IY* pIY = NULL;

COM元件的類廠(COM技術内幕筆記之四)

        hr = pIX->QueryInterface(IID_IY,(void**)&pIY);

COM元件的類廠(COM技術内幕筆記之四)

        if(SUCCEEDED(hr))

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

            trace("Succeeded getting IY");

COM元件的類廠(COM技術内幕筆記之四)

            pIY->Fy();

COM元件的類廠(COM技術内幕筆記之四)

            pIY->Release();

COM元件的類廠(COM技術内幕筆記之四)

            trace("Release IY interface");

COM元件的類廠(COM技術内幕筆記之四)

        }

COM元件的類廠(COM技術内幕筆記之四)

        else

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

{

COM元件的類廠(COM技術内幕筆記之四)

            trace("Could not get interface IY.");

COM元件的類廠(COM技術内幕筆記之四)

        }

COM元件的類廠(COM技術内幕筆記之四)

        pIX->Release();

COM元件的類廠(COM技術内幕筆記之四)

    }

COM元件的類廠(COM技術内幕筆記之四)

    else

COM元件的類廠(COM技術内幕筆記之四)

        cout<<"Client: /t/tCould not create component hr="<<hex<<hr<<endl;

COM元件的類廠(COM技術内幕筆記之四)
COM元件的類廠(COM技術内幕筆記之四)

    CoUninitialize();

COM元件的類廠(COM技術内幕筆記之四)

}

再在最後詳述一篇,用戶端調用CoCreateInstance,導緻調用CoGetClassObject,CoGetClassObject通過查找系統資料庫,得知DLL位置,檔案名,然後調用DLL中DllGetClassObject,

DllGetClassObject的功能是傳回CFactory的執行個體.

傳回後,回到CoCreateInstance,通過CFactory的指針,調用

pClassFactory->CreaetInstance()建立元件執行個體.

這樣就傳回了元件執行個體的指針.

CoCreateInstace  -->  CoGetClassObject  --> DllGetClassObject --> Get CFactory*

                      <-------------------------------------------------------

                 -->  CFactory->CreateInstance(); --> Get IX* 

IX->Fx();

來源:http://www.cnblogs.com/shipfi/archive/2007/02/13/649196.html