Com学习

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

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

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

 

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

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

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

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

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

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

  1. #ifndef ICOMPTEST_H  
  2. #define ICOMPTEST_H  
  3.   
  4. #include <unknwn.h>  
  5.   
  6. // {81A80687-6CC4-4996-8DD2-F058907FDCA8}  
  7. static const GUID IID_ICompTest =   
  8. { 0x81a80687, 0x6cc4, 0x4996, { 0x8d, 0xd2, 0xf0, 0x58, 0x90, 0x7f, 0xdc, 0xa8 } };  
  9.   
  10.   
  11. class ICompTest :  
  12.     public IUnknown  
  13. {  
  14. public:  
  15.     virtual int _stdcall HelloWorld() = 0;  
  16. };  
  17. #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中。


  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中。


  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函数的实现

  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中的所有引出函数就都出现了

  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的全貌


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


 

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


  1. LIBRARY "CompTest"  
  2. EXPORTS  
  3. DllCanUnloadNow  
  4. DllGetClassObject  
  5. DllUnregisterServer  
  6. DllRegisterServer  

 

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

CompTestClass.h

  1. #ifndef COMPTESTCLASS_H  
  2. #define COMPTESTCLASS_H  
  3.   
  4.   
  5. #include "ICompTest.h"  
  6.   
  7. // {9CA9DBE8-C0B1-42c9-B6C7-856BE5756855}  
  8. static const GUID CLSID_CompTestClass =   
  9. { 0x9ca9dbe8, 0xc0b1, 0x42c9, { 0xb6, 0xc7, 0x85, 0x6b, 0xe5, 0x75, 0x68, 0x55 } };  
  10.   
  11. class CompTestClass :  
  12.     public ICompTest  
  13. {  
  14. public:  
  15.       
  16.     CompTestClass();  
  17.     ~CompTestClass();  
  18.   
  19.     //要实现IUnknown接口  
  20.     virtual HRESULT _stdcall QueryInterface(const IID& riid, void** ppvObject);  
  21.     virtual ULONG _stdcall AddRef();  
  22.     virtual ULONG _stdcall Release();  
  23.   
  24.     //要实现ICompTest接口  
  25.     virtual int _stdcall HelloWorld();  
  26. protected:  
  27.   
  28.     ULONG m_Ref;  
  29. };  
  30. #endif  


CompTestClass.cpp

  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


  1. #ifndef FACTORY_H  
  2. #define FACTORY_H  
  3.   
  4. #include <unknwn.h>  
  5.   
  6.   
  7. class CompTestFactory :  
  8.     public IClassFactory  
  9. {  
  10. public:  
  11.     CompTestFactory();  
  12.     ~CompTestFactory();  
  13.   
  14.     //要实现IUnknown接口  
  15.     virtual HRESULT _stdcall QueryInterface(const IID& riid, void** ppvObject);  
  16.     virtual ULONG _stdcall AddRef();  
  17.     virtual ULONG _stdcall Release();  
  18.   
  19.     //要实现IClassFactory接口  
  20.     virtual HRESULT _stdcall CreateInstance(IUnknown *pUnkOuter, const IID& riid, void **ppvObject);  
  21.     virtual HRESULT _stdcall LockServer(BOOL fLock);  
  22.   
  23. protected:  
  24.     ULONG m_Ref;  
  25. };  
  26.   
  27. #endif  

 

factory.cpp

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


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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值