C++纯手工打造COM:COM之来龙去脉——组件如何被创建

来源:互联网 发布:战舰世界弗林特数据 编辑:程序博客网 时间:2024/05/21 22:33

本文意旨帮助初涉COM的学者能对COM组件的创建过程有一个清晰的了解。全文以《COM技术内幕》第7章的示例代码为蓝本,稍做修改之后进行详细介绍。如果你也阅读过此书的相关内容,那么理解起来将会更容易。

COM技术内幕》这本书的示例代码编写于1996年。时至今日,编译器发生了或多或少的变化,将本书作者编写的代码重新组织到Visual studio 2008中并成功编译,对于当时刚接触COM的我来说都略有困难,当时的我甚至不知道进程中服务器的组件需要注册才能调用(当然,现在我不需要注册也能调用),这些都是学习COM的过程中遇到的痛苦,但不是全部,因为学习的过程也是有乐趣的,那就是有所收获。

在介绍COM的创建过程之前,我想用一定的篇幅来解释一下COM到底是什么!开句玩笑,嘿嘿!好了,要正文了。

先整体,再局部,先看看我从别处扒来的图:

首先,我们来看一下客户是如何使用API函数来启动组件的创建的:


[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //in client.cpp  
  2. #include <objbase.h>  
  3. #include <iostream>  
  4.   
  5. #include "..\Chapter7\Iface.h"//包含了诸如IX的声明  
  6. #include "..\Chapter7\GUIDS.cpp"//包含了诸如IID_IX、CLSID_Component1的定义  
  7.   
  8. int main()  
  9. {  
  10.     CoInitialize(NULL) ;  
  11.   
  12.     IX* pIX = NULL ;   
  13.     HRESULT hr = ::CoCreateInstance(CLSID_Component1,  
  14.                                     NULL,   
  15.                                     CLSCTX_INPROC_SERVER,  
  16.                                     IID_IX,   
  17.                                     (void**)&pIX) ;  
  18.     if (SUCCEEDED(hr))  
  19.     {  
  20.         pIX->Fx() ;   
  21.   }  
  22.     
  23.   CoUninitialize();  
  24.   return 0;  
  25. }  

正如你所看到的,客户通过参数CLSID_Component1和 IID_IX调用了CoCreateInstance函数来创建所需要的组件。在此你应该对CLSID_Component1和 IID_IX高度警觉,因为这两个参数是创建组件的依据。下面我开始分析CoCreateInstance的调用过程。

<>首先有一点必须要明白,CoCreateInstance实际上是用CoGetClassObject实现的:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. HRESULT CoCreateInstance(const CLSID& clsid,IUnknown * pUnknownOuter,DWORD dwClsContext,const IID& iid,void ** ppv)  
  2. {  
  3.     *ppv=NULL;  
  4.     IClassFactory* pIFactory=NULL;  
  5.     HRESULT hr=CoGetClassObject(clsid,dwClsContext,NULL,IID_IClassFactory,(void**)&pIFactory);  
  6.     If(SUCCEEDED(hr))  
  7.     {  
  8.         hr=pIFactory->CreateInstance(pUnknownOuter,iid,&ppv);  
  9.         pIFactory->Release();  
  10.     }  
  11.     return hr;  
  12. }  

由上面的代码可以看到,CoCreateInstance首先调用CoGetClassObject。在此需要强调的一点是,CoGetClassObject从CoCreateInstance接受了CLSID_Component1和 IID_IX中的第一个实参(形参为clsid),即CLSID_Component1。到目前为此,先记住这一点就够了。下面我们来分析CoGetClassObject函数的调用过程。

1、CoGetClassObject首先根据形参clsid在注册表项HKEY_CLASS_ROOT\CLSID下查找与之匹配的值,如果找得到(前提是组件已经注册,注册的作用之一是在注册表中写入实现该组件的DLL保存在磁盘中的哪个位置,例如我注册的组件在注册表中的情况是这样的(如果图片中的文字看不清,可以鼠标右键另存为,再打开看):


),那么CoGetClassObject就将该DLL加载到当前进程地址空间中。

2、并调用该DLL中由程序员实现的DllGetClassObject函数:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //in component’s DLL  
  2. STDAPI DllGetClassObject(const CLSID& clsid,  
  3.                          const IID& iid,  
  4.                          void** ppv)  
  5. {  
  6.     if (clsid != CLSID_Component1)  
  7.     {  
  8.         return CLASS_E_CLASSNOTAVAILABLE ;  
  9.     }  
  10.   
  11.     CFactory* pFactory = new CFactory ;    
  12.     if (pFactory == NULL)  
  13.     {  
  14.         return E_OUTOFMEMORY ;  
  15.     }  
  16.   
  17.     HRESULT hr = pFactory->QueryInterface(iid, ppv);  
  18.     pFactory->Release() ;  
  19.     /*if pFactory->QueryInterface failed,pFactory->Release() will delete itself.*/  
  20.   
  21.     return hr ;  
  22. }  

由此可看到,DllGetClassObject首先对clsid进行判断,如果clsid的值表明不是组件本身的CLSID,即CLSID_Component1,就返回CLASS_E_CLASSNOTAVAILABLE。否则就创建一个类厂实例(它也由程序员在编写组件时自行实现),并通过此类厂实例指针请求由iid标识的接口,即pFactory->QueryInterface(iid, ppv)这行代码。 先等一等,还记得前面我说,CoGetClassObject从CoCreateInstance接受了CLSID_Component1和 IID_IX中的第一个实参(形参为clsid),即CLSID_Component1吗?我们先不管 IID_IX去哪里了。在此需要关心的是,这里的iid是从哪里传进来的?值是什么?答案是由CoGetClassObject传进来的,值是IID_IClassFactory。回到前面步骤<一>中CoCreateInstance函数的实现,你将会看到,iid的值确实为IID_IClassFactory。这意味着什么?pFactory->QueryInterface(iid, ppv)将只能请求IUnknownIClassFactory接口指针,正如下面的代码所示:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. HRESULT __stdcall CFactory::QueryInterface(const IID& iid, void** ppv)  
  2. {      
  3.     if ((iid == IID_IUnknown) || (iid == IID_IClassFactory))  
  4.     {  
  5.         *ppv = static_cast<IClassFactory*>(this) ;   
  6.     }  
  7.     else  
  8.     {  
  9.         *ppv = NULL ;  
  10.         return E_NOINTERFACE ;  
  11.     }  
  12.     reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;  
  13.     return S_OK ;  
  14. }  

这没有问题,我们就是要这样子做!因为CoGetClassObject在调用DLL中的DllGetClassObject函数时,传递给它的iid值是固定的IID_IClassFactory,因此我们类厂的QueryInterface即上述的CFactory::QueryInterface函数也只需要对IID_IUnknown和IID_IClassFactory处理就行。注意,CFactory::QueryInterface函数返回之后,* ppv就保存了创建所需组件的类厂指针。至此,CoGetClassObject函数调用完成。

<>接下来,我们来看看前面强调但未正式提及的参数IID_IX。为了避免你反复滚鼠标滚轮,我又将CoCreateInstance的实现代码再次贴到这里,同时也因为对CoCreateInstance的实现进行分析显示太重要了:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. HRESULT CoCreateInstance(const CLSID& clsid,IUnknown * pUnknownOuter,DWORD dwClsContext,const IID& iid,void ** ppv)  
  2. {  
  3.     *ppv=NULL;  
  4.     IClassFactory* pIFactory=NULL;  
  5.     HRESULT hr=CoGetClassObject(clsid,dwClsContext,NULL,IID_IClassFactory,(void**)&pIFactory);  
  6.     If(SUCCEEDED(hr))  
  7.     {  
  8.         hr=pIFactory->CreateInstance(pUnknownOuter,iid,&ppv);  
  9.         pIFactory->Release();  
  10.     }  
  11.     return hr;  
  12. }  

可以看到,CoGetClassObject调用完成之后,pIFactory像前面所说的那样,它指向了创建所需组件的类厂指针。随后通过这个指针调用了CreateInstance函数,即pIFactory->CreateInstance(pUnknownOuter,iid,&ppv)这行代码。这时你会发现,传递给CreateInstance函数的iid正是传给CoCreateInstance的那个iid,也就是客户代码中的实参IID_IX。而这里的CreateInstance函数是通过pIFactory来调用的,pIFactory的类型虽然是IClassFactory指针,但它实际指向的是派生类的实例,即我们的类厂CFactory。常规情况下,如果基类指针指向派生类,那么只能通过此基类指针调用派生类中的基类方法,但这里的CreateInstance是虚拟的,因此pIFactory->CreateInstance(pUnknownOuter,iid,&ppv)这行代码将执行派生类中的实现,而我们在派生类即CFactory中重写了CreateInstance:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,  
  2.                                            const IID& iid,  
  3.                                            void** ppv)   
  4. {  
  5.     if (pUnknownOuter != NULL)  
  6.     {  
  7.         return CLASS_E_NOAGGREGATION ;  
  8.     }  
  9.   
  10.     /* Create an actual component even if the requested interface is not supported. 
  11.     But subsequent calling Release will delete itselt if QueryInterface failed.*/  
  12.     CA* pA = new CA ;  
  13.     if (pA == NULL)  
  14.     {  
  15.         return E_OUTOFMEMORY ;  
  16.     }  
  17.   
  18.     // Get the requested interface.  
  19.     HRESULT hr = pA->QueryInterface(iid, ppv) ;  
  20.   
  21.     // Release the IUnknown pointer.  
  22.     // (If QueryInterface failed, component will delete itself.)  
  23.     pA->Release() ;  
  24.     return hr ;  
  25. }  

可以看到,类厂的CreateInstance函数使用C++new操作符创建实际的组件,并将客户代码中的接口标识符IID_IX传递给后续的QueryInterface调用,即pA->QueryInterface(iid, ppv) 这行代码。而组件本身的QueryInterface的实现也很简单,即返回它所能支持的接口指针,也就是基类指针:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv)  
  2. {      
  3.     if (iid == IID_IUnknown)  
  4.     {  
  5.         *ppv = static_cast<IX*>(this) ;   
  6.     }  
  7.     else if (iid == IID_IX)  
  8.     {  
  9.         *ppv = static_cast<IX*>(this) ;  
  10.     }  
  11.     else if (iid == IID_IY)  
  12.     {  
  13.         *ppv = static_cast<IY*>(this) ;   
  14.     }  
  15.     else  
  16.     {  
  17.         *ppv = NULL ;  
  18.         return E_NOINTERFACE ;  
  19.     }  
  20.     reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;  
  21.     return S_OK ;  
  22. }  

而我们的类CA的定义是这样的:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class CA : public IX,public IY   
  2. {  
  3. public:  
  4.     // IUnknown  
  5.     virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ;  
  6.     virtual ULONG __stdcall AddRef() ;  
  7.     virtual ULONG __stdcall Release() ;  
  8. ……  
  9. }  

CAIXIY派生。那么对于前面的QueryInterface,CA肯定支持IXIY接口,因此对IID_IX调用CA::QueryInterface(const IID& iid, void** ppv)肯定是可以的。换句说,客户代码调用CoCreateInstance(CLSID_Component1,NULL, CLSCTX_INPROC_SERVER, IID_IX, (void**)&pIX) 肯定能够成功,亦即成功创建了组件。CA::QueryInterface(const IID& iid, void** ppv)返回之后,* ppv就保存了指向组件实例的指针,这对于客户代码来说,pIX就取得了所请求的接口指针。至此,CoCreateInstance的调用完毕,那么后面通过接口指针pIX调用相应的方法就水到渠成了。  

以上就是组件的创建过程分析。不知是否实现了初衷,但通过本文,加深了我对组件创建过程的理解,如果你也有同感,我会倍感欣慰!

最后贴上本文的示例代码:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //in Chapter7 vcproj  
  2.   
  3. // Iface.h -   
  4. //    Declarations of interfaces, IIDs, and CLSID  
  5. //    shared by the client and the component.  
  6. //  
  7. interface IX : IUnknown  
  8. {  
  9.     virtual void pascal Fx() = 0 ;  
  10. };  
  11.   
  12.   
  13. interface IY : IUnknown  
  14. {  
  15.     virtual void pascal Fy() = 0 ;  
  16. };  
  17.   
  18.   
  19. interface IZ : IUnknown  
  20. {  
  21.     virtual void pascal Fz() = 0 ;  
  22. };  
  23.   
  24. //  
  25. // Declaration of GUIDs for interfaces and component.  
  26. //   These constants are defined in GUIDs.cpp.  
  27. //  
  28. extern "C" const IID IID_IX ;  
  29. extern "C" const IID IID_IY ;  
  30. extern "C" const IID IID_IZ ;  
  31.   
  32. extern "C" const CLSID CLSID_Component1 ;  
  33. #ifndef __Registry_H__  
  34. #define __Registry_H__  
  35. //  
  36. // Registry.h  
  37. //   - Helper functions registering and unregistering a component.  
  38. //  
  39.   
  40. // This function will register a component in the Registry.  
  41. // The component calls this function from its DllRegisterServer function.  
  42. HRESULT RegisterServer(HMODULE hModule,   
  43.                        const CLSID& clsid,   
  44.                        const char* szFriendlyName,  
  45.                        const char* szVerIndProgID,  
  46.                        const char* szProgID) ;  
  47.   
  48. // This function will unregister a component.  Components  
  49. // call this function from their DllUnregisterServer function.  
  50. HRESULT UnregisterServer(const CLSID& clsid,  
  51.                          const char* szVerIndProgID,  
  52.                          const char* szProgID) ;  
  53.   
  54. #endif  
  55. //  
  56. // Cmpnt.cpp  
  57. //  
  58. #include <iostream>  
  59. #include <objbase.h>  
  60. using std::cout;  
  61. using std::endl;  
  62.   
  63. #include "Iface.h"      // Interface declarations  
  64. #include "Registry.h"   // Registry helper functions  
  65. void trace(const char* strMsg)  
  66. {  
  67.     cout << strMsg << endl;  
  68. }  
  69. ///////////////////////////////////////////////////////////  
  70. //  
  71. // Global variables  
  72. //  
  73. static HMODULE g_hModule = NULL ;   // DLL module handle  
  74. static long g_cComponents = 0 ;     // Count of active components  
  75. static long g_cServerLocks = 0 ;    // Count of locks  
  76.   
  77. // Friendly name of component  
  78. const char g_szFriendlyName[] = "Inside COM, Chapter 7 Example" ;  
  79.   
  80. // Version-independent ProgID  
  81. const char g_szVerIndProgID[] = "InsideCOM.Chap07" ;  
  82.   
  83. // ProgID  
  84. const char g_szProgID[] = "InsideCOM.Chap07.1" ;  
  85.   
  86.   
  87. ///////////////////////////////////////////////////////////  
  88. //  
  89. // Component   
  90. //  
  91. class CA : public IX,  
  92.            public IY   
  93. {  
  94. public:  
  95.     // IUnknown  
  96.     virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ;  
  97.     virtual ULONG __stdcall AddRef() ;  
  98.     virtual ULONG __stdcall Release() ;  
  99.   
  100.     // Interface IX  
  101.     virtual void __stdcall Fx() { cout << "Fx" << endl ;}  
  102.   
  103.     // Interface IY  
  104.     virtual void __stdcall Fy() { cout << "Fy" << endl ;}   
  105.   
  106.     // Constructor  
  107.     CA() ;  
  108.   
  109.     // Destructor  
  110.     ~CA() ;  
  111.   
  112. private:  
  113.     // Reference count  
  114.     long m_cRef ;  
  115. } ;  
  116.   
  117.   
  118. //  
  119. // Constructor  
  120. //  
  121. CA::CA() : m_cRef(1)  
  122. {   
  123.     InterlockedIncrement(&g_cComponents) ;   
  124. }  
  125.   
  126. //  
  127. // Destructor  
  128. //  
  129. CA::~CA()   
  130. {   
  131.     InterlockedDecrement(&g_cComponents) ;   
  132.     trace("Component:\t\tDestroy self.") ;  
  133. }  
  134.   
  135. //  
  136. // IUnknown implementation  
  137. //  
  138. HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv)  
  139. {      
  140.     if (iid == IID_IUnknown)  
  141.     {  
  142.         *ppv = static_cast<IX*>(this) ;   
  143.     }  
  144.     else if (iid == IID_IX)  
  145.     {  
  146.         *ppv = static_cast<IX*>(this) ;  
  147.         trace("Component:\t\tReturn pointer to IX.") ;   
  148.     }  
  149.     else if (iid == IID_IY)  
  150.     {  
  151.         *ppv = static_cast<IY*>(this) ;   
  152.         trace("Component:\t\tReturn pointer to IY.") ;   
  153.     }  
  154.     else  
  155.     {  
  156.         *ppv = NULL ;  
  157.         return E_NOINTERFACE ;  
  158.     }  
  159.     reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;  
  160.     return S_OK ;  
  161. }  
  162.   
  163. ULONG __stdcall CA::AddRef()  
  164. {  
  165.     return InterlockedIncrement(&m_cRef) ;  
  166. }  
  167.   
  168. ULONG __stdcall CA::Release()   
  169. {  
  170.     if (InterlockedDecrement(&m_cRef) == 0)  
  171.     {  
  172.         delete this ;  
  173.         return 0 ;  
  174.     }  
  175.     return m_cRef ;  
  176. }  
  177.   
  178.   
  179. ///////////////////////////////////////////////////////////  
  180. //  
  181. // Class factory  
  182. //  
  183. class CFactory : public IClassFactory  
  184. {  
  185. public:  
  186.     // IUnknown  
  187.     virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ;           
  188.     virtual ULONG   __stdcall AddRef() ;  
  189.     virtual ULONG   __stdcall Release() ;  
  190.   
  191.     // Interface IClassFactory  
  192.     virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,  
  193.                                              const IID& iid,  
  194.                                              void** ppv) ;  
  195.     virtual HRESULT __stdcall LockServer(BOOL bLock) ;   
  196.   
  197.     // Constructor  
  198.     CFactory() : m_cRef(1) {}  
  199.   
  200.     // Destructor  
  201.     ~CFactory() { trace("Class factory:\t\tDestroy self.") ;}  
  202.   
  203. private:  
  204.     long m_cRef ;  
  205. } ;  
  206.   
  207. //  
  208. // Class factory IUnknown implementation  
  209. //  
  210. HRESULT __stdcall CFactory::QueryInterface(const IID& iid, void** ppv)  
  211. {      
  212.     if ((iid == IID_IUnknown) || (iid == IID_IClassFactory))  
  213.     {  
  214.         *ppv = static_cast<IClassFactory*>(this) ;   
  215.     }  
  216.     else  
  217.     {  
  218.         *ppv = NULL ;  
  219.         return E_NOINTERFACE ;  
  220.     }  
  221.     reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;  
  222.     return S_OK ;  
  223. }  
  224.   
  225. ULONG __stdcall CFactory::AddRef()  
  226. {  
  227.     return InterlockedIncrement(&m_cRef) ;  
  228. }  
  229.   
  230. ULONG __stdcall CFactory::Release()   
  231. {  
  232.     if (InterlockedDecrement(&m_cRef) == 0)  
  233.     {  
  234.         delete this ;  
  235.         return 0 ;  
  236.     }  
  237.     return m_cRef ;  
  238. }  
  239.   
  240. //  
  241. // IClassFactory implementation  
  242. //  
  243. HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,  
  244.                                            const IID& iid,  
  245.                                            void** ppv)   
  246. {  
  247.     trace("Class factory:\t\tCreate component.") ;  
  248.   
  249.     // Cannot aggregate.  
  250.     if (pUnknownOuter != NULL)  
  251.     {  
  252.         return CLASS_E_NOAGGREGATION ;  
  253.     }  
  254.   
  255.     /* Create an actual component even if the requested interface is not supported. 
  256.     But subsequent calling Release will delete itselt if QueryInterface failed.*/  
  257.     CA* pA = new CA ;  
  258.     if (pA == NULL)  
  259.     {  
  260.         return E_OUTOFMEMORY ;  
  261.     }  
  262.   
  263.     // Get the requested interface.  
  264.     HRESULT hr = pA->QueryInterface(iid, ppv) ;  
  265.   
  266.     // Release the IUnknown pointer.  
  267.     // (If QueryInterface failed, component will delete itself.)  
  268.     pA->Release() ;  
  269.     return hr ;  
  270. }  
  271.   
  272. // LockServer  
  273. HRESULT __stdcall CFactory::LockServer(BOOL bLock)   
  274. {  
  275.     if (bLock)  
  276.     {  
  277.         InterlockedIncrement(&g_cServerLocks) ;   
  278.     }  
  279.     else  
  280.     {  
  281.         InterlockedDecrement(&g_cServerLocks) ;  
  282.     }  
  283.     return S_OK ;  
  284. }  
  285.   
  286.   
  287. ///////////////////////////////////////////////////////////  
  288. //  
  289. // Exported functions  
  290. //  
  291.   
  292. //  
  293. // Can DLL unload now?  
  294. //  
  295. STDAPI DllCanUnloadNow()  
  296. {  
  297.     if ((g_cComponents == 0) && (g_cServerLocks == 0))  
  298.     {  
  299.         return S_OK ;  
  300.     }  
  301.     else  
  302.     {  
  303.         return S_FALSE ;  
  304.     }  
  305. }  
  306.   
  307. //  
  308. // Get class factory  
  309. //  
  310. STDAPI DllGetClassObject(const CLSID& clsid,  
  311.                          const IID& iid,  
  312.                          void** ppv)  
  313. {  
  314.     trace("DllGetClassObject:\tCreate class factory.") ;  
  315.   
  316.     // Can we create this component?  
  317.     if (clsid != CLSID_Component1)  
  318.     {  
  319.         return CLASS_E_CLASSNOTAVAILABLE ;  
  320.     }  
  321.   
  322.     // Create class factory.  
  323.     /* set CFactory::m_cRef's value to 1 in constructor.*/  
  324.     CFactory* pFactory = new CFactory ;    
  325.       
  326.     if (pFactory == NULL)  
  327.     {  
  328.         return E_OUTOFMEMORY ;  
  329.     }  
  330.   
  331.     // Get requested interface.  
  332.     HRESULT hr = pFactory->QueryInterface(iid, ppv);  
  333.     /*call CFactory::AddRef() if requested interface supported,or ppv's value will be set to null.*/  
  334.   
  335.     pFactory->Release() ;  
  336.     /*if pFactory->QueryInterface failed,pFactory->Release() will delete itself.*/  
  337.   
  338.     return hr ;  
  339. }  
  340.   
  341. //  
  342. // Server registration  
  343. //  
  344. STDAPI DllRegisterServer()  
  345. {  
  346.     return RegisterServer(g_hModule,   
  347.                           CLSID_Component1,  
  348.                           g_szFriendlyName,  
  349.                           g_szVerIndProgID,  
  350.                           g_szProgID) ;  
  351. }  
  352.   
  353.   
  354. //  
  355. // Server unregistration  
  356. //  
  357. STDAPI DllUnregisterServer()  
  358. {  
  359.     return UnregisterServer(CLSID_Component1,  
  360.                             g_szVerIndProgID,  
  361.                             g_szProgID) ;  
  362. }  
  363.   
  364. ///////////////////////////////////////////////////////////  
  365. //  
  366. // DLL module information  
  367. //  
  368. BOOL APIENTRY DllMain(HMODULE hModule,  
  369.                       DWORD dwReason,  
  370.                       void* lpReserved)  
  371. {  
  372.     if (dwReason == DLL_PROCESS_ATTACH)  
  373.     {  
  374.         g_hModule = hModule ;  
  375.     }  
  376.     return TRUE ;  
  377. }  
  378.   
  379. // in CMPNT.def  
  380. LIBRARY "Chapter7"  
  381. EXPORTS  
  382.     DllGetClassObject       PRIVATE  
  383.     DllCanUnloadNow         PRIVATE  
  384.     DllRegisterServer       PRIVATE  
  385.     DllUnregisterServer     PRIVATE  
  386. //  
  387. // GUIDs.cpp  
  388. //   - Defines all IIDs and CLSIDs for the client and the component.  
  389. //     The declaration of these GUIDs is in Iface.h  
  390. //  
  391. #include <objbase.h>  
  392.   
  393. // {32bb8320-b41b-11cf-a6bb-0080c7b2d682}  
  394. extern "C" const IID IID_IX =   
  395.     {0x32bb8320, 0xb41b, 0x11cf,  
  396.     {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;  
  397.   
  398. // {32bb8321-b41b-11cf-a6bb-0080c7b2d682}  
  399. extern "C" const IID IID_IY =   
  400.     {0x32bb8321, 0xb41b, 0x11cf,  
  401.     {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;  
  402.   
  403. // {32bb8322-b41b-11cf-a6bb-0080c7b2d682}  
  404. extern "C" const IID IID_IZ =   
  405.     {0x32bb8322, 0xb41b, 0x11cf,  
  406.     {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;  
  407.   
  408. // {0c092c21-882c-11cf-a6bb-0080c7b2d682}  
  409. extern "C" const CLSID CLSID_Component1 =  
  410.     {0x0c092c21, 0x882c, 0x11cf,  
  411.     {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;  
  412. //  
  413. // Registry.cpp  
  414. //  
  415.   
  416. #include <objbase.h>  
  417. #include <assert.h>  
  418.   
  419. #include "Registry.h"  
  420.   
  421. ////////////////////////////////////////////////////////  
  422. //  
  423. // Internal helper functions prototypes  
  424. //  
  425.   
  426. // Set the given key and its value.  
  427. BOOL setKeyAndValue(const char* pszPath,  
  428.                     const char* szSubkey,  
  429.                     const char* szValue) ;  
  430.   
  431. // Convert a CLSID into a char string.  
  432. void CLSIDtochar(const CLSID& clsid,   
  433.                  char* szCLSID,  
  434.                  int length) ;  
  435.   
  436. // Delete szKeyChild and all of its descendents.  
  437. LONG recursiveDeleteKey(HKEY hKeyParent, const char* szKeyChild) ;  
  438.   
  439. ////////////////////////////////////////////////////////  
  440. //  
  441. // Constants  
  442. //  
  443.   
  444. // Size of a CLSID as a string  
  445. const int CLSID_STRING_SIZE = 39 ;  
  446.   
  447. /////////////////////////////////////////////////////////  
  448. //  
  449. // Public function implementation  
  450. //  
  451.   
  452. //  
  453. // Register the component in the registry.  
  454. //  
  455. HRESULT RegisterServer(HMODULE hModule,            // DLL module handle  
  456.                        const CLSID& clsid,         // Class ID  
  457.                        const char* szFriendlyName, // Friendly Name  
  458.                        const char* szVerIndProgID, // Programmatic  
  459.                        const char* szProgID)       //   IDs  
  460. {  
  461.     // Get server location.  
  462.     char szModule[512] ;  
  463.     DWORD dwResult =  
  464.         ::GetModuleFileName(hModule,   
  465.                             szModule,  
  466.                             sizeof(szModule)/sizeof(char)) ;  
  467.     assert(dwResult != 0) ;  
  468.   
  469.     // Convert the CLSID into a char.  
  470.     char szCLSID[CLSID_STRING_SIZE] ;  
  471.     CLSIDtochar(clsid, szCLSID, sizeof(szCLSID)) ;  
  472.   
  473.     // Build the key CLSID\\{...}  
  474.     char szKey[64] ;  
  475.     strcpy(szKey, "CLSID\\") ;  
  476.     strcat(szKey, szCLSID) ;  
  477.     
  478.     // Add the CLSID to the registry.  
  479.     setKeyAndValue(szKey, NULL, szFriendlyName) ;  
  480.   
  481.     // Add the server filename subkey under the CLSID key.  
  482.     setKeyAndValue(szKey, "InprocServer32", szModule) ;  
  483.   
  484.     // Add the ProgID subkey under the CLSID key.  
  485.     setKeyAndValue(szKey, "ProgID", szProgID) ;  
  486.   
  487.     // Add the version-independent ProgID subkey under CLSID key.  
  488.     setKeyAndValue(szKey, "VersionIndependentProgID",  
  489.                    szVerIndProgID) ;  
  490.   
  491.     // Add the version-independent ProgID subkey under HKEY_CLASSES_ROOT.  
  492.     setKeyAndValue(szVerIndProgID, NULL, szFriendlyName) ;   
  493.     setKeyAndValue(szVerIndProgID, "CLSID", szCLSID) ;  
  494.     setKeyAndValue(szVerIndProgID, "CurVer", szProgID) ;  
  495.   
  496.     // Add the versioned ProgID subkey under HKEY_CLASSES_ROOT.  
  497.     setKeyAndValue(szProgID, NULL, szFriendlyName) ;   
  498.     setKeyAndValue(szProgID, "CLSID", szCLSID) ;  
  499.   
  500.     return S_OK ;  
  501. }  
  502.   
  503. //  
  504. // Remove the component from the registry.  
  505. //  
  506. LONG UnregisterServer(const CLSID& clsid,         // Class ID  
  507.                       const char* szVerIndProgID, // Programmatic  
  508.                       const char* szProgID)       //   IDs  
  509. {  
  510.     // Convert the CLSID into a char.  
  511.     char szCLSID[CLSID_STRING_SIZE] ;  
  512.     CLSIDtochar(clsid, szCLSID, sizeof(szCLSID)) ;  
  513.   
  514.     // Build the key CLSID\\{...}  
  515.     char szKey[64] ;  
  516.     strcpy(szKey, "CLSID\\") ;  
  517.     strcat(szKey, szCLSID) ;  
  518.   
  519.     // Delete the CLSID Key - CLSID\{...}  
  520.     LONG lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szKey) ;  
  521.     assert((lResult == ERROR_SUCCESS) ||  
  522.            (lResult == ERROR_FILE_NOT_FOUND)) ; // Subkey may not exist.  
  523.   
  524.     // Delete the version-independent ProgID Key.  
  525.     lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szVerIndProgID) ;  
  526.     assert((lResult == ERROR_SUCCESS) ||  
  527.            (lResult == ERROR_FILE_NOT_FOUND)) ; // Subkey may not exist.  
  528.   
  529.     // Delete the ProgID key.  
  530.     lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szProgID) ;  
  531.     assert((lResult == ERROR_SUCCESS) ||  
  532.            (lResult == ERROR_FILE_NOT_FOUND)) ; // Subkey may not exist.  
  533.   
  534.     return S_OK ;  
  535. }  
  536.   
  537. ///////////////////////////////////////////////////////////  
  538. //  
  539. // Internal helper functions  
  540. //  
  541.   
  542. // Convert a CLSID to a char string.  
  543. void CLSIDtochar(const CLSID& clsid,  
  544.                  char* szCLSID,  
  545.                  int length)  
  546. {  
  547.     assert(length >= CLSID_STRING_SIZE) ;  
  548.     // Get CLSID  
  549.     LPOLESTR wszCLSID = NULL ;  
  550.     HRESULT hr = StringFromCLSID(clsid, &wszCLSID) ;  
  551.     assert(SUCCEEDED(hr)) ;  
  552.   
  553.     // Covert from wide characters to non-wide.  
  554.     wcstombs(szCLSID, wszCLSID, length) ;  
  555.   
  556.     // Free memory.  
  557.     CoTaskMemFree(wszCLSID) ;  
  558. }  
  559.   
  560. //  
  561. // Delete a key and all of its descendents.  
  562. //  
  563. LONG recursiveDeleteKey(HKEY hKeyParent,           // Parent of key to delete  
  564.                         const char* lpszKeyChild)  // Key to delete  
  565. {  
  566.     // Open the child.  
  567.     HKEY hKeyChild ;  
  568.     LONG lRes = RegOpenKeyEx(hKeyParent, lpszKeyChild, 0,  
  569.                              KEY_ALL_ACCESS, &hKeyChild) ;  
  570.     if (lRes != ERROR_SUCCESS)  
  571.     {  
  572.         return lRes ;  
  573.     }  
  574.   
  575.     // Enumerate all of the decendents of this child.  
  576.     FILETIME time ;  
  577.     char szBuffer[256] ;  
  578.     DWORD dwSize = 256 ;  
  579.     while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL,  
  580.                         NULL, NULL, &time) == S_OK)  
  581.     {  
  582.         // Delete the decendents of this child.  
  583.         lRes = recursiveDeleteKey(hKeyChild, szBuffer) ;  
  584.         if (lRes != ERROR_SUCCESS)  
  585.         {  
  586.             // Cleanup before exiting.  
  587.             RegCloseKey(hKeyChild) ;  
  588.             return lRes;  
  589.         }  
  590.         dwSize = 256 ;  
  591.     }  
  592.   
  593.     // Close the child.  
  594.     RegCloseKey(hKeyChild) ;  
  595.   
  596.     // Delete this child.  
  597.     return RegDeleteKey(hKeyParent, lpszKeyChild) ;  
  598. }  
  599.   
  600. //  
  601. // Create a key and set its value.  
  602. //   - This helper function was borrowed and modifed from  
  603. //     Kraig Brockschmidt's book Inside OLE.  
  604. //  
  605. BOOL setKeyAndValue(const char* szKey,  
  606.                     const char* szSubkey,  
  607.                     const char* szValue)  
  608. {  
  609.     HKEY hKey;  
  610.     char szKeyBuf[1024] ;  
  611.   
  612.     // Copy keyname into buffer.  
  613.     strcpy(szKeyBuf, szKey) ;  
  614.   
  615.     // Add subkey name to buffer.  
  616.     if (szSubkey != NULL)  
  617.     {  
  618.         strcat(szKeyBuf, "\\") ;  
  619.         strcat(szKeyBuf, szSubkey ) ;  
  620.     }  
  621.   
  622.     // Create and open key and subkey.  
  623.     long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT ,  
  624.                                   szKeyBuf,   
  625.                                   0, NULL, REG_OPTION_NON_VOLATILE,  
  626.                                   KEY_ALL_ACCESS, NULL,   
  627.                                   &hKey, NULL) ;  
  628.     if (lResult != ERROR_SUCCESS)  
  629.     {  
  630.         return FALSE ;  
  631.     }  
  632.   
  633.     // Set the Value.  
  634.     if (szValue != NULL)  
  635.     {  
  636.         RegSetValueEx(hKey, NULL, 0, REG_SZ,   
  637.                       (BYTE *)szValue,   
  638.                       strlen(szValue)+1) ;  
  639.     }  
  640.   
  641.     RegCloseKey(hKey) ;  
  642.     return TRUE ;  
  643. }  
  644.   
  645.   
  646.   
  647. //in UseCmpnt vcproj  
  648.   
  649. //client.cpp  
  650. #include <iostream>  
  651. using std::cout;  
  652. using std::endl;  
  653. #include <objbase.h>  
  654.   
  655. #include "..\Chapter7\Iface.h"//包含了诸如IX、IY的声明  
  656. #include "..\Chapter7\GUIDS.cpp"//包含了诸如IID_IX、CLSID_Component1的定义  
  657.   
  658.   
  659. void OutPut(const char* msg);  
  660. {   
  661.     cout << "Client: \t\t" << msg << endl ;  
  662. }  
  663.   
  664. int main()  
  665. {  
  666.     CoInitialize(NULL) ;  
  667.   
  668.     OutPut("Call CoCreateInstance to create") ;  
  669.     OutPut("  component and get interface IX.") ;  
  670.     IX* pIX = NULL ;   
  671.     HRESULT hr = ::CoCreateInstance(CLSID_Component1,  
  672.                                     NULL,   
  673.                                     CLSCTX_INPROC_SERVER,  
  674.                                     IID_IX,   
  675.                                     (void**)&pIX) ;  
  676.     if (SUCCEEDED(hr))  
  677.     {  
  678.         OutPut("Succeeded getting IX.") ;  
  679.         pIX->Fx() ;          // Use interface IX.  
  680.   
  681.         OutPut("Ask for interface IY.") ;  
  682.         IY* pIY = NULL ;  
  683.         hr = pIX->QueryInterface(IID_IY, (void**)&pIY) ;  
  684.         if (SUCCEEDED(hr))  
  685.         {  
  686.             OutPut("Succeeded getting IY.") ;  
  687.             pIY->Fy() ;       // Use interface IY.  
  688.             pIY->Release() ;  
  689.             OutPut("Release IY interface.") ;  
  690.         }  
  691.         else  
  692.         {  
  693.             OutPut("Could not get interface IY.") ;  
  694.         }  
  695.   
  696.         OutPut("Ask for interface IZ.") ;  
  697.   
  698.         IZ* pIZ = NULL ;  
  699.         hr = pIX->QueryInterface(IID_IZ, (void**)&pIZ) ;  
  700.         if (SUCCEEDED(hr))  
  701.         {  
  702.             OutPut("Succeeded in getting interface IZ.") ;  
  703.             pIZ->Fz() ;  
  704.             pIZ->Release() ;  
  705.             OutPut("Release IZ interface.") ;  
  706.         }  
  707.         else  
  708.         {  
  709.             OutPut("Could not get interface IZ.") ;  
  710.         }  
  711.   
  712.         OutPut("Release IX interface.") ;  
  713.         pIX->Release() ;  
  714.     }  
  715.     else  
  716.     {  
  717.         cout << "Client: \t\tCould not create component. hr = "  
  718.             << hex << hr << endl ;      
  719.     }  
  720.   
  721.     // Uninitialize COM Library  
  722.     CoUninitialize();  
  723.   
  724.     return 0;  
  725. }  

                               

版权所有,翻版不究,欢迎山寨!          

本文意旨帮助初涉COM的学者能对COM组件的创建过程有一个清晰的了解。全文以《COM技术内幕》第7章的示例代码为蓝本,稍做修改之后进行详细介绍。如果你也阅读过此书的相关内容,那么理解起来将会更容易。

COM技术内幕》这本书的示例代码编写于1996年。时至今日,编译器发生了或多或少的变化,将本书作者编写的代码重新组织到Visual studio 2008中并成功编译,对于当时刚接触COM的我来说都略有困难,当时的我甚至不知道进程中服务器的组件需要注册才能调用(当然,现在我不需要注册也能调用),这些都是学习COM的过程中遇到的痛苦,但不是全部,因为学习的过程也是有乐趣的,那就是有所收获。

在介绍COM的创建过程之前,我想用一定的篇幅来解释一下COM到底是什么!开句玩笑,嘿嘿!好了,要正文了。

先整体,再局部,先看看我从别处扒来的图:

首先,我们来看一下客户是如何使用API函数来启动组件的创建的:


[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //in client.cpp  
  2. #include <objbase.h>  
  3. #include <iostream>  
  4.   
  5. #include "..\Chapter7\Iface.h"//包含了诸如IX的声明  
  6. #include "..\Chapter7\GUIDS.cpp"//包含了诸如IID_IX、CLSID_Component1的定义  
  7.   
  8. int main()  
  9. {  
  10.     CoInitialize(NULL) ;  
  11.   
  12.     IX* pIX = NULL ;   
  13.     HRESULT hr = ::CoCreateInstance(CLSID_Component1,  
  14.                                     NULL,   
  15.                                     CLSCTX_INPROC_SERVER,  
  16.                                     IID_IX,   
  17.                                     (void**)&pIX) ;  
  18.     if (SUCCEEDED(hr))  
  19.     {  
  20.         pIX->Fx() ;   
  21.   }  
  22.     
  23.   CoUninitialize();  
  24.   return 0;  
  25. }  

正如你所看到的,客户通过参数CLSID_Component1和 IID_IX调用了CoCreateInstance函数来创建所需要的组件。在此你应该对CLSID_Component1和 IID_IX高度警觉,因为这两个参数是创建组件的依据。下面我开始分析CoCreateInstance的调用过程。

<>首先有一点必须要明白,CoCreateInstance实际上是用CoGetClassObject实现的:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. HRESULT CoCreateInstance(const CLSID& clsid,IUnknown * pUnknownOuter,DWORD dwClsContext,const IID& iid,void ** ppv)  
  2. {  
  3.     *ppv=NULL;  
  4.     IClassFactory* pIFactory=NULL;  
  5.     HRESULT hr=CoGetClassObject(clsid,dwClsContext,NULL,IID_IClassFactory,(void**)&pIFactory);  
  6.     If(SUCCEEDED(hr))  
  7.     {  
  8.         hr=pIFactory->CreateInstance(pUnknownOuter,iid,&ppv);  
  9.         pIFactory->Release();  
  10.     }  
  11.     return hr;  
  12. }  

由上面的代码可以看到,CoCreateInstance首先调用CoGetClassObject。在此需要强调的一点是,CoGetClassObject从CoCreateInstance接受了CLSID_Component1和 IID_IX中的第一个实参(形参为clsid),即CLSID_Component1。到目前为此,先记住这一点就够了。下面我们来分析CoGetClassObject函数的调用过程。

1、CoGetClassObject首先根据形参clsid在注册表项HKEY_CLASS_ROOT\CLSID下查找与之匹配的值,如果找得到(前提是组件已经注册,注册的作用之一是在注册表中写入实现该组件的DLL保存在磁盘中的哪个位置,例如我注册的组件在注册表中的情况是这样的(如果图片中的文字看不清,可以鼠标右键另存为,再打开看):


),那么CoGetClassObject就将该DLL加载到当前进程地址空间中。

2、并调用该DLL中由程序员实现的DllGetClassObject函数:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //in component’s DLL  
  2. STDAPI DllGetClassObject(const CLSID& clsid,  
  3.                          const IID& iid,  
  4.                          void** ppv)  
  5. {  
  6.     if (clsid != CLSID_Component1)  
  7.     {  
  8.         return CLASS_E_CLASSNOTAVAILABLE ;  
  9.     }  
  10.   
  11.     CFactory* pFactory = new CFactory ;    
  12.     if (pFactory == NULL)  
  13.     {  
  14.         return E_OUTOFMEMORY ;  
  15.     }  
  16.   
  17.     HRESULT hr = pFactory->QueryInterface(iid, ppv);  
  18.     pFactory->Release() ;  
  19.     /*if pFactory->QueryInterface failed,pFactory->Release() will delete itself.*/  
  20.   
  21.     return hr ;  
  22. }  

由此可看到,DllGetClassObject首先对clsid进行判断,如果clsid的值表明不是组件本身的CLSID,即CLSID_Component1,就返回CLASS_E_CLASSNOTAVAILABLE。否则就创建一个类厂实例(它也由程序员在编写组件时自行实现),并通过此类厂实例指针请求由iid标识的接口,即pFactory->QueryInterface(iid, ppv)这行代码。 先等一等,还记得前面我说,CoGetClassObject从CoCreateInstance接受了CLSID_Component1和 IID_IX中的第一个实参(形参为clsid),即CLSID_Component1吗?我们先不管 IID_IX去哪里了。在此需要关心的是,这里的iid是从哪里传进来的?值是什么?答案是由CoGetClassObject传进来的,值是IID_IClassFactory。回到前面步骤<一>中CoCreateInstance函数的实现,你将会看到,iid的值确实为IID_IClassFactory。这意味着什么?pFactory->QueryInterface(iid, ppv)将只能请求IUnknownIClassFactory接口指针,正如下面的代码所示:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. HRESULT __stdcall CFactory::QueryInterface(const IID& iid, void** ppv)  
  2. {      
  3.     if ((iid == IID_IUnknown) || (iid == IID_IClassFactory))  
  4.     {  
  5.         *ppv = static_cast<IClassFactory*>(this) ;   
  6.     }  
  7.     else  
  8.     {  
  9.         *ppv = NULL ;  
  10.         return E_NOINTERFACE ;  
  11.     }  
  12.     reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;  
  13.     return S_OK ;  
  14. }  

这没有问题,我们就是要这样子做!因为CoGetClassObject在调用DLL中的DllGetClassObject函数时,传递给它的iid值是固定的IID_IClassFactory,因此我们类厂的QueryInterface即上述的CFactory::QueryInterface函数也只需要对IID_IUnknown和IID_IClassFactory处理就行。注意,CFactory::QueryInterface函数返回之后,* ppv就保存了创建所需组件的类厂指针。至此,CoGetClassObject函数调用完成。

<>接下来,我们来看看前面强调但未正式提及的参数IID_IX。为了避免你反复滚鼠标滚轮,我又将CoCreateInstance的实现代码再次贴到这里,同时也因为对CoCreateInstance的实现进行分析显示太重要了:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. HRESULT CoCreateInstance(const CLSID& clsid,IUnknown * pUnknownOuter,DWORD dwClsContext,const IID& iid,void ** ppv)  
  2. {  
  3.     *ppv=NULL;  
  4.     IClassFactory* pIFactory=NULL;  
  5.     HRESULT hr=CoGetClassObject(clsid,dwClsContext,NULL,IID_IClassFactory,(void**)&pIFactory);  
  6.     If(SUCCEEDED(hr))  
  7.     {  
  8.         hr=pIFactory->CreateInstance(pUnknownOuter,iid,&ppv);  
  9.         pIFactory->Release();  
  10.     }  
  11.     return hr;  
  12. }  

可以看到,CoGetClassObject调用完成之后,pIFactory像前面所说的那样,它指向了创建所需组件的类厂指针。随后通过这个指针调用了CreateInstance函数,即pIFactory->CreateInstance(pUnknownOuter,iid,&ppv)这行代码。这时你会发现,传递给CreateInstance函数的iid正是传给CoCreateInstance的那个iid,也就是客户代码中的实参IID_IX。而这里的CreateInstance函数是通过pIFactory来调用的,pIFactory的类型虽然是IClassFactory指针,但它实际指向的是派生类的实例,即我们的类厂CFactory。常规情况下,如果基类指针指向派生类,那么只能通过此基类指针调用派生类中的基类方法,但这里的CreateInstance是虚拟的,因此pIFactory->CreateInstance(pUnknownOuter,iid,&ppv)这行代码将执行派生类中的实现,而我们在派生类即CFactory中重写了CreateInstance:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,  
  2.                                            const IID& iid,  
  3.                                            void** ppv)   
  4. {  
  5.     if (pUnknownOuter != NULL)  
  6.     {  
  7.         return CLASS_E_NOAGGREGATION ;  
  8.     }  
  9.   
  10.     /* Create an actual component even if the requested interface is not supported. 
  11.     But subsequent calling Release will delete itselt if QueryInterface failed.*/  
  12.     CA* pA = new CA ;  
  13.     if (pA == NULL)  
  14.     {  
  15.         return E_OUTOFMEMORY ;  
  16.     }  
  17.   
  18.     // Get the requested interface.  
  19.     HRESULT hr = pA->QueryInterface(iid, ppv) ;  
  20.   
  21.     // Release the IUnknown pointer.  
  22.     // (If QueryInterface failed, component will delete itself.)  
  23.     pA->Release() ;  
  24.     return hr ;  
  25. }  

可以看到,类厂的CreateInstance函数使用C++new操作符创建实际的组件,并将客户代码中的接口标识符IID_IX传递给后续的QueryInterface调用,即pA->QueryInterface(iid, ppv) 这行代码。而组件本身的QueryInterface的实现也很简单,即返回它所能支持的接口指针,也就是基类指针:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv)  
  2. {      
  3.     if (iid == IID_IUnknown)  
  4.     {  
  5.         *ppv = static_cast<IX*>(this) ;   
  6.     }  
  7.     else if (iid == IID_IX)  
  8.     {  
  9.         *ppv = static_cast<IX*>(this) ;  
  10.     }  
  11.     else if (iid == IID_IY)  
  12.     {  
  13.         *ppv = static_cast<IY*>(this) ;   
  14.     }  
  15.     else  
  16.     {  
  17.         *ppv = NULL ;  
  18.         return E_NOINTERFACE ;  
  19.     }  
  20.     reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;  
  21.     return S_OK ;  
  22. }  

而我们的类CA的定义是这样的:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class CA : public IX,public IY   
  2. {  
  3. public:  
  4.     // IUnknown  
  5.     virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ;  
  6.     virtual ULONG __stdcall AddRef() ;  
  7.     virtual ULONG __stdcall Release() ;  
  8. ……  
  9. }  

CAIXIY派生。那么对于前面的QueryInterface,CA肯定支持IXIY接口,因此对IID_IX调用CA::QueryInterface(const IID& iid, void** ppv)肯定是可以的。换句说,客户代码调用CoCreateInstance(CLSID_Component1,NULL, CLSCTX_INPROC_SERVER, IID_IX, (void**)&pIX) 肯定能够成功,亦即成功创建了组件。CA::QueryInterface(const IID& iid, void** ppv)返回之后,* ppv就保存了指向组件实例的指针,这对于客户代码来说,pIX就取得了所请求的接口指针。至此,CoCreateInstance的调用完毕,那么后面通过接口指针pIX调用相应的方法就水到渠成了。  

以上就是组件的创建过程分析。不知是否实现了初衷,但通过本文,加深了我对组件创建过程的理解,如果你也有同感,我会倍感欣慰!

最后贴上本文的示例代码:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //in Chapter7 vcproj  
  2.   
  3. // Iface.h -   
  4. //    Declarations of interfaces, IIDs, and CLSID  
  5. //    shared by the client and the component.  
  6. //  
  7. interface IX : IUnknown  
  8. {  
  9.     virtual void pascal Fx() = 0 ;  
  10. };  
  11.   
  12.   
  13. interface IY : IUnknown  
  14. {  
  15.     virtual void pascal Fy() = 0 ;  
  16. };  
  17.   
  18.   
  19. interface IZ : IUnknown  
  20. {  
  21.     virtual void pascal Fz() = 0 ;  
  22. };  
  23.   
  24. //  
  25. // Declaration of GUIDs for interfaces and component.  
  26. //   These constants are defined in GUIDs.cpp.  
  27. //  
  28. extern "C" const IID IID_IX ;  
  29. extern "C" const IID IID_IY ;  
  30. extern "C" const IID IID_IZ ;  
  31.   
  32. extern "C" const CLSID CLSID_Component1 ;  
  33. #ifndef __Registry_H__  
  34. #define __Registry_H__  
  35. //  
  36. // Registry.h  
  37. //   - Helper functions registering and unregistering a component.  
  38. //  
  39.   
  40. // This function will register a component in the Registry.  
  41. // The component calls this function from its DllRegisterServer function.  
  42. HRESULT RegisterServer(HMODULE hModule,   
  43.                        const CLSID& clsid,   
  44.                        const char* szFriendlyName,  
  45.                        const char* szVerIndProgID,  
  46.                        const char* szProgID) ;  
  47.   
  48. // This function will unregister a component.  Components  
  49. // call this function from their DllUnregisterServer function.  
  50. HRESULT UnregisterServer(const CLSID& clsid,  
  51.                          const char* szVerIndProgID,  
  52.                          const char* szProgID) ;  
  53.   
  54. #endif  
  55. //  
  56. // Cmpnt.cpp  
  57. //  
  58. #include <iostream>  
  59. #include <objbase.h>  
  60. using std::cout;  
  61. using std::endl;  
  62.   
  63. #include "Iface.h"      // Interface declarations  
  64. #include "Registry.h"   // Registry helper functions  
  65. void trace(const char* strMsg)  
  66. {  
  67.     cout << strMsg << endl;  
  68. }  
  69. ///////////////////////////////////////////////////////////  
  70. //  
  71. // Global variables  
  72. //  
  73. static HMODULE g_hModule = NULL ;   // DLL module handle  
  74. static long g_cComponents = 0 ;     // Count of active components  
  75. static long g_cServerLocks = 0 ;    // Count of locks  
  76.   
  77. // Friendly name of component  
  78. const char g_szFriendlyName[] = "Inside COM, Chapter 7 Example" ;  
  79.   
  80. // Version-independent ProgID  
  81. const char g_szVerIndProgID[] = "InsideCOM.Chap07" ;  
  82.   
  83. // ProgID  
  84. const char g_szProgID[] = "InsideCOM.Chap07.1" ;  
  85.   
  86.   
  87. ///////////////////////////////////////////////////////////  
  88. //  
  89. // Component   
  90. //  
  91. class CA : public IX,  
  92.            public IY   
  93. {  
  94. public:  
  95.     // IUnknown  
  96.     virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ;  
  97.     virtual ULONG __stdcall AddRef() ;  
  98.     virtual ULONG __stdcall Release() ;  
  99.   
  100.     // Interface IX  
  101.     virtual void __stdcall Fx() { cout << "Fx" << endl ;}  
  102.   
  103.     // Interface IY  
  104.     virtual void __stdcall Fy() { cout << "Fy" << endl ;}   
  105.   
  106.     // Constructor  
  107.     CA() ;  
  108.   
  109.     // Destructor  
  110.     ~CA() ;  
  111.   
  112. private:  
  113.     // Reference count  
  114.     long m_cRef ;  
  115. } ;  
  116.   
  117.   
  118. //  
  119. // Constructor  
  120. //  
  121. CA::CA() : m_cRef(1)  
  122. {   
  123.     InterlockedIncrement(&g_cComponents) ;   
  124. }  
  125.   
  126. //  
  127. // Destructor  
  128. //  
  129. CA::~CA()   
  130. {   
  131.     InterlockedDecrement(&g_cComponents) ;   
  132.     trace("Component:\t\tDestroy self.") ;  
  133. }  
  134.   
  135. //  
  136. // IUnknown implementation  
  137. //  
  138. HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv)  
  139. {      
  140.     if (iid == IID_IUnknown)  
  141.     {  
  142.         *ppv = static_cast<IX*>(this) ;   
  143.     }  
  144.     else if (iid == IID_IX)  
  145.     {  
  146.         *ppv = static_cast<IX*>(this) ;  
  147.         trace("Component:\t\tReturn pointer to IX.") ;   
  148.     }  
  149.     else if (iid == IID_IY)  
  150.     {  
  151.         *ppv = static_cast<IY*>(this) ;   
  152.         trace("Component:\t\tReturn pointer to IY.") ;   
  153.     }  
  154.     else  
  155.     {  
  156.         *ppv = NULL ;  
  157.         return E_NOINTERFACE ;  
  158.     }  
  159.     reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;  
  160.     return S_OK ;  
  161. }  
  162.   
  163. ULONG __stdcall CA::AddRef()  
  164. {  
  165.     return InterlockedIncrement(&m_cRef) ;  
  166. }  
  167.   
  168. ULONG __stdcall CA::Release()   
  169. {  
  170.     if (InterlockedDecrement(&m_cRef) == 0)  
  171.     {  
  172.         delete this ;  
  173.         return 0 ;  
  174.     }  
  175.     return m_cRef ;  
  176. }  
  177.   
  178.   
  179. ///////////////////////////////////////////////////////////  
  180. //  
  181. // Class factory  
  182. //  
  183. class CFactory : public IClassFactory  
  184. {  
  185. public:  
  186.     // IUnknown  
  187.     virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ;           
  188.     virtual ULONG   __stdcall AddRef() ;  
  189.     virtual ULONG   __stdcall Release() ;  
  190.   
  191.     // Interface IClassFactory  
  192.     virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,  
  193.                                              const IID& iid,  
  194.                                              void** ppv) ;  
  195.     virtual HRESULT __stdcall LockServer(BOOL bLock) ;   
  196.   
  197.     // Constructor  
  198.     CFactory() : m_cRef(1) {}  
  199.   
  200.     // Destructor  
  201.     ~CFactory() { trace("Class factory:\t\tDestroy self.") ;}  
  202.   
  203. private:  
  204.     long m_cRef ;  
  205. } ;  
  206.   
  207. //  
  208. // Class factory IUnknown implementation  
  209. //  
  210. HRESULT __stdcall CFactory::QueryInterface(const IID& iid, void** ppv)  
  211. {      
  212.     if ((iid == IID_IUnknown) || (iid == IID_IClassFactory))  
  213.     {  
  214.         *ppv = static_cast<IClassFactory*>(this) ;   
  215.     }  
  216.     else  
  217.     {  
  218.         *ppv = NULL ;  
  219.         return E_NOINTERFACE ;  
  220.     }  
  221.     reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;  
  222.     return S_OK ;  
  223. }  
  224.   
  225. ULONG __stdcall CFactory::AddRef()  
  226. {  
  227.     return InterlockedIncrement(&m_cRef) ;  
  228. }  
  229.   
  230. ULONG __stdcall CFactory::Release()   
  231. {  
  232.     if (InterlockedDecrement(&m_cRef) == 0)  
  233.     {  
  234.         delete this ;  
  235.         return 0 ;  
  236.     }  
  237.     return m_cRef ;  
  238. }  
  239.   
  240. //  
  241. // IClassFactory implementation  
  242. //  
  243. HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,  
  244.                                            const IID& iid,  
  245.                                            void** ppv)   
  246. {  
  247.     trace("Class factory:\t\tCreate component.") ;  
  248.   
  249.     // Cannot aggregate.  
  250.     if (pUnknownOuter != NULL)  
  251.     {  
  252.         return CLASS_E_NOAGGREGATION ;  
  253.     }  
  254.   
  255.     /* Create an actual component even if the requested interface is not supported. 
  256.     But subsequent calling Release will delete itselt if QueryInterface failed.*/  
  257.     CA* pA = new CA ;  
  258.     if (pA == NULL)  
  259.     {  
  260.         return E_OUTOFMEMORY ;  
  261.     }  
  262.   
  263.     // Get the requested interface.  
  264.     HRESULT hr = pA->QueryInterface(iid, ppv) ;  
  265.   
  266.     // Release the IUnknown pointer.  
  267.     // (If QueryInterface failed, component will delete itself.)  
  268.     pA->Release() ;  
  269.     return hr ;  
  270. }  
  271.   
  272. // LockServer  
  273. HRESULT __stdcall CFactory::LockServer(BOOL bLock)   
  274. {  
  275.     if (bLock)  
  276.     {  
  277.         InterlockedIncrement(&g_cServerLocks) ;   
  278.     }  
  279.     else  
  280.     {  
  281.         InterlockedDecrement(&g_cServerLocks) ;  
  282.     }  
  283.     return S_OK ;  
  284. }  
  285.   
  286.   
  287. ///////////////////////////////////////////////////////////  
  288. //  
  289. // Exported functions  
  290. //  
  291.   
  292. //  
  293. // Can DLL unload now?  
  294. //  
  295. STDAPI DllCanUnloadNow()  
  296. {  
  297.     if ((g_cComponents == 0) && (g_cServerLocks == 0))  
  298.     {  
  299.         return S_OK ;  
  300.     }  
  301.     else  
  302.     {  
  303.         return S_FALSE ;  
  304.     }  
  305. }  
  306.   
  307. //  
  308. // Get class factory  
  309. //  
  310. STDAPI DllGetClassObject(const CLSID& clsid,  
  311.                          const IID& iid,  
  312.                          void** ppv)  
  313. {  
  314.     trace("DllGetClassObject:\tCreate class factory.") ;  
  315.   
  316.     // Can we create this component?  
  317.     if (clsid != CLSID_Component1)  
  318.     {  
  319.         return CLASS_E_CLASSNOTAVAILABLE ;  
  320.     }  
  321.   
  322.     // Create class factory.  
  323.     /* set CFactory::m_cRef's value to 1 in constructor.*/  
  324.     CFactory* pFactory = new CFactory ;    
  325.       
  326.     if (pFactory == NULL)  
  327.     {  
  328.         return E_OUTOFMEMORY ;  
  329.     }  
  330.   
  331.     // Get requested interface.  
  332.     HRESULT hr = pFactory->QueryInterface(iid, ppv);  
  333.     /*call CFactory::AddRef() if requested interface supported,or ppv's value will be set to null.*/  
  334.   
  335.     pFactory->Release() ;  
  336.     /*if pFactory->QueryInterface failed,pFactory->Release() will delete itself.*/  
  337.   
  338.     return hr ;  
  339. }  
  340.   
  341. //  
  342. // Server registration  
  343. //  
  344. STDAPI DllRegisterServer()  
  345. {  
  346.     return RegisterServer(g_hModule,   
  347.                           CLSID_Component1,  
  348.                           g_szFriendlyName,  
  349.                           g_szVerIndProgID,  
  350.                           g_szProgID) ;  
  351. }  
  352.   
  353.   
  354. //  
  355. // Server unregistration  
  356. //  
  357. STDAPI DllUnregisterServer()  
  358. {  
  359.     return UnregisterServer(CLSID_Component1,  
  360.                             g_szVerIndProgID,  
  361.                             g_szProgID) ;  
  362. }  
  363.   
  364. ///////////////////////////////////////////////////////////  
  365. //  
  366. // DLL module information  
  367. //  
  368. BOOL APIENTRY DllMain(HMODULE hModule,  
  369.                       DWORD dwReason,  
  370.                       void* lpReserved)  
  371. {  
  372.     if (dwReason == DLL_PROCESS_ATTACH)  
  373.     {  
  374.         g_hModule = hModule ;  
  375.     }  
  376.     return TRUE ;  
  377. }  
  378.   
  379. // in CMPNT.def  
  380. LIBRARY "Chapter7"  
  381. EXPORTS  
  382.     DllGetClassObject       PRIVATE  
  383.     DllCanUnloadNow         PRIVATE  
  384.     DllRegisterServer       PRIVATE  
  385.     DllUnregisterServer     PRIVATE  
  386. //  
  387. // GUIDs.cpp  
  388. //   - Defines all IIDs and CLSIDs for the client and the component.  
  389. //     The declaration of these GUIDs is in Iface.h  
  390. //  
  391. #include <objbase.h>  
  392.   
  393. // {32bb8320-b41b-11cf-a6bb-0080c7b2d682}  
  394. extern "C" const IID IID_IX =   
  395.     {0x32bb8320, 0xb41b, 0x11cf,  
  396.     {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;  
  397.   
  398. // {32bb8321-b41b-11cf-a6bb-0080c7b2d682}  
  399. extern "C" const IID IID_IY =   
  400.     {0x32bb8321, 0xb41b, 0x11cf,  
  401.     {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;  
  402.   
  403. // {32bb8322-b41b-11cf-a6bb-0080c7b2d682}  
  404. extern "C" const IID IID_IZ =   
  405.     {0x32bb8322, 0xb41b, 0x11cf,  
  406.     {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;  
  407.   
  408. // {0c092c21-882c-11cf-a6bb-0080c7b2d682}  
  409. extern "C" const CLSID CLSID_Component1 =  
  410.     {0x0c092c21, 0x882c, 0x11cf,  
  411.     {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;  
  412. //  
  413. // Registry.cpp  
  414. //  
  415.   
  416. #include <objbase.h>  
  417. #include <assert.h>  
  418.   
  419. #include "Registry.h"  
  420.   
  421. ////////////////////////////////////////////////////////  
  422. //  
  423. // Internal helper functions prototypes  
  424. //  
  425.   
  426. // Set the given key and its value.  
  427. BOOL setKeyAndValue(const char* pszPath,  
  428.                     const char* szSubkey,  
  429.                     const char* szValue) ;  
  430.   
  431. // Convert a CLSID into a char string.  
  432. void CLSIDtochar(const CLSID& clsid,   
  433.                  char* szCLSID,  
  434.                  int length) ;  
  435.   
  436. // Delete szKeyChild and all of its descendents.  
  437. LONG recursiveDeleteKey(HKEY hKeyParent, const char* szKeyChild) ;  
  438.   
  439. ////////////////////////////////////////////////////////  
  440. //  
  441. // Constants  
  442. //  
  443.   
  444. // Size of a CLSID as a string  
  445. const int CLSID_STRING_SIZE = 39 ;  
  446.   
  447. /////////////////////////////////////////////////////////  
  448. //  
  449. // Public function implementation  
  450. //  
  451.   
  452. //  
  453. // Register the component in the registry.  
  454. //  
  455. HRESULT RegisterServer(HMODULE hModule,            // DLL module handle  
  456.                        const CLSID& clsid,         // Class ID  
  457.                        const char* szFriendlyName, // Friendly Name  
  458.                        const char* szVerIndProgID, // Programmatic  
  459.                        const char* szProgID)       //   IDs  
  460. {  
  461.     // Get server location.  
  462.     char szModule[512] ;  
  463.     DWORD dwResult =  
  464.         ::GetModuleFileName(hModule,   
  465.                             szModule,  
  466.                             sizeof(szModule)/sizeof(char)) ;  
  467.     assert(dwResult != 0) ;  
  468.   
  469.     // Convert the CLSID into a char.  
  470.     char szCLSID[CLSID_STRING_SIZE] ;  
  471.     CLSIDtochar(clsid, szCLSID, sizeof(szCLSID)) ;  
  472.   
  473.     // Build the key CLSID\\{...}  
  474.     char szKey[64] ;  
  475.     strcpy(szKey, "CLSID\\") ;  
  476.     strcat(szKey, szCLSID) ;  
  477.     
  478.     // Add the CLSID to the registry.  
  479.     setKeyAndValue(szKey, NULL, szFriendlyName) ;  
  480.   
  481.     // Add the server filename subkey under the CLSID key.  
  482.     setKeyAndValue(szKey, "InprocServer32", szModule) ;  
  483.   
  484.     // Add the ProgID subkey under the CLSID key.  
  485.     setKeyAndValue(szKey, "ProgID", szProgID) ;  
  486.   
  487.     // Add the version-independent ProgID subkey under CLSID key.  
  488.     setKeyAndValue(szKey, "VersionIndependentProgID",  
  489.                    szVerIndProgID) ;  
  490.   
  491.     // Add the version-independent ProgID subkey under HKEY_CLASSES_ROOT.  
  492.     setKeyAndValue(szVerIndProgID, NULL, szFriendlyName) ;   
  493.     setKeyAndValue(szVerIndProgID, "CLSID", szCLSID) ;  
  494.     setKeyAndValue(szVerIndProgID, "CurVer", szProgID) ;  
  495.   
  496.     // Add the versioned ProgID subkey under HKEY_CLASSES_ROOT.  
  497.     setKeyAndValue(szProgID, NULL, szFriendlyName) ;   
  498.     setKeyAndValue(szProgID, "CLSID", szCLSID) ;  
  499.   
  500.     return S_OK ;  
  501. }  
  502.   
  503. //  
  504. // Remove the component from the registry.  
  505. //  
  506. LONG UnregisterServer(const CLSID& clsid,         // Class ID  
  507.                       const char* szVerIndProgID, // Programmatic  
  508.                       const char* szProgID)       //   IDs  
  509. {  
  510.     // Convert the CLSID into a char.  
  511.     char szCLSID[CLSID_STRING_SIZE] ;  
  512.     CLSIDtochar(clsid, szCLSID, sizeof(szCLSID)) ;  
  513.   
  514.     // Build the key CLSID\\{...}  
  515.     char szKey[64] ;  
  516.     strcpy(szKey, "CLSID\\") ;  
  517.     strcat(szKey, szCLSID) ;  
  518.   
  519.     // Delete the CLSID Key - CLSID\{...}  
  520.     LONG lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szKey) ;  
  521.     assert((lResult == ERROR_SUCCESS) ||  
  522.            (lResult == ERROR_FILE_NOT_FOUND)) ; // Subkey may not exist.  
  523.   
  524.     // Delete the version-independent ProgID Key.  
  525.     lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szVerIndProgID) ;  
  526.     assert((lResult == ERROR_SUCCESS) ||  
  527.            (lResult == ERROR_FILE_NOT_FOUND)) ; // Subkey may not exist.  
  528.   
  529.     // Delete the ProgID key.  
  530.     lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szProgID) ;  
  531.     assert((lResult == ERROR_SUCCESS) ||  
  532.            (lResult == ERROR_FILE_NOT_FOUND)) ; // Subkey may not exist.  
  533.   
  534.     return S_OK ;  
  535. }  
  536.   
  537. ///////////////////////////////////////////////////////////  
  538. //  
  539. // Internal helper functions  
  540. //  
  541.   
  542. // Convert a CLSID to a char string.  
  543. void CLSIDtochar(const CLSID& clsid,  
  544.                  char* szCLSID,  
  545.                  int length)  
  546. {  
  547.     assert(length >= CLSID_STRING_SIZE) ;  
  548.     // Get CLSID  
  549.     LPOLESTR wszCLSID = NULL ;  
  550.     HRESULT hr = StringFromCLSID(clsid, &wszCLSID) ;  
  551.     assert(SUCCEEDED(hr)) ;  
  552.   
  553.     // Covert from wide characters to non-wide.  
  554.     wcstombs(szCLSID, wszCLSID, length) ;  
  555.   
  556.     // Free memory.  
  557.     CoTaskMemFree(wszCLSID) ;  
  558. }  
  559.   
  560. //  
  561. // Delete a key and all of its descendents.  
  562. //  
  563. LONG recursiveDeleteKey(HKEY hKeyParent,           // Parent of key to delete  
  564.                         const char* lpszKeyChild)  // Key to delete  
  565. {  
  566.     // Open the child.  
  567.     HKEY hKeyChild ;  
  568.     LONG lRes = RegOpenKeyEx(hKeyParent, lpszKeyChild, 0,  
  569.                              KEY_ALL_ACCESS, &hKeyChild) ;  
  570.     if (lRes != ERROR_SUCCESS)  
  571.     {  
  572.         return lRes ;  
  573.     }  
  574.   
  575.     // Enumerate all of the decendents of this child.  
  576.     FILETIME time ;  
  577.     char szBuffer[256] ;  
  578.     DWORD dwSize = 256 ;  
  579.     while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL,  
  580.                         NULL, NULL, &time) == S_OK)  
  581.     {  
  582.         // Delete the decendents of this child.  
  583.         lRes = recursiveDeleteKey(hKeyChild, szBuffer) ;  
  584.         if (lRes != ERROR_SUCCESS)  
  585.         {  
  586.             // Cleanup before exiting.  
  587.             RegCloseKey(hKeyChild) ;  
  588.             return lRes;  
  589.         }  
  590.         dwSize = 256 ;  
  591.     }  
  592.   
  593.     // Close the child.  
  594.     RegCloseKey(hKeyChild) ;  
  595.   
  596.     // Delete this child.  
  597.     return RegDeleteKey(hKeyParent, lpszKeyChild) ;  
  598. }  
  599.   
  600. //  
  601. // Create a key and set its value.  
  602. //   - This helper function was borrowed and modifed from  
  603. //     Kraig Brockschmidt's book Inside OLE.  
  604. //  
  605. BOOL setKeyAndValue(const char* szKey,  
  606.                     const char* szSubkey,  
  607.                     const char* szValue)  
  608. {  
  609.     HKEY hKey;  
  610.     char szKeyBuf[1024] ;  
  611.   
  612.     // Copy keyname into buffer.  
  613.     strcpy(szKeyBuf, szKey) ;  
  614.   
  615.     // Add subkey name to buffer.  
  616.     if (szSubkey != NULL)  
  617.     {  
  618.         strcat(szKeyBuf, "\\") ;  
  619.         strcat(szKeyBuf, szSubkey ) ;  
  620.     }  
  621.   
  622.     // Create and open key and subkey.  
  623.     long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT ,  
  624.                                   szKeyBuf,   
  625.                                   0, NULL, REG_OPTION_NON_VOLATILE,  
  626.                                   KEY_ALL_ACCESS, NULL,   
  627.                                   &hKey, NULL) ;  
  628.     if (lResult != ERROR_SUCCESS)  
  629.     {  
  630.         return FALSE ;  
  631.     }  
  632.   
  633.     // Set the Value.  
  634.     if (szValue != NULL)  
  635.     {  
  636.         RegSetValueEx(hKey, NULL, 0, REG_SZ,   
  637.                       (BYTE *)szValue,   
  638.                       strlen(szValue)+1) ;  
  639.     }  
  640.   
  641.     RegCloseKey(hKey) ;  
  642.     return TRUE ;  
  643. }  
  644.   
  645.   
  646.   
  647. //in UseCmpnt vcproj  
  648.   
  649. //client.cpp  
  650. #include <iostream>  
  651. using std::cout;  
  652. using std::endl;  
  653. #include <objbase.h>  
  654.   
  655. #include "..\Chapter7\Iface.h"//包含了诸如IX、IY的声明  
  656. #include "..\Chapter7\GUIDS.cpp"//包含了诸如IID_IX、CLSID_Component1的定义  
  657.   
  658.   
  659. void OutPut(const char* msg);  
  660. {   
  661.     cout << "Client: \t\t" << msg << endl ;  
  662. }  
  663.   
  664. int main()  
  665. {  
  666.     CoInitialize(NULL) ;  
  667.   
  668.     OutPut("Call CoCreateInstance to create") ;  
  669.     OutPut("  component and get interface IX.") ;  
  670.     IX* pIX = NULL ;   
  671.     HRESULT hr = ::CoCreateInstance(CLSID_Component1,  
  672.                                     NULL,   
  673.                                     CLSCTX_INPROC_SERVER,  
  674.                                     IID_IX,   
  675.                                     (void**)&pIX) ;  
  676.     if (SUCCEEDED(hr))  
  677.     {  
  678.         OutPut("Succeeded getting IX.") ;  
  679.         pIX->Fx() ;          // Use interface IX.  
  680.   
  681.         OutPut("Ask for interface IY.") ;  
  682.         IY* pIY = NULL ;  
  683.         hr = pIX->QueryInterface(IID_IY, (void**)&pIY) ;  
  684.         if (SUCCEEDED(hr))  
  685.         {  
  686.             OutPut("Succeeded getting IY.") ;  
  687.             pIY->Fy() ;       // Use interface IY.  
  688.             pIY->Release() ;  
  689.             OutPut("Release IY interface.") ;  
  690.         }  
  691.         else  
  692.         {  
  693.             OutPut("Could not get interface IY.") ;  
  694.         }  
  695.   
  696.         OutPut("Ask for interface IZ.") ;  
  697.   
  698.         IZ* pIZ = NULL ;  
  699.         hr = pIX->QueryInterface(IID_IZ, (void**)&pIZ) ;  
  700.         if (SUCCEEDED(hr))  
  701.         {  
  702.             OutPut("Succeeded in getting interface IZ.") ;  
  703.             pIZ->Fz() ;  
  704.             pIZ->Release() ;  
  705.             OutPut("Release IZ interface.") ;  
  706.         }  
  707.         else  
  708.         {  
  709.             OutPut("Could not get interface IZ.") ;  
  710.         }  
  711.   
  712.         OutPut("Release IX interface.") ;  
  713.         pIX->Release() ;  
  714.     }  
  715.     else  
  716.     {  
  717.         cout << "Client: \t\tCould not create component. hr = "  
  718.             << hex << hr << endl ;      
  719.     }  
  720.   
  721.     // Uninitialize COM Library  
  722.     CoUninitialize();  
  723.   
  724.     return 0;  
  725. }  

                               

版权所有,翻版不究,欢迎山寨!          



0 0
原创粉丝点击