COM学习笔记1_COM初步探索

来源:互联网 发布:淘宝购物返利那个高 编辑:程序博客网 时间:2024/04/30 07:32
COM组件的两个重要需求:
1。 动态链接
2。 隐藏实现细节

COM初步探索

一个典型C++客户和组件的例子
[cpp] view plaincopy
  1. // 组件模块  
  2. interface IX  
  3. {  
  4.     virtual void __stdcall Fx1() = 0 ;  
  5.     virtual void __stdcall Fx2() = 0 ;  
  6. } ;  
  7. interface IY  
  8. {  
  9.     virtual void __stdcall Fy1() = 0 ;  
  10.     virtual void __stdcall Fy2() = 0 ;  
  11. } ;  
  12. // Interface implementation  
  13. class CA : public IX,   
  14.            public IY  
  15. {  
  16. //......  
  17. } ;  
  18. // 客户模块  
  19. int main()  
  20. {  
  21.     CA* pA = new CA ;  
  22.     pA->Fx1() ;  
  23.     pA->Fx2() ;  
  24.       
  25.     pA->Fy1() ;  
  26.     pA->Fy2() ;  
  27.       
  28.     delete pA ;  
  29. }  



在COM中,推荐使用接口的指针来使用组件,上面客户端可以改成如下工作:
[cpp] view plaincopy
  1. // 客户模块  
  2. int main()  
  3. {  
  4.     CA* pA = new CA ;  
  5.     // Get an IX pointer.  
  6.     IX* pIX = pA ;  
  7.     pIX->Fx1() ;  
  8.     pIX->Fx2() ;  
  9.     // Get an IY pointer.  
  10.     IY* pIY = pA ;  
  11.     pIY->Fy1() ;  
  12.     pIY->Fy2() ;  
  13.     delete pA ;  
  14. }  



接下来问题是:
1。 CA* pA = new CA ;
这里暴露太多细节,最起码客户需要类CA的头文件声明,这里把类CA的内部细节(私有成员)都暴露了,
而且当CA的实现细节改动,客户端肯定需要重新编译代码。
另外COM组件可能不在客户进程中,甚至在远程机器上,这样就不可能简单new出组件实例。

2。delete pA ;
这里需要显示释放组件。
但pIX和pIY也指向pA的对象,delete pA后如果再使用pIX等就会发生错误。
容易造成代码维护困难。

解决方案是所有接口派生自IUnknown。
IUnknown提供QueryInterface,AddRef和Release接口。
另外提供函数CreateInstance。

对于上面问题1,通过CreateInstance创建组件,并返回IUnknown接口指针,
然后通过QueryInterface再获取各种接口的指针。

对于上面问题2,每次获取组件指针时(自动)调用AddRef,该指针不再使用时调用Release。
组件内部维护引用计数,当计数为0时自动释放自己。这样就不需要手动new和delete了。

现在组件和客户代码如下:
[cpp] view plaincopy
  1. // 组件代码  
  2. interface IX : IUnknown  
  3. {  
  4.     virtual void __stdcall Fx() = 0 ;  
  5. } ;  
  6. interface IY : IUnknown  
  7. {  
  8.     virtual void __stdcall Fy() = 0 ;  
  9. } ;  
  10. // Forward references for GUIDs  
  11. extern const IID IID_IX ;  
  12. extern const IID IID_IY ;  
  13. class CA : public IX,  
  14.            public IY  
  15. {  
  16.     virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ;            
  17.     virtual ULONG __stdcall AddRef() { return 0 ;}  
  18.     virtual ULONG __stdcall Release() { return 0 ;}  
  19.     virtual void __stdcall Fx() { cout << "Fx" << endl ;}  
  20.     virtual void __stdcall Fy() { cout << "Fy" << endl ;}  
  21. } ;  
  22. IUnknown* CreateInstance()  
  23. {  
  24.     IUnknown* pI = static_cast<IX*>(new CA) ;  
  25.     pI->AddRef() ;  
  26.     return pI ;  
  27. }  
  28. // 客户代码  
  29. int main()  
  30. {  
  31.     IUnknown* pIUnknown = CreateInstance() ;  
  32.     IX* pIX = NULL ;   
  33.     if (SUCCEEDED (pIUnknown->QueryInterface(IID_IX, (void**)&pIX)))  
  34.     {  
  35.         pIX->Fx() ;          // Use interface IX.  
  36.     }  
  37.     IY* pIY = NULL ;  
  38.     if (SUCCEEDED (pIUnknown->QueryInterface(IID_IY, (void**)&pIY)))  
  39.     {  
  40.         pIY->Fy() ;          // Use interface IY.  
  41.         pIY->Release() ;  
  42.     }  
  43.     IY* pIYfromIX = NULL ;  
  44.     if (SUCCEEDED (pIX->QueryInterface(IID_IY, (void**)&pIYfromIX)))  
  45.     {     
  46.         pIYfromIX->Fy() ;  
  47.         pIYfromIX->Release() ;  
  48.     }  
  49.     pIX->Release() ;  
  50.     pIUnknown->Release() ;  
  51. }  
0 0