COM组件笔记(一)

COM是什么:

COM是微软组件对象模型的简称。由于COM具有二进制代码共享的特性,所以它具备了高可开发性、高度可维护性和高度的可移植性(跨开发语言),以至于在Windows上面的诸多应用软件采用了COM来做整体的架构。比如微软的DirectX等。COM虽然流行于2000-2004年之间,由于它的普及面之广,应用软件种类之繁多再加上Windows对其默认支持很好,开发出来的软件无需依赖其他的开发包,所以被很多软件公司采用至今。


COM组件的三个优点。

①采用COM组件编写软件,可以很方便的进行模块划分,各个模块的独立性高,耦合度低,从而可以更方便的进行开发任务的分工。

②COM组件可以让程序员更方便的维护、升级软件,旧模块能够直接被新模块代替,而不影响软件的使用。

③COM组件具有跨平台移植性,如C++的MFC平台移植到C#的WinForm平台。(第一份工作中就是用到了C++开发的COM接口递交给C#调用)COM组件同时可以跨应用,所以C++调用可以被C#调用。

④ COM组件适用于Windows平台,而Linux不适用于COM组件

 

以下是基于组件的小Demo1,可以快速的了解组件是什么东西:

复制代码
 1 #define  _CRT_SECURE_NO_WARNINGS
 2 #include <iostream>
 3 using namespace std;
 4 
 5 // 预定义interface
 6 #define interface struct
 7 
 8 // 接口 IX
 9 interface IX {
10     virtual void Fx1() = 0;
11     virtual void Fx2() = 0;
12 };
13 
14 // 接口 IY
15 interface IY {
16     virtual void Fy1() = 0;
17     virtual void Fy2() = 0;
18 };
19 
20 class CA : public IX, public IY
21 {
22 public:
23     virtual void Fx1() {
24         cout << "Fx1" << endl;
25     }
26 
27     virtual void Fx2() {
28         cout << "Fx2" << endl;
29     }
30 
31     virtual void Fy1() {
32         cout << "Fy1" << endl;
33     }
34 
35     virtual void Fy2() {
36         cout << "Fy2" << endl;
37     }
38 
39 };
40 
41 
42 
43 int main(int argc, char* argv[])
44 {
45     // 创建组件的实例
46     CA* pA = new CA();
47 
48     // 获取IX的接口
49     IX* pIX = pA;
50 
51     // 使用IX的接口
52     pIX->Fx1();
53     pIX->Fx2();
54 
55     // 获取IY的接口
56     IY* pIY = pA;
57     pIY->Fy1();
58     pIY->Fy2();
59 
60     getchar();
61     return 0;
62 }
View Code
复制代码

 

COM组件与COM接口函数原型:

1 interface IUnknown
2 {
3        virtual HRESULT QueryInterface(const IID& iid, void **pv) = 0;
4        virtual ULONG AddRef() = 0;
5        virtual ULONG Release() = 0;            
6 }

① QueryInterface函数,可以通过它查询某个组件是否支持某个特定的接口。例如Demo1中,我们就可以通过这个函数查询CA这个组件类是否支持FX1这种接口,或者我们需要调用类似于FZ1这种函数,也可以查询是否有FZ1这种接口。如果支持,该函数会返回指向这个函数的指针,如果不支持,这个函数会返回null指针。  

  返回值 HRESULT :表示该函数是否正确执行,并不代表找不到这个接口。以下是HRESULT的返回值类型。

            

  const IID& iid:interface ID 代表接口标识符。每个接口都可以设置其相应的接口标识符,本质上IID 是一个 GUID,以下是GUID的结构内部变量:

复制代码
1 typedef struct _GUID
2 {
3       DWORD Data1;       // 随机数
4       WORD Data2;         // 和时间相关      
5       WORD Data3;         // 和时间相关
6       BYTE   Data4[8];     // 和网卡MAC相关
7 }GUID;
// GUID 示例
// 8位 - 4位 - 4位 - 4位 - 12位
{234564DF-58SW-WE8F-QW8D-AASAD8769851}

// 另一种展现形式
stactic const GUID guid = { aswertfsz, oaser452, 458sdwq,{58sa, 58s, oxas, oxe9, kjf7, ox2, ox5em oxb9}}

 

复制代码

  GUID一共16个字节,128位,VS可以通过以下方式创建GUID, GUID是唯一的。

                 

  void **pv:返回函数结果的参数变量。

以下是基于GUID的Demo2:

复制代码
  1 #define  _CRT_SECURE_NO_WARNINGS
  2 #include <iostream>
  3 #include <Unknwn.h>
  4 using namespace std;
  5 
  6 // {4E22FE4C-FC61-4616-B13E-7AC19186000D}
  7 static const IID IID_IX =
  8 { 0x4e22fe4c, 0xfc61, 0x4616, { 0xb1, 0x3e, 0x7a, 0xc1, 0x91, 0x86, 0x0, 0xd } };
  9 
 10 // {26C7D646-9C25-4C88-AAC5-215FC0569CD5}
 11 static const IID IID_IY =
 12 { 0x26c7d646, 0x9c25, 0x4c88, { 0xaa, 0xc5, 0x21, 0x5f, 0xc0, 0x56, 0x9c, 0xd5 } };
 13 
 14 
 15 // 接口IX
 16 interface IX : public IUnknown
 17 {
 18     virtual void Fx1() = 0;
 19     virtual void Fx2() = 0;
 20 };
 21 
 22 // 接口IY
 23 interface IY : public IUnknown
 24 {
 25     virtual void Fy1() = 0;
 26     virtual void Fy2() = 0;
 27 };
 28 
 29 // 组件CA
 30 class CA : public IX, public IY {
 31 public:
 32     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppv) {
 33         if (iid == IID_IUnknown) {
 34             // 如果未知的话,我们一般来说返回先继承的那个接口
 35             *ppv = static_cast<IX*>(this);
 36         }
 37         else if (iid == IID_IX) {
 38             // 返回IX接口
 39             *ppv = static_cast<IX*>(this);
 40         }
 41         else if (iid == IID_IY) {
 42             // 返回IY接口
 43             *ppv = static_cast<IY*>(this);
 44         }
 45         else {
 46             // 查询不到IID,*ppv返回NULL
 47             *ppv = NULL;
 48             return E_NOINTERFACE; // 函数返回值返回E_NOINTERFACE,表示调用的组件不支持iid的接口
 49         }
 50 
 51         AddRef();    //之后会提到
 52 
 53         return S_OK;    // 代表函数成功执行
 54     }
 55     virtual ULONG STDMETHODCALLTYPE AddRef() {
 56         // 暂时不实现
 57         return 0;
 58     };
 59     virtual ULONG STDMETHODCALLTYPE Release() {
 60         // 暂时不实现
 61         return 0;
 62     };
 63 
 64 public:
 65     virtual void Fx1() {
 66         cout << "Fx1" << endl;
 67     }
 68 
 69     virtual void Fx2() {
 70         cout << "Fx2" << endl;
 71     }
 72 
 73     virtual void Fy1() {
 74         cout << "Fy1" << endl;
 75     }
 76 
 77     virtual void Fy2() {
 78         cout << "Fy2" << endl;
 79     }
 80 
 81 // 数据
 82 public:
 83     long m_IAA;
 84     long m_IAB;
 85     long m_IAC;
 86 
 87 };
 88 
 89 int main(int argc, char* argv[])
 90 {
 91     HRESULT hr;
 92 
 93     // 创建组件
 94     CA* pA = new CA();
 95 
 96     // 从组件查询IUnknown接口
 97     IUnknown* pIUnknown = NULL;
 98     hr = pA->QueryInterface(IID_IUnknown, (void**)&pIUnknown);
 99     if (SUCCEEDED(hr)) {    // 对于HRESULT返回值的判断,一般采用SUCCEEDED
100         // 从IUnknown查询IX接口
101         IX* pIX = NULL;
102         hr = pIUnknown->QueryInterface(IID_IX, (void**)&pIX);
103         if (SUCCEEDED(hr)) {
104             // 调用IX接口方法
105             pIX->Fx1();
106             pIX->Fx2();
107         }
108 
109         IY* pIY = NULL;
110         hr = pIUnknown->QueryInterface(IID_IY, (void**)&pIY);
111         if (SUCCEEDED(hr)) {
112             pIY->Fy1();
113             pIY->Fy2();
114         }
115 
116         if ((void*)pIX != (void*)pIY) {
117             cout << "pIX != pIY" << endl;
118         }
119 
120         if ((void*)pIUnknown != (void*)pIY) {
121             cout << "pIUnknown != pIY" << endl;
122         }
123 
124         if ((void*)pIUnknown != (void*)pIX) {
125             cout << "pIUnknown != pIX" << endl;
126         }
127 
128         // 从IX查询IY
129         IY* pIY2 = NULL;
130         hr = pIX->QueryInterface(IID_IY, (void**)&pIY2);
131         if (SUCCEEDED(hr)) {
132             pIY2->Fy1();
133             pIY2->Fy2();
134         }
135 
136         /*
137         * 从IX也可以查询到IUnknown
138         * 从IY也可以查询到IX
139         * 从IY也可以呃查询到IUnknowN
140         * 从CA也可以查询到IX
141         * 从CA也可以查询到IY
142         * 总结:
143         *    只要是CA所继承的接口,从CA的组件里都可以查询到
144         *    只要是CA所继承的接口,从CA所继承的其他接口里也都可以查询到
145         */
146     }
147 
148     delete pA;
149 
150     getchar();
151     return 0;
152 }
View Code
复制代码

 取自于B站视频 https://www.bilibili.com/video/BV1R7411x7U9?p=17&share_source=copy_web 《COM实用入门教程》第一讲, 感谢,收获颇丰。

posted @   炫迈吃到爽  阅读(429)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示