初学COM

因为要给同学用COM组件技术写一个简单的demo程序。然而两天前还对COM是一片空白,这两天在网上到处找资料来看,现在把自己这两天来学习的结果记录一下做为备忘。

首先,COM的基础是C++语言,至少自己这两天学习COM的感觉如此。在《COM本质论》中也说,COM是更好的C++。而贯穿于这些技术中最最重要的,则是C++中的虚函数这一类的技术。但是假如是在学校的课堂上,每个人捧着一本C++教材,老师在上面讲,无非就是有一个类叫做A,它包含一个虚函数数叫做f,有两个类B和C都从A继承,在B和C中都分别重写了f函数,现在有一个函数h,它接受一个类型为A的引用或指针,在h内部调用了这个f函数,那么在调用h的时候,如果传给它的是一个B,则它会调用B的实现,如果传给它的是一个C,则它会调用C的实现,这样,统一的代码,多态的实现。再好一点,给A,B,C起一个具体的名字,比如A叫做鸟,B叫作喜鹊,C叫做燕子的。但也仅此而已。然而明白了这些,并不能够就此而明白了MFC,明白了设计模式。。。在软件开发的世界,并不是简单的ABC也不是简单的数学抽象,它需要从现实世界中挖掘出最普遍的行为规律。

关于COM的技术文章,网上有很多资料。在CSDN的blog里搜索一下,会找到大量详细的讲解。VC知识库里不但有大量的技术精华文章,还有与之配套的示例源代码可供下载。MSDN中也有专门讲解COM技术的专著,打开MSDN,选择“目录”标签,在下面的specification子项下有一个component object model specification 0.9,这下面就是。

在COM程序中会看到一些修饰函数声明的宏,像STDAPI, STDMETHOD, PURE等这些宏,看它们的源代码是最好的方式,在objbase.h头文件中,有所有这些宏的定义,如下:

  1. #if !defined( _BASETYPS_H_ )
  2. #define _BASETYPS_H_
  3. // Common macros gleamed from COMPOBJ.H
  4. #ifdef __cplusplus
  5.     #define EXTERN_C    extern "C"
  6. #else
  7.     #define EXTERN_C    extern
  8. #endif
  9. #ifdef _WIN32
  10. // Win32 doesn't support __export
  11. #define STDMETHODCALLTYPE       __stdcall
  12. #define STDMETHODVCALLTYPE      __cdecl
  13. #define STDAPICALLTYPE          __stdcall
  14. #define STDAPIVCALLTYPE         __cdecl
  15. #else
  16. #define STDMETHODCALLTYPE       __export __stdcall
  17. #define STDMETHODVCALLTYPE      __export __cdecl
  18. #define STDAPICALLTYPE          __export __stdcall
  19. #define STDAPIVCALLTYPE         __export __cdecl
  20. #endif
  21. #define STDAPI                  EXTERN_C HRESULT STDAPICALLTYPE
  22. #define STDAPI_(type)           EXTERN_C type STDAPICALLTYPE
  23. #define STDMETHODIMP            HRESULT STDMETHODCALLTYPE
  24. #define STDMETHODIMP_(type)     type STDMETHODCALLTYPE
  25. // The 'V' versions allow Variable Argument lists.
  26. #define STDAPIV                 EXTERN_C HRESULT STDAPIVCALLTYPE
  27. #define STDAPIV_(type)          EXTERN_C type STDAPIVCALLTYPE
  28. #define STDMETHODIMPV           HRESULT STDMETHODVCALLTYPE
  29. #define STDMETHODIMPV_(type)    type STDMETHODVCALLTYPE
  30. #if defined(__cplusplus) && !defined(CINTERFACE)
  31. //#define interface               struct FAR
  32. #define interface struct
  33. #define STDMETHOD(method)       virtual HRESULT STDMETHODCALLTYPE method
  34. #define STDMETHOD_(type,method) virtual type STDMETHODCALLTYPE method
  35. #define PURE                    = 0
  36. #define THIS_
  37. #define THIS                    void
  38. #define DECLARE_INTERFACE(iface)    interface iface
  39. #define DECLARE_INTERFACE_(iface, baseiface)    interface iface : public baseiface
  40. #else
  41. #define interface               struct
  42. #define STDMETHOD(method)       HRESULT (STDMETHODCALLTYPE * method)
  43. #define STDMETHOD_(type,method) type (STDMETHODCALLTYPE * method)
  44. #define PURE
  45. #define THIS_                   INTERFACE FAR* This,
  46. #define THIS                    INTERFACE FAR* This
  47. #ifdef CONST_VTABLE
  48. #define DECLARE_INTERFACE(iface)    typedef interface iface { /
  49.                                     const struct iface##Vtbl FAR* lpVtbl; /
  50.                                 } iface; /
  51.                                 typedef const struct iface##Vtbl iface##Vtbl; /
  52.                                 const struct iface##Vtbl
  53. #else
  54. #define DECLARE_INTERFACE(iface)    typedef interface iface { /
  55.                                     struct iface##Vtbl FAR* lpVtbl; /
  56.                                 } iface; /
  57.                                 typedef struct iface##Vtbl iface##Vtbl; /
  58.                                 struct iface##Vtbl
  59. #endif
  60. #define DECLARE_INTERFACE_(iface, baseiface)    DECLARE_INTERFACE(iface)
  61. #endif
  62. #ifndef INITGUID
  63. #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) /
  64.     EXTERN_C const GUID FAR name
  65. #else
  66. #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) /
  67.         EXTERN_C const GUID name /
  68.                 = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }
  69. #endif // INITGUID
  70. #define DEFINE_OLEGUID(name, l, w1, w2) /
  71.     DEFINE_GUID(name, l, w1, w2, 0xC0,0,0,0,0,0,0,0x46)
  72. #ifndef _ERROR_STATUS_T_DEFINED
  73. typedef unsigned long error_status_t;
  74. #define _ERROR_STATUS_T_DEFINED
  75. #endif
  76. #ifndef _WCHAR_T_DEFINED
  77. typedef unsigned short wchar_t;
  78. #define _WCHAR_T_DEFINED
  79. #endif
  80. #ifndef GUID_DEFINED
  81. #define GUID_DEFINED
  82. typedef struct _GUID
  83. {
  84.     unsigned long Data1;
  85.     unsigned short Data2;
  86.     unsigned short Data3;
  87.     unsigned char Data4[8];
  88. } GUID;
  89. #endif /* GUID_DEFINED */
  90. #endif

VC知识库中一篇叫做《COM入门初探:一》的文章写的非常好,并在其中举了个例子,这个例子非常容易理解。目前自己对简单的COM的理解就是,它就是一个很好的工厂方法。在DLL中,定义一个或多个interface,它们从IUnknow接口中继承,这些interface可以看成是工厂方法的UML图中的Abstract Product。然后写一个或多个实现类,来实现这些interface,这些实现类可以看成是工厂方法中的Concret Product,然后再写一个创建器(可选但必要),这个创建器就是一个继承自IClassFactory的类,它实现了IClassFactory中的CreateInstance方法和LockServer方法,这个类就是工厂方法中的Concreat Factory。最后,从DLL中导出一个函数,叫做DllGetClassObject,当用户使用这个COM组件时,DllGetClassObject便会使用那个继承自IClassFactory的工厂来根据用户指定的接口ID创建一个实现类的实例。这就是完整的非常标准的设计模式中的简单工厂方法。

 

com client使用这个DLL的方法一般是通过CoCreateInstance或者是通过CoGetClassObject,这两个函数在MSDN中都有详细的解释,以及关于它们之间的区别和各自的适用场合的。其中,CoCreateInstance就是封装了以下的实现:

  1. CoGetClassObject(rclsid, dwClsContext, NULL, IID_IClassFactory, &pCF); 
  2. hresult = pCF->CreateInstance(pUnkOuter, riid, ppvObj) 
  3. pCF->Release(); 

 

在使用VC6写一些简单的demo的时候,一般是创建一个win32控制台程序,把支持MFC这一项选上。写一个com server的demo,是创建一个win32 dynamic library的project。如果使用了IActiveDesktop接口,则在编译时会出现:IActiveDesktop undeclared identifier的错误。这是由于头文件的包含造成的,在#include <afxdisp.h>之前包含<wininet.h>头文件,并且把它们放在<afx.h>之后,下同是一个能正常运行的project的stdafx.h文件:

  1. #include <afx.h>
  2. #include <afxwin.h>         // MFC core and standard components
  3. #include <wininet.h>
  4. #include <afxdisp.h>
  5. #include <afxext.h>         // MFC extensions
  6. #include <afxdtctl.h>       // MFC support for Internet Explorer 4 Common Controls
  7. #ifndef _AFX_NO_AFXCMN_SUPPORT
  8. #include <afxcmn.h>         // MFC support for Windows Common Controls
  9. #endif // _AFX_NO_AFXCMN_SUPPORT

另外,在Microsot visual studio/common/tools目录下有guidgen.exe和uuidgen.exe两个程序,可以自动生成guid或者一个uuid。

 

你可能感兴趣的:(设计模式,mfc,dll,library,UML,interface)