1 流程图

image.png

注: COM库指的是 OLE32.dll

image.png

2 COM创建函数

COM库中有三个用于创建组件的函数:

  • CoGetClassObject
  • CoCreateInstance
  • CoCreateInstanceEx

    (1) CoGetClassObject

    创建一个类厂, 并获取类厂指针作为输出参数
    如果客户希望获取类厂对象或者要调用类厂的某些成员函数,则选用CoGetClassObject函数;

    1. HRESULT CoGetClassObject(
    2. const CLSID& clsid,
    3. DWORD dwClsContext,
    4. COSERVERINFO *pServerInfo,
    5. const IID& iid,
    6. (void **)ppv
    7. );

    (2) CoCreateInstance

    此函数内部调用了 CoGetClassObject 和 CreateInstance
    在其他情况下,使用CoCreateInstance函数创建对象,这是最常用的方法

    1. HRESULT CoCreateInstance(
    2. const CLSID& clsid,
    3. IUnknown *pUnknownOuter,
    4. DWORD dwClsContext,
    5. const IID& iid,
    6. (void **)ppv
    7. );

    实现伪码如下

    1. HRESULT CoCreateInstance(const CLSID& clsid, IUnknown *pUnknownOuter,
    2. DWORD dwClsContext, const IID& iid, void *ppv)
    3. {
    4. IClassFactory *pCF;
    5. HRESULT hr;
    6. hr = CoGetClassObject(clsid, dwClsContext, NULL, IID_IClassFactory, (void *)pCF);
    7. if (FAILED(hr))
    8. return hr;
    9. hr = pCF->CreateInstance(pUnkOuter, iid, (void *)ppv);
    10. pCF->Release();
    11. return hr;
    12. }

    (3) CoCreateInstanceEx

    如果客户创建远程对象或者希望一次获取对象的多个接口指针,则选用CoCreateInstanceEx函数;

    1. HRESULT CoCreateInstanceEx(
    2. const CLSID& clsid,
    3. IUnknown *pUnknownOuter,
    4. DWORD dwClsContext,
    5. COSERVERINFO *pServerInfo,
    6. DWORD dwCount,
    7. MULTI_QI *rgMultiQI
    8. );

    3 类厂的实现

    ```cpp class CDictionaryFactory : public IClassFactory { protected:

    1. ULONG m_Ref;

    public:

    1. CDictionaryFactory (void);
    2. ~ CDictionaryFactory (void);
    3. //IUnknown members
    4. HRESULT QueryInterface(const IID& iid, void **ppv);
    5. ULONG AddRef();
    6. ULONG Release();
    7. //IClassFactory members
    8. HRESULT CreateInstance(IUnknown *, const IID& iid, void **ppv);
    9. HRESULT LockServer(BOOL);

    };

HRESULT CDictionaryFactory::CreateInstance(IUnknown pUnknownOuter, const IID& iid, void **ppv) { CDictionary pObj;
HRESULT hr; *ppv=NULL; hr=E_OUTOFMEMORY; if (pUnknownOuter != NULL) return CLASS_E_NOAGGREGATION;

  1. pObj=new CDictionary();
  2. if (pObj== NULL)
  3. return hr;
  4. //Obtain the first interface pointer (which does an AddRef)
  5. hr=pObj->QueryInterface(iid, ppv);
  6. if (hr != S_OK) {
  7. g_DictionaryNumber --;
  8. delete pObj;
  9. }
  10. return hr;

}

extern “C” HRESULT __stdcall DllGetClassObject(const CLSID& clsid, const IID& iid, void *ppv) { if (clsid == CLSID_Dictionary ) { CDictionaryFactory pFactory = new CDictionaryFactory;

  1. if (pFactory == NULL) {
  2. return E_OUTOFMEMORY ;
  3. }
  4. HRESULT result = pFactory->QueryInterface(iid, ppv);
  5. return result;
  6. } else {
  7. return CLASS_E_CLASSNOTAVAILABLE;
  8. }

} ```