C++ COM组件的编写

来源:互联网 发布:河北驰捷网络 编辑:程序博客网 时间:2024/05/22 14:22

COM组件的编写

        本文提供一个完全用C++实现的进程内(DLL)COM服务器,不要ATL或MFC提供任何支持。用这种方式编写COM对象可以让你深入地洞察到COM处 理进程内服务器的方法以及COM是如何创建类工厂的。利用本文提供的这个简单框架你可以实现很基本的COM组件,如外壳扩展(Shell Extensions)等。如果你在使用过程中发现了任何问题,请将它反馈到vckbase@public.hk.hi.cn。
        以下是用本文所说的方式编写自己的COM对象要经过的步骤:
第一步:写一个头文件,这个头文件包含以下内容:
1、 包含文件comdef.h:

[cpp] view plaincopyprint?
  1. #include <comdef.h>  

2、 定义COM服务器的GUID。

[cpp] view plaincopyprint?
  1. _declspec(selectany) GUID CLSID_Mine = { 0xdc186800,0x657f,0x11d4,{0xb0, 0xb5, 0x0, 0x50, 0xba, 0xbf, 0xc9, 0x4}};   

3、 给出接口的IID以及这个接口要实现的方法定义。到时客户端会用到这个接口的IID和接口的方法。

[cpp] view plaincopyprint?
  1. interface __declspec(uuid("F614FB00-6702-11d4-B0B7-0050BABFC904")) ImyInterface : public IUnknown  
  2. {  
  3.     STDMETHOD(Square)(long *pVal)PURE;  
  4.     STDMETHOD(Cube)(long *pVal)PURE;  
  5. };  
客户端使用此接口:
[cpp] view plaincopyprint?
  1. HRESULT hr;  
  2. ImyInterface *pmine=(0);  
  3. hr = CoCreateInstance(CLSID_Mine, // COM 服务器的CLSID  
  4.         NULL, //不支持聚合  
  5.         CLSCTX_INPROC_SERVER, // 是个DLL  
  6.         __uuidof(ImyInterface), // 接口的IID  
  7.         (void**)&pmine);  

      还有一种方法可以从注册表中获得COM对象的CLSID,就是调用CLSIDFromProgId()函数,不过必须把组件的ProgId传递给这个函数。

第二步:必须为所定义的接口提供实现,本文用的方法是创建一个从接口继承的新类:

[cpp] view plaincopyprint?
  1. //   
  2. // 这个类实现单接口ImyInterface ...  
  3. //  
  4. class CmyInterface : public CComBase<> ,public InterfaceImpl<ImyInterface>  
  5. {  
  6. public:  
  7.     CmyInterface();  
  8.     virtual ~CmyInterface();  
  9.   
  10.     // 我们必须要为QueryInterface 编写代码  
  11.     STDMETHOD(QueryInterface)(REFIID riid,LPVOID *ppv);  
  12.   
  13.     // ImyInterface 接口方法  
  14.     STDMETHOD(Square)(long *pVal);  
  15.     STDMETHOD(Cube)(long *pVal);  
  16. };  

        模版类InterfaceImpl<>提供接口引用计数的实现。在此我们可以用多接口继承,那样就能在一个COM组件中实现多个接口。

第三步:在完成这个对象之前,我们还要编写Queryinterface和两个接口方法:

[cpp] view plaincopyprint?
  1. STDMETHODIMP CmyInterface::QueryInterface(REFIID riid,LPVOID *ppv)  
  2. {  
  3.     *ppv = NULL;  
  4.     if(IsEqualIID(riid,IID_IUnknown) IsEqualIID(riid,__uuidof(ImyInterface)))  
  5.     {  
  6.         // 因为我们从ImyInterface继承,所以要进行强制类型转换  
  7.         *ppv = (ImyInterface *) this;  
  8.   
  9.         _AddRef(); // 这个方法从某个基类继承而来  
  10.         return S_OK;  
  11.     }  
  12.     return E_NOINTERFACE;  
  13. }  
  14.   
  15. STDMETHODIMP CmyInterface::Square(long *pVal)  
  16. {  
  17.     long value = *pVal;  
  18.     *pVal = value * value;  
  19.     return S_OK;  
  20. }  
  21.   
  22. STDMETHODIMP CmyInterface::Cube(long *pVal)  
  23. {  
  24.     long value = *pVal;  
  25.     *pVal = value * value * value;  
  26.     return S_OK;  
  27. }  
    注意这里使用了__uuidof(ImyInterface)来获取接口的IID,这是因为我们已经在第一步中将这个接口关联到了某个uuid。

最后一步:

        COM组件的DLLs必须输出一个叫DllGetClassObject的函数。由这个函数为CmyInterface创建类工厂并返回一个对它的引用。然后我们调用CoCreateInstance为进程内COM创建类工厂,接着调用DllGetClassObject。

        这个类工厂有一个方法是CreateInstance,由这个方法创建对象并返回对它的引用。

[cpp] view plaincopyprint?
  1. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut)  
  2. {  
  3.     *ppvOut = NULL;  
  4.     if (IsEqualIID(rclsid, CLSID_Mine))  
  5.     {  
  6.         // 为CmyInterface类声明类工厂  
  7.         CClassFactory<CmyInterface>  
  8.         *pcf = new CClassFactory<CmyInterface>;  
  9.         return pcf->QueryInterface(riid,ppvOut);  
  10.     }  
  11.     return CLASS_E_CLASSNOTAVAILABLE;  
  12. }  
       在此我们要检查所请求的CLSID是不是CLSID_Mine,如果不是则返回一个错误代码。
       你可能会问在哪里创建实际的CmyInterface类对象,实际上这是由CClassFactory的模板实例来处理的。以下是CClassFatory的实现:
[cpp] view plaincopyprint?
  1. // CSingleCreator 用于单实例类工厂,这个类为多个CreateObject请求返回相同的对象指针..  
  2. template<class comObj>  
  3. class CSingleCreator  
  4. {  
  5. protected:  
  6.     CSingleCreator():m_pObj(0) {};  
  7.   
  8.     comObj *CreateObject()  
  9.     {  
  10.         if(!m_pObj)  
  11.         {  
  12.             m_pObj = new comObj;  
  13.         }  
  14.         return m_pObj;  
  15.     }  
  16.     comObj * m_pObj;  
  17. };  
  18.   
  19. // CMultiCreator 用于常用类工厂,这个类为每一个CreateObject请求返回新的对象指针..  
  20. template<class comObj>  
  21. class CMultiCreator  
  22. {  
  23. protected:  
  24.     CMultiCreator():m_pObj(0) {};  
  25.     comObj *CreateObject()  
  26.     {  
  27.         return new comObj;  
  28.     }  
  29.     comObj * m_pObj;  
  30. };  
  31.   
  32. //ClassFactory类实现  
  33. // MultiCreator是缺省的类工厂创建者  
  34. //这个类实现了接口IclasFactory......  
  35. class CClassFactory : public CComBase<>,  
  36.     public InterfaceImpl<IClassFactory>,  
  37.     public creatorClass  
  38. {  
  39. public:  
  40.     CClassFactory() {};  
  41.     virtual ~CClassFactory() {};  
  42.   
  43.     STDMETHOD(QueryInterface)(REFIID riid,LPVOID *ppv)  
  44.     {  
  45.         *ppv = NULL;  
  46.         if(IsEqualIID(riid,IID_IUnknown) || IsEqualIID(riid,IID_IClassFactory))  
  47.         {  
  48.             *ppv = (IClassFactory *) this;  
  49.             _AddRef();  
  50.             return S_OK;  
  51.         }  
  52.         return E_NOINTERFACE;  
  53.     }  
  54.   
  55.     STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObj)  
  56.     {  
  57.         *ppvObj = NULL;  
  58.         if (pUnkOuter)  
  59.             return CLASS_E_NOAGGREGATION;  
  60.         m_pObj = CreateObject(); // m_pObj 在creatorClass中定义  
  61.         if (!m_pObj)  
  62.             return E_OUTOFMEMORY;  
  63.         HRESULT hr = m_pObj->QueryInterface(riid, ppvObj);  
  64.         if(hr != S_OK)  
  65.         {  
  66.             delete m_pObj;  
  67.         }  
  68.         return hr;  
  69.     }  
  70.   
  71.     STDMETHODIMP LockServer(BOOL)  
  72.     {  
  73.         return S_OK;    // 未实现  
  74.     }  
  75. };  
        COM调用CreateInstance创建请求的对象,参数riid指的是所请求的接口IID,如果这个对象支持这个接口,则增加它的引用计数并返回对自身的引用。

        关于代码:本文所提出的方法是如何用纯粹的C++编写COM组件的一个大概念。很多方面的细节都省略了。从本文的文字和代码中可以看出用纯C++编写COM组件需要做些什么工作,如果你要用这种方法编写COM组件的话,这些代码只能是抛砖引玉,具体的实现可以在此基础上往下做.......。


COM组件的使用方法

Requirement:
1.创建myCom.dll,该COM只有一个组件,两个接口:

IGetRes--方法Hello(),
IGetResEx--方法HelloEx()

2.在工程中导入组件或类型库

[cpp] view plaincopyprint?
  1. #import "组件所在目录\myCom.dll" no_namespace  
       或
[cpp] view plaincopyprint?
  1. #import "类型库所在目录\myCom.tlb"  
  2. using namespace MYCOM;  

--Method 1-------------------------------------------------------
[cpp] view plaincopyprint?
  1. CoInitialize(NULL);  
  2. CLSID clsid;  
  3. CLSIDFromProgID(OLESTR("myCom.GetRes"),&clsid);  
  4. CComPtr<IGetRes> pGetRes;//智能指针  
  5. pGetRes.CoCreateInstance(clsid);  
  6. pGetRes->Hello();  
  7. pGetRes.Release();//小心哦!!请看最后的“注意”  
  8. CoUninitialize();  

--Method 2---------------------------------------------------------

[cpp] view plaincopyprint?
  1. CoInitialize(NULL);  
  2. CLSID clsid;  
  3. HRESULT hr=CLSIDFromProgID(OLESTR("myCom.GetRes"),&clsid);  
  4. IGetRes *ptr;  
  5. hr=CoCreateInstance(clsid,NULL,CLSCTX_INPROC_SERVER,  
  6.                     __uuidof(IGetRes),(LPVOID*)&ptr);  
  7. ptr->Hello();  
  8. CoUninitialize();  

--Method 3--------------------------------------------------------

[cpp] view plaincopyprint?
  1. CoInitialize(NULL);  
  2. HRESULT hr;  
  3. CLSID clsid;  
  4. hr=CLSIDFromProgID(OLESTR("myCom.GetRes"),&clsid);  
  5. IGetRes* ptr;  
  6. IGetResEx* ptrEx;  
  7.   
  8. //使用CoCreateClassObject创建一个组件(特别是mutilThreads)的多个对象的时候,效率更高.  
  9. IClassFactory* p_classfactory;  
  10. hr=CoGetClassObject(clsid,CLSCTX_INPROC_SERVER,  
  11.                     NULL,IID_IClassFactory,  
  12.                     (LPVOID*)&p_classfactory);  
  13. p_classfactory->CreateInstance(NULL,__uuidof(IGetRes),(LPVOID*)&ptr);  
  14. p_classfactory->CreateInstance(NULL,__uuidof(IGetResEx),(LPVOID*)&ptrEx);  
  15. ptr->Hello();  
  16. ptrEx->HelloEx();  
  17. CoUninitialize();  

--Method 4--------------------------------------------------------
       直接从dll中得到DllGetClassObject,接着生成类对象及类实例(这方法可以
使组件不用在注册表里注册,这是最原始的方法,但这样做没什么意义,至少失去了COM
对用户的透明性),不推荐使用.

[cpp] view plaincopyprint?
  1. typedef HRESULT (__stdcall * pfnHello)(REFCLSID,REFIID,void**);  
  2. pfnHello fnHello= NULL;  
  3. HINSTANCE hdllInst = LoadLibrary("组件所在目录\myCom.dll");  
  4. fnHello=(pfnHello)GetProcAddress(hdllInst,"DllGetClassObject");  
  5. if (fnHello != 0)  
  6. {  
  7.     IClassFactory* pcf = NULL;  
  8.     HRESULT hr=(fnHello)(CLSID_GetRes,IID_IClassFactory,(void**)&pcf);  
  9.     if (SUCCEEDED(hr) && (pcf != NULL))  
  10.     {  
  11.         IGetRes* pGetRes = NULL;  
  12.         hr = pcf->CreateInstance(NULL, IID_IFoo, (void**)&pGetRes);  
  13.         if (SUCCEEDED(hr) && (pFoo != NULL))  
  14.         {  
  15.             pGetRes->Hello();  
  16.             pGetRes->Release();  
  17.         }  
  18.         pcf->Release();  
  19.     }  
  20. }  
  21. FreeLibrary(hdllInst);  

--Method 5-------------------------------------------------------
       通过ClassWizard利用类型库生成包装类,不过前提是com组件的接口必须是派生自IDispatch,具体方法:
       调出添加类向导(.NET中),选择类型库中MFC类,打开,选择"文件",选择"myCom.dll"或"myCom.tlb",接下来会出来该myCom中的所有接口,选择你想生成的接口包装类后,向导会自动生成相应的.h文件.这样你就可以在你的MFC中像使用普通类那样使用组件了.

[cpp] view plaincopyprint?
  1. CoInitialize(NULL);  
  2. CGetRes getRest;  
  3. if (getRest.CreateDispatch("myCom.GetRes") != 0)  
  4. {  
  5.     getRest.Hello();  
  6.     getRest.ReleaseDispatch();  
  7. }  
  8. CoUninitialize();  

--注意--------------------------------------------------------------
       COM中的智能指针实际上是重载了->的类,目的是为了简化引用记数,几不需要程序员显示的调用AddRef()和Release(),但是为什么我们在Method 1中pGetRes.Release(),问题在与,我们的智能指针pGetRes生命周期的结束是在CoUninitialize()之后,CoInitialize所开的套间在CoUninitialize()后已经被关闭,而pGetRes此时发生析构,导致了程序的崩溃,解决这个问题的另一个方法是
[cpp] view plaincopyprint?
  1. CoInitialize(NULL);  
  2. CLSID clsid;  
  3. CLSIDFromProgID(OLESTR("myCom.GetRes"),&clsid);  
  4. {  
  5.     CComPtr<IGetRes> pGetRes;//智能指针  
  6.     pGetRes.CoCreateInstance(clsid);  
  7.     pGetRes->Hello();  
  8. }  
  9. CoUninitialize();  
--------------------------------------------------------------------

        以上就是COM的5种方法,当然具体怎么使用还是在于程序的环境,加以琢磨....

http://www.yesky.com/dev/382/2019882.shtml


========================================================文二===================================================

本文提供一个完全用C++实现的进程内(DLL)COM服务器,不要ATL或MFC提供任何支持。用这种方式编写COM对象可以让你深入地洞察到COM处理进程内服务器的方法以及COM是如何创建类工厂的。利用本文提供的这个简单框架你可以实现很基本的COM组件,如外壳扩展(Shell Extensions)等。

以下是用本文所说的方式编写自己的COM对象要经过的步骤:

第一步:写一个头文件,这个头文件包含以下内容:

1、 包含文件comdef.h:#include <comdef.h>。

2、 定义COM服务器的GUID。

  1. _declspec(selectany) GUID CLSID_Mine = { 0xdc186800,  
  2. 0x657f,  
  3. 0x11d4,   
  4. {0xb0, 0xb5, 0x0, 0x50, 0xba, 0xbf, 0xc9, 0x4}  
  5. }; 

3、 给出接口的IID以及这个接口要实现的方法定义。到时客户端会用到这个接口的IID和接口的方法。

  1. interface __declspec(uuid("F614FB00-6702-11d4-B0B7-0050BABFC904")) ImyInterface : public IUnknown  
  2. {  
  3. STDMETHOD(Square)(long *pVal)PURE;  
  4. STDMETHOD(Cube)(long *pVal)PURE;  
  5. }; 

客户端使用此接口:

  1. HRESULT hr;  
  2. ImyInterface *pmine=(0);  
  3. hr = CoCreateInstance(CLSID_Mine, // COM 服务器的CLSID   
  4. NULL, //不支持聚合  
  5. CLSCTX_INPROC_SERVER, // 是个DLL   
  6. __uuidof(ImyInterface), // 接口的IID  
  7. (void**)&pmine   
  8. ); 

还有一种方法可以从注册表中获得COM对象的CLSID,就是调用CLSIDFromProgId()函数,不过必须把组件的ProgId传递给这个函数。

第二步:必须为所定义的接口提供实现,本文用的方法是创建一个从接口继承的新类:

  1. // 这个类实现单接口ImyInterface ...  
  2. //   
  3. //   
  4. class CmyInterface : public CComBase<> ,   
  5. public InterfaceImpl<ImyInterface>   
  6. {  
  7. public:  
  8. CmyInterface();  
  9. virtual ~CmyInterface();  
  10. // 我们必须要为QueryInterface 编写代码  
  11. STDMETHOD(QueryInterface)(REFIID riid,LPVOID *ppv);  
  12. // ImyInterface 接口方法  
  13. STDMETHOD(Square)(long *pVal);  
  14. STDMETHOD(Cube)(long *pVal);  
  15. }; 

模版类InterfaceImpl<>提供接口引用计数的实现。在此我们可以用多接口继承,那样就能在一个COM组件中实现多个接口。

第三步:在完成这个对象之前,我们还要编写Queryinterface和两个接口方法:

  1. STDMETHODIMP CmyInterface::QueryInterface(REFIID riid,LPVOID *ppv)  
  2. {  
  3. *ppv = NULL;  
  4. if(IsEqualIID(riid,IID_IUnknown) || IsEqualIID(riid,__uuidof(ImyInterface)))  
  5. {  
  6. // 因为我们从ImyInterface继承,所以要进行强制类型转换  
  7. *ppv = (ImyInterface *) this;  
  8.  
  9. _AddRef(); // 这个方法从某个基类继承而来  
  10. return S_OK;  
  11. }  
  12. return E_NOINTERFACE;  
  13. }  
  14.  
  15. STDMETHODIMP CmyInterface::Square(long *pVal)  
  16. {  
  17. long value = *pVal;  
  18. *pVal = value * value;  
  19. return S_OK;  
  20. }  
  21.  
  22. STDMETHODIMP CmyInterface::Cube(long *pVal)  
  23. {  
  24. long value = *pVal;  
  25. *pVal = value * value * value;  
  26. return S_OK;  

注意这里使用了__uuidof(ImyInterface)来获取接口的IID,这是因为我们已经在第一步中将这个接口关联到了某个uuid。

最后一步:COM 组件的DLLs必须输出一个叫DllGetClassObject的函数。由这个函数为CmyInterface创建类工厂并返回一个对它的引用。然后我们调用CoCreateInstance为进程内COM创建类工厂,接着调用DllGetClassObject。这个类工厂有一个方法是CreateInstance,由这个方法创建对象并返回对它的引用。

  1. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut)  
  2. {  
  3. *ppvOut = NULL;  
  4. if (IsEqualIID(rclsid, CLSID_Mine))  
  5. {  
  6. // 为CmyInterface类声明类工厂  
  7. CClassFactory<CmyInterface>   
  8. *pcf = new CClassFactory<CmyInterface>;   
  9. return pcf->QueryInterface(riid,ppvOut);  
  10. }  
  11. return CLASS_E_CLASSNOTAVAILABLE;  

在此我们要检查所请求的CLSID是不是CLSID_Mine,如果不是则返回一个错误代码。

你可能会问在哪里创建实际的CmyInterface类对象,实际上这是由CClassFactory<CmyInterface>的模板实例来处理的。以下是CClassFatory的实现:

  1. // CSingleCreator 用于单实例类工厂,这个类为多个CreateObject请求返回相同的对象指针..   
  2. template<class comObj>  
  3. class CSingleCreator  
  4. {  
  5. protected:  
  6. CSingleCreator():m_pObj(0) {};  
  7. comObj *CreateObject()  
  8. {  
  9. if(!m_pObj)  
  10. {  
  11. m_pObj = new comObj;  
  12. }  
  13. return m_pObj;  
  14. }  
  15. comObj * m_pObj;  
  16. };  
  17. // CMultiCreator 用于常用类工厂,这个类为每一个CreateObject请求返回新的对象指针..  
  18. template<class comObj>  
  19. class CMultiCreator  
  20. {  
  21. protected:  
  22. CMultiCreator():m_pObj(0) {};  
  23. comObj *CreateObject()  
  24. {  
  25. return new comObj;  
  26. }  
  27. comObj * m_pObj;  
  28. };  
  29. //ClassFactory类实现  
  30. // MultiCreator是缺省的类工厂创建者  
  31. //这个类实现了接口IclasFactory......  
  32.  
  33. class CClassFactory : public CComBase<>,  
  34. public InterfaceImpl<IClassFactory>,  
  35. public creatorClass   
  36. {  
  37. public:  
  38. CClassFactory() {};  
  39. virtual ~CClassFactory() {};  
  40.  
  41. STDMETHOD(QueryInterface)(REFIID riid,LPVOID *ppv)  
  42. {  
  43. *ppv = NULL;  
  44. if(IsEqualIID(riid,IID_IUnknown) || IsEqualIID(riid,IID_IClassFactory))  
  45. {  
  46. *ppv = (IClassFactory *) this;  
  47. _AddRef();   
  48. return S_OK;  
  49. }  
  50. return E_NOINTERFACE;  
  51. }  
  52.  
  53. STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObj)  
  54. {  
  55. *ppvObj = NULL;  
  56. if (pUnkOuter)  
  57. return CLASS_E_NOAGGREGATION;  
  58. m_pObj = CreateObject(); // m_pObj 在creatorClass中定义  
  59. if (!m_pObj)  
  60. return E_OUTOFMEMORY;  
  61. HRESULT hr = m_pObj->QueryInterface(riid, ppvObj);  
  62. if(hr != S_OK)  
  63. {  
  64. delete m_pObj;  
  65. }  
  66. return hr;  
  67. }  
  68. STDMETHODIMP LockServer(BOOL) { return S_OK; } // 未实现  
  69. }; 

COM调用CreateInstance创建请求的对象,参数riid指的是所请求的接口IID,如果这个对象支持这个接口,则增加它的引用计数并返回对自身的引用。

关于代码:本文所提出的方法是如何用纯粹的C++编写COM组件的一个大概念。很多方面的细节都省略了。从本文的文字和代码中可以看出用纯C++编写COM组件需要做些什么工作,如果你要用这种方法编写COM组件的话,这些代码只能是抛砖引玉,具体的实现可以在此基础上往下做.

==================================================文三===========================================================================

最近在学习COM,自己实现了一个小Demo,拿出来和大家分享一下。求各种批评。

我实现的这个组件向外提供了一个接口ICompTest,里面只有一个函数helloworld(),功能为返回一个整数89。

实现了自注册功能。下面贴出代码,希望对刚开始学习COM的朋友有所帮助。

 

首先看一下工程结构,编译环境为vs 2008

CompTest工程是服务端工程,是一个dll,CtrlTest是客户端工程,是一个控制台工程。

下面通过客户端的运行逻辑来讲述整个运行流程,先看一下CtrlTest.cpp文件

[cpp] view plaincopy
  1. /** 
  2. *  @file CtrlTest.cpp 
  3. *  @author LiWang112358 
  4. *  @date 2012/3/17 
  5. *  @version 1.0 
  6. *  @brief COM客户端代码 
  7. */  
  8. #include <iostream>  
  9. #include "ICompTest.h"  
  10.   
  11. using namespace std;  
  12.   
  13. int main()  
  14. {  
  15.     CoInitialize(NULL);     //初始化COM库,使用默认的内存分配器  
  16.     IUnknown* pUnknown = NULL;    
  17.     GUID CLSID_CompTestClass;  
  18.     HRESULT hResult = CLSIDFromProgID(L"COMCTL.CompTest", &CLSID_CompTestClass);    //获取ProgID为COMCTL.CompTest组建的CLSID  
  19.     if (S_OK != hResult){  
  20.         printf("Can't find CLSID!\n");  
  21.         return -1;  
  22.     }  
  23.     else{  
  24.         LPOLESTR szCLSID;     
  25.         StringFromCLSID(CLSID_CompTestClass, &szCLSID);     //将其转化为字符串形式用来输出  
  26.         wprintf(L"find CLSID \"%s\"\n",szCLSID);      
  27.         CoTaskMemFree(szCLSID);     //调用COM库的内存释放  
  28.     }  
  29.   
  30.     //用此CLSID创建一个COM对象并获取IUnknown接口  
  31.     hResult = CoCreateInstance(CLSID_CompTestClass, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown,(void **)&pUnknown);  
  32.       
  33.     if (S_OK != hResult || NULL == pUnknown){  
  34.         printf("Create Object Failed!\n");  
  35.         return -1;  
  36.     }  
  37.   
  38.     ICompTest* pCompTest = NULL;  
  39.     hResult = pUnknown->QueryInterface(IID_ICompTest, (void**)&pCompTest);//通过此结构查询我们自己的ICompTest接口  
  40.   
  41.     cout << pCompTest->HelloWorld() << endl;//调用我们自己接口中的函数  
  42.     pCompTest->Release();    //释放自己的接口  
  43.     pUnknown->Release(); //释放IUnknown接口  
  44.     CoUninitialize();       //COM库反初始化  
  45.     return 0;  
  46. }  

这是客户程序的主逻辑,主要就是通过COM库创建CompTestClass对象,这个对象在这里是不可见的,这里只能拿到ICompTest接口,通过该接口调用函数HelloWorld。

下面看一下接口的声明ICompTest.h文件,这个文件是客户端和服务端都要有的。

[cpp] view plaincopy
  1. /** 
  2. *  @file ICompTest.h 
  3. *  @author LiWang112358 
  4. *  @date 2012/3/17 
  5. *  @version 1.0 
  6. *  @brief ICompTest接口的声明这个文件是服务端和客户端共有的 
  7. */  
  8. #ifndef ICOMPTEST_H  
  9. #define ICOMPTEST_H  
  10.   
  11. #include <unknwn.h>  
  12.   
  13. // {81A80687-6CC4-4996-8DD2-F058907FDCA8}  
  14. static const GUID IID_ICompTest =   
  15. { 0x81a80687, 0x6cc4, 0x4996, { 0x8d, 0xd2, 0xf0, 0x58, 0x90, 0x7f, 0xdc, 0xa8 } };  
  16.   
  17.   
  18. class ICompTest :  
  19.     public IUnknown  
  20. {  
  21. public:  
  22.     virtual int _stdcall HelloWorld() = 0;  
  23. };  
  24. #endif  

这个文件中有一个GUID IID_ICompTest ,用于查询接口ICompTest 。

我们可以在 CtrlTest.cpp文件中看到CLSIDFromProgID和CoCreateInstance这两个函数,

第一个函数是要通过一个名字"COMCTL.CompTest"拿到一个CLSID,这个过程需要CLSID信息。

第二个函数是要通过这个CLSID找到我们的组件(dll),并加载这个dll,然后创建COM对象,这个过程需要dll的路径信息。

这些信息都被放在注册表中,是这个组件自注册的时候由DllRegisterServer函数写入的。

我们可以先看一下注册之后注册表中的内容

其中COMCTL.CompTest是在键HKEY_CLASSES_ROOT下,{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}是在键HKEY_CLASSES_ROOT\CLSID下。

下面我们看一下这个dll的注册过程。

用“regsvr32.exe dll路径”对dll进行注册,实际上regsvr32只是调用了dll中的DllRegisterServer引出函数。

下面我们看一下DllRegisterServer函数的实现,这个函数在CompTest.cpp中。

[cpp] view plaincopy
  1. int myReg(LPCWSTR lpPath)   //将本组件的信息写入注册表,包括CLSID、所在路径lpPath、ProgID  
  2. {  
  3.     HKEY thk, tclsidk;  
  4.   
  5.     //打开键HKEY_CLASSES_ROOT\CLSID,创建新键为CompTestClass的CLSID,  
  6.     //在该键下创建键InprocServer32,并将本组件(dll)所在路径lpPath写为该键的默认值  
  7.     if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, L"CLSID", &thk)){  
  8.         if (ERROR_SUCCESS == RegCreateKey(thk, L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}", &tclsidk)){  
  9.             HKEY tinps32k, tprogidk;  
  10.             if (ERROR_SUCCESS == RegCreateKey(tclsidk, L"InprocServer32", &tinps32k)){  
  11.                 if (ERROR_SUCCESS == RegSetValue(tinps32k, NULL, REG_SZ, lpPath, wcslen(lpPath) * 2)){  
  12.                 }  
  13.                 RegCloseKey(tinps32k);  
  14.             }  
  15.             RegCloseKey(tclsidk);  
  16.         }  
  17.         RegCloseKey(thk);  
  18.     }  
  19.     //在键HKEY_CLASSES_ROOT下创建新键为COMCTL.CompTest,  
  20.     //在该键下创建子键,并将CompTestClass的CLSID写为该键的默认值  
  21.     if (ERROR_SUCCESS == RegCreateKey(HKEY_CLASSES_ROOT, L"COMCTL.CompTest", &thk)){  
  22.         if (ERROR_SUCCESS == RegCreateKey(thk, L"CLSID", &tclsidk)){  
  23.             if (ERROR_SUCCESS == RegSetValue(tclsidk,   
  24.                 NULL,   
  25.                 REG_SZ,   
  26.                 L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}",  
  27.                 wcslen(L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}") * 2)){  
  28.             }  
  29.         }  
  30.     }  
  31.     //这样的话一个客户端程序如果想要使用本组件,首先可以以COMCTL.CompTest为参数调用CLSIDFromProgID函数  
  32.     //来获取CompTestClass的CLSID,再以这个CLSID为参数调用CoCreateInstance创建COM对象  
  33.     return 0;  
  34. }  
  35.   
  36. extern "C" HRESULT _stdcall DllRegisterServer()  
  37. {  
  38.     WCHAR szModule[1024];  
  39.     DWORD dwResult = GetModuleFileName(g_hModule, szModule, 1024); //获取本组件(dll)所在路径  
  40.     if (0 == dwResult){  
  41.         return -1;  
  42.     }  
  43.     MessageBox(NULL, szModule, L"", MB_OK);  
  44.     myReg(szModule);//将路径等信息写入注册表  
  45.     return 0;  
  46. }  


 

用“regsvr32.exe dll路径 -u”对dll进行反注册,同样,实际上regsvr32只是调用了dll中的DllUnregisterServer引出函数。

下面我们来看一下DllUnregisterServer函数的实现,这个函数在CompTest.cpp中。

 

[cpp] view plaincopy
  1. int myDelKey(HKEY hk, LPCWSTR lp)  
  2. {  
  3.     if (ERROR_SUCCESS == RegDeleteKey(hk, lp)){  
  4.     }  
  5.     return 0;  
  6. }  
  7.   
  8. int myDel() //删除注册时写入注册表的信息  
  9. {  
  10.     HKEY thk;  
  11.     if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, L"CLSID", &thk)){  
  12.         myDelKey(thk, L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}\\InprocServer32");  
  13.         myDelKey(thk, L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}");  
  14.           
  15.         RegCloseKey(thk);  
  16.     }  
  17.     if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, L"COMCTL.CompTest", &thk)){  
  18.         myDelKey(thk, L"CLSID");  
  19.     }  
  20.     myDelKey(HKEY_CLASSES_ROOT, L"COMCTL.CompTest");  
  21.     return 0;  
  22. }  
  23.   
  24. extern "C" HRESULT _stdcall DllUnregisterServer()  
  25. {  
  26.     myDel();//删除注册时写入注册表的信息  
  27.   
  28.     return 0;  
  29. }  

我们继续分析客户端的代码CoCreateInstance(CLSID_CompTestClass, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown,(void **)&pUnknown);

这个函数是要调用CoGetClassObject函数,来获取CompTestClass的类厂,以此创建CompTestClass对象并获取IUnknown接口。其中,CoGetClassObject函数

实际上是调用了CompTest.cpp中的又一个引出函数DllGetClassObject来获取IClassFactory接口的。最终CoCreateInstance会调用IClassFactory接口的CreateInstance

函数去创建COM对象。

下面我们看一下DllGetClassObject函数的实现

[cpp] view plaincopy
  1. extern "C" HRESULT _stdcall DllGetClassObject(__in REFCLSID rclsid, __in REFIID riid, LPVOID FAR* ppv)//用于创建类厂并返回所需接口,由CoGetClassObject函数调用  
  2. {  
  3.     if (CLSID_CompTestClass == rclsid){  
  4.         CompTestFactory* pFactory = new CompTestFactory();//创建类厂对象  
  5.         if (NULL == pFactory){  
  6.             return E_OUTOFMEMORY;  
  7.         }  
  8.         HRESULT result = pFactory->QueryInterface(riid, ppv);//获取所需接口  
  9.         return result;  
  10.     }  
  11.     else{  
  12.         return CLASS_E_CLASSNOTAVAILABLE;  
  13.     }  
  14. }  

接下来我们看一下组件中的最后一个引出函数DllCanUnloadNow,这样dll中的所有引出函数就都出现了

[cpp] view plaincopy
  1. extern "C" HRESULT _stdcall DllCanUnloadNow()//用于判断是否可以卸载本组建, 由CoFreeUnusedLibraries函数调用  
  2. {  
  3.     if (0 == g_num){//如果对象个数为0,则可以卸载  
  4.         return S_OK;  
  5.     }  
  6.     else{  
  7.         return S_FALSE;  
  8.     }  
  9. }  
其中ULONG g_num表示组件中CompTestClass对象的个数,用于判断是否可以卸载本组建,如值为0则可以卸载

下面我们看一下CompTest.cpp的全貌

[cpp] view plaincopy
  1. /** 
  2. *  @file CompTest.cpp 
  3. *  @author LiWang112358 
  4. *  @date 2012/3/17 
  5. *  @version 1.0 
  6. *  @brief 四个重要的引出函数的实现, 
  7. *  @      分别是DllRegisterServer,用于注册本dll,由regsvr32.exe调用 
  8. *  @            DllUnregisterServer, 用于反注册本dll,由regsvr32.exe -u 调用   
  9. *  @            DllCanUnloadNow,用于判断是否可以卸载本组建, 由CoFreeUnusedLibraries函数调用 
  10. *  @            DllGetClassObject,用于创建类厂并返回所需接口,由CoGetClassObject函数调用 
  11. */  
  12. #include <iostream>  
  13. #include <windows.h>  
  14.   
  15. #include "factory.h"  
  16. #include "CompTestClass.h"  
  17.   
  18. using namespace std;  
  19.   
  20. HMODULE g_hModule;  //dll进程实例句柄  
  21. ULONG g_num;        //组件中CompTestClass对象的个数,用于判断是否可以卸载本组建,如值为0则可以卸载  
  22.   
  23. int myReg(LPCWSTR lpPath)   //将本组件的信息写入注册表,包括CLSID、所在路径lpPath、ProgID  
  24. {  
  25.     HKEY thk, tclsidk;  
  26.   
  27.     //打开键HKEY_CLASSES_ROOT\CLSID,创建新键为CompTestClass的CLSID,  
  28.     //在该键下创建键InprocServer32,并将本组件(dll)所在路径lpPath写为该键的默认值  
  29.     if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, L"CLSID", &thk)){  
  30.         if (ERROR_SUCCESS == RegCreateKey(thk, L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}", &tclsidk)){  
  31.             HKEY tinps32k, tprogidk;  
  32.             if (ERROR_SUCCESS == RegCreateKey(tclsidk, L"InprocServer32", &tinps32k)){  
  33.                 if (ERROR_SUCCESS == RegSetValue(tinps32k, NULL, REG_SZ, lpPath, wcslen(lpPath) * 2)){  
  34.                 }  
  35.                 RegCloseKey(tinps32k);  
  36.             }  
  37.             RegCloseKey(tclsidk);  
  38.         }  
  39.         RegCloseKey(thk);  
  40.     }  
  41.     //在键HKEY_CLASSES_ROOT下创建新键为COMCTL.CompTest,  
  42.     //在该键下创建子键,并将CompTestClass的CLSID写为该键的默认值  
  43.     if (ERROR_SUCCESS == RegCreateKey(HKEY_CLASSES_ROOT, L"COMCTL.CompTest", &thk)){  
  44.         if (ERROR_SUCCESS == RegCreateKey(thk, L"CLSID", &tclsidk)){  
  45.             if (ERROR_SUCCESS == RegSetValue(tclsidk,   
  46.                 NULL,   
  47.                 REG_SZ,   
  48.                 L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}",  
  49.                 wcslen(L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}") * 2)){  
  50.             }  
  51.         }  
  52.     }  
  53.     //这样的话一个客户端程序如果想要使用本组件,首先可以以COMCTL.CompTest为参数调用CLSIDFromProgID函数  
  54.     //来获取CompTestClass的CLSID,再以这个CLSID为参数调用CoCreateInstance创建COM对象  
  55.     return 0;  
  56. }  
  57.   
  58. extern "C" HRESULT _stdcall DllRegisterServer()  
  59. {  
  60.     WCHAR szModule[1024];  
  61.     DWORD dwResult = GetModuleFileName(g_hModule, szModule, 1024); //获取本组件(dll)所在路径  
  62.     if (0 == dwResult){  
  63.         return -1;  
  64.     }  
  65.     MessageBox(NULL, szModule, L"", MB_OK);  
  66.     myReg(szModule);//将路径等信息写入注册表  
  67.     return 0;  
  68. }  
  69.   
  70. int myDelKey(HKEY hk, LPCWSTR lp)  
  71. {  
  72.     if (ERROR_SUCCESS == RegDeleteKey(hk, lp)){  
  73.     }  
  74.     return 0;  
  75. }  
  76.   
  77. int myDel() //删除注册时写入注册表的信息  
  78. {  
  79.     HKEY thk;  
  80.     if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, L"CLSID", &thk)){  
  81.         myDelKey(thk, L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}\\InprocServer32");  
  82.         myDelKey(thk, L"{9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}");  
  83.           
  84.         RegCloseKey(thk);  
  85.     }  
  86.     if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, L"COMCTL.CompTest", &thk)){  
  87.         myDelKey(thk, L"CLSID");  
  88.     }  
  89.     myDelKey(HKEY_CLASSES_ROOT, L"COMCTL.CompTest");  
  90.     return 0;  
  91. }  
  92.   
  93. extern "C" HRESULT _stdcall DllUnregisterServer()  
  94. {  
  95.     myDel();//删除注册时写入注册表的信息  
  96.   
  97.     return 0;  
  98. }  
  99.   
  100. extern "C" HRESULT _stdcall DllCanUnloadNow()//用于判断是否可以卸载本组建, 由CoFreeUnusedLibraries函数调用  
  101. {  
  102.     if (0 == g_num){//如果对象个数为0,则可以卸载  
  103.         return S_OK;  
  104.     }  
  105.     else{  
  106.         return S_FALSE;  
  107.     }  
  108. }  
  109.   
  110. extern "C" HRESULT _stdcall DllGetClassObject(__in REFCLSID rclsid, __in REFIID riid, LPVOID FAR* ppv)//用于创建类厂并返回所需接口,由CoGetClassObject函数调用  
  111. {  
  112.     if (CLSID_CompTestClass == rclsid){  
  113.         CompTestFactory* pFactory = new CompTestFactory();//创建类厂对象  
  114.         if (NULL == pFactory){  
  115.             return E_OUTOFMEMORY;  
  116.         }  
  117.         HRESULT result = pFactory->QueryInterface(riid, ppv);//获取所需接口  
  118.         return result;  
  119.     }  
  120.     else{  
  121.         return CLASS_E_CLASSNOTAVAILABLE;  
  122.     }  
  123. }  
  124.   
  125.   
  126. BOOL APIENTRY DllMain( HMODULE hModule,  
  127.                        DWORD  ul_reason_for_call,  
  128.                        LPVOID lpReserved  
  129.                      )  
  130. {  
  131.     g_hModule = hModule;//获取进程实例句柄,用于获取本组件(dll)路径  
  132.     switch (ul_reason_for_call)  
  133.     {  
  134.     case DLL_PROCESS_ATTACH:  
  135.     case DLL_THREAD_ATTACH:  
  136.     case DLL_THREAD_DETACH:  
  137.     case DLL_PROCESS_DETACH:  
  138.         break;  
  139.     }  
  140.     return TRUE;  
  141. }  


 

下面是.def文件mydef.def用于声明dll的引出函数

[cpp] view plaincopy
  1. LIBRARY "CompTest"  
  2. EXPORTS  
  3. DllCanUnloadNow  
  4. DllGetClassObject  
  5. DllUnregisterServer  
  6. DllRegisterServer  

 

下面是剩下的文件,有些许注释,语焉不详之处,望海涵。

CompTestClass.h

[cpp] view plaincopy
  1. /** 
  2. *  @file CompTestClass.h 
  3. *  @author LiWang112358 
  4. *  @date 2012/3/17 
  5. *  @version 1.0 
  6. *  @brief CompTestClass对象的声明,这个类要实现ICompTest接口 
  7. */  
  8. #ifndef COMPTESTCLASS_H  
  9. #define COMPTESTCLASS_H  
  10.   
  11.   
  12. #include "ICompTest.h"  
  13.   
  14. // {9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}  
  15. static const GUID CLSID_CompTestClass =   
  16. { 0x9ca9dbe8, 0xc0b1, 0x42c9, { 0xb6, 0xc7, 0x85, 0x6b, 0xe5, 0x75, 0x68, 0x55 } };  
  17.   
  18. class CompTestClass :  
  19.     public ICompTest  
  20. {  
  21. public:  
  22.       
  23.     CompTestClass();  
  24.     ~CompTestClass();  
  25.   
  26.     //要实现IUnknown接口  
  27.     virtual HRESULT _stdcall QueryInterface(const IID& riid, void** ppvObject);  
  28.     virtual ULONG _stdcall AddRef();  
  29.     virtual ULONG _stdcall Release();  
  30.   
  31.     //要实现ICompTest接口  
  32.     virtual int _stdcall HelloWorld();  
  33. protected:  
  34.   
  35.     ULONG m_Ref;  
  36. };  
  37. #endif  


CompTestClass.cpp

[cpp] view plaincopy
  1. /** 
  2. *  @file CompTestClass.cpp 
  3. *  @author LiWang112358 
  4. *  @date 2012/3/17 
  5. *  @version 1.0 
  6. *  @brief CompTestClass类的实现 
  7. */  
  8. #include "CompTestClass.h"  
  9.   
  10. ULONG CompTestClass::m_objNum = 0;//组件中CompTestClass对象的个数,用于判断是否可以卸载本组建,如值为0则可以卸载  
  11. CRITICAL_SECTION CompTestClass::m_cs;//为了多线程调用对m_objNum加的锁  
  12.   
  13. CompTestClass::CompTestClass()  
  14. {  
  15.     m_Ref = 0;  
  16.     autoLock tlock(m_cs);  
  17.     m_objNum ++;    //构造了一个对象  
  18. }  
  19.   
  20. CompTestClass::~CompTestClass()  
  21. {  
  22.     autoLock tlock(m_cs);  
  23.     m_objNum --;    //释放了一个对象  
  24. }  
  25.   
  26. HRESULT _stdcall CompTestClass::QueryInterface(const IID &riid, void **ppvObject)  
  27. {  
  28.     if (IID_IUnknown == riid){  
  29.         *ppvObject = (IUnknown*)this;  
  30.         ((IUnknown*)(*ppvObject))->AddRef();  
  31.     }  
  32.     else if (IID_ICompTest == riid){  
  33.         *ppvObject = (ICompTest*)this;  
  34.         ((ICompTest*)(*ppvObject))->AddRef();  
  35.     }  
  36.     else{  
  37.         *ppvObject = NULL;  
  38.         return E_NOINTERFACE;  
  39.     }  
  40.     return S_OK;  
  41. }  
  42.   
  43. ULONG _stdcall CompTestClass::AddRef()  
  44. {  
  45.     m_Ref ++;  
  46.     return m_Ref;  
  47. }  
  48.   
  49. ULONG _stdcall CompTestClass::Release()  
  50. {  
  51.     m_Ref --;  
  52.     if (0 == m_Ref){  
  53.         delete this;  
  54.         return 0;  
  55.     }  
  56.     return m_Ref;  
  57. }  
  58.   
  59. int _stdcall CompTestClass::HelloWorld()//ICompTest接口的实现,返回一个整数89  
  60. {  
  61.     return 89;  
  62. }  
  63.   
  64. int CompTestClass::Init()  
  65. {  
  66.     m_objNum = 0;  
  67.     InitializeCriticalSection(&m_cs);  
  68.     return 0;  
  69. }  
  70.   
  71. ULONG CompTestClass::ObjNum()  
  72. {  
  73.     return m_objNum;  
  74. }  

 

factory.h

[cpp] view plaincopy
  1. /** 
  2. *  @file factory.h 
  3. *  @author LiWang112358 
  4. *  @date 2012/3/17 
  5. *  @version 1.0 
  6. *  @brief CompTestClass对象的类厂的声明 
  7. */  
  8. #ifndef FACTORY_H  
  9. #define FACTORY_H  
  10.   
  11. #include <unknwn.h>  
  12.   
  13.   
  14. class CompTestFactory :  
  15.     public IClassFactory  
  16. {  
  17. public:  
  18.     CompTestFactory();  
  19.     ~CompTestFactory();  
  20.   
  21.     //要实现IUnknown接口  
  22.     virtual HRESULT _stdcall QueryInterface(const IID& riid, void** ppvObject);  
  23.     virtual ULONG _stdcall AddRef();  
  24.     virtual ULONG _stdcall Release();  
  25.   
  26.     //要实现IClassFactory接口  
  27.     virtual HRESULT _stdcall CreateInstance(IUnknown *pUnkOuter, const IID& riid, void **ppvObject);  
  28.     virtual HRESULT _stdcall LockServer(BOOL fLock);  
  29.   
  30. protected:  
  31.     ULONG m_Ref;  
  32. };  
  33.   
  34. #endif  

 

factory.cpp

[cpp] view plaincopy
  1. /** 
  2. *  @file factory.cpp 
  3. *  @author LiWang112358 
  4. *  @date 2012/3/17 
  5. *  @version 1.0 
  6. *  @brief CompTestClass对象的类厂的实现 
  7. */  
  8.   
  9. #include "factory.h"  
  10. #include "CompTestClass.h"  
  11.   
  12. CompTestFactory::CompTestFactory()  
  13. {  
  14.     m_Ref = 0;  
  15. }  
  16.   
  17. CompTestFactory::~CompTestFactory()  
  18. {  
  19.   
  20. }  
  21.   
  22. HRESULT _stdcall CompTestFactory::QueryInterface(const IID &riid, void **ppvObject)  
  23. {  
  24.     if (IID_IUnknown == riid){  
  25.         *ppvObject = (IUnknown*)this;  
  26.         ((IUnknown*)(*ppvObject))->AddRef();  
  27.     }  
  28.     else if (IID_IClassFactory == riid){  
  29.         *ppvObject = (IClassFactory*)this;  
  30.         ((IClassFactory*)(*ppvObject))->AddRef();  
  31.     }  
  32.     else{  
  33.         *ppvObject = NULL;  
  34.         return E_NOINTERFACE;  
  35.     }  
  36.     return S_OK;  
  37. }  
  38.   
  39. ULONG _stdcall CompTestFactory::AddRef()  
  40. {  
  41.     m_Ref ++;  
  42.     return m_Ref;  
  43. }  
  44.   
  45. ULONG _stdcall CompTestFactory::Release()  
  46. {  
  47.     m_Ref --;  
  48.     if (0 == m_Ref){  
  49.         delete this;  
  50.         return 0;  
  51.     }  
  52.     return m_Ref;  
  53. }  
  54.   
  55. HRESULT _stdcall CompTestFactory::CreateInstance(IUnknown *pUnkOuter, const IID &riid, void **ppvObject)//最重要的函数,这个函数创建CompTestClass对象,并返回所需接口  
  56. {  
  57.     if (NULL != pUnkOuter){  
  58.         return CLASS_E_NOAGGREGATION;  
  59.     }  
  60.     HRESULT hr = E_OUTOFMEMORY;  
  61.     CompTestClass::Init();  
  62.     CompTestClass* pObj = new CompTestClass();   
  63.     if (NULL == pObj){  
  64.         return hr;  
  65.     }  
  66.   
  67.     hr = pObj->QueryInterface(riid, ppvObject);  
  68.     if (S_OK != hr){  
  69.         delete pObj;  
  70.     }  
  71.     return hr;  
  72. }  
  73.   
  74. HRESULT _stdcall CompTestFactory::LockServer(BOOL fLock)  
  75. {  
  76.     return NOERROR;  
  77. }  


以下是客户程序的运行结果


1 0
原创粉丝点击