C++ COM组件编写初探

本文介绍如何使用COM(Component Object Model)实现一个服务端组件,并通过客户端调用组件提供的接口实现功能交互。详细解释了组件的注册、创建、接口调用过程,以及DLL的注册与反注册流程。
摘要由CSDN通过智能技术生成

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

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

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

 

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

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

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

[cpp]  view plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  1. LIBRARY "CompTest"  
  2. EXPORTS  
  3. DllCanUnloadNow  
  4. DllGetClassObject  
  5. DllUnregisterServer  
  6. DllRegisterServer  

 

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

CompTestClass.h

[cpp]  view plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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. }  


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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值