COM组件笔记(五)

一、COM组件的注册

  1. 我们目前用ATL制作出来的简单对象是*.dll的形式,我们在之前的例子中能调用这个dll,是因为我们的VisualStudio在编译生成这个dll时,对它进行了注册。
  2. 如何手动注册COM组件:

      1)打开控制台窗口(一般情况下要以管理员身份运行,因为注册COM组件的程序一般需要管理员权限):

          

 

 

 

 

                         

 

                      2)查看注册的动态库信息,需要加载注册表:

 

          

 

                      查找对应的GUID信息

 

       

   3.对COM组件进行注册的意义:

    我们刚才从注册表中看到了注册信息记录了组件的CLSID,组件的路径,组件的PropID等。

    而我们的COM组件是跨应用的,网页,MFC,C#的WinForm,VB需要识别并创建我们的组件。最终需要得到我们组件的路径。而路径是可能改变的,比如用户安装程序时选择不同目录,CLSID跟PropID是不变 的,我们采用CLSID或PropID去创建组件,不管COM组件的ll在哪个位置,都跟我们的创建代码无关。

          从vista开始,注册需要权限了,我们可以做一个不需要注册的COM。这个内容放到以后高级编程中来讲。

 

 二、智能指针的使用

  • C++在调用COM接口指针时是很危险的,因为使用过程需要每一个使用都严格并且正确地调用AddRef()与Release()方法。一旦出现问题,就会造成对象不能被正常释放或者对象被重复删除。
  • 所以C++程序员使用COM接口时,得小心翼翼的。有没有办法改变这种现状,让我们的编程过程更简单呢?答案是有的,那就是智能指针。
  • CComPtr是智能指针,是ATL提供的一个模板类,能封装COM接口的AddRef()与Release()方法。
  • CComPtr声明出来的变量是一个对象,这个对象封装了COM接口指针,这个对象的使用访问跟COM接口的使用方法几乎一样。

  案例:

复制代码
 1 // 案例在MFC下进行,函数写在一个按钮中
 2 void CMFCTestSectionDemo1Dlg::OnBnClickedButton1()
 3 {
 4     // TODO: 在此添加控件通知处理程序代码
 5 #pragma region 不使用智能指针
 6     HRESULT hr = E_FAIL;
 7     hr = CoInitialize(NULL);    // 使用com组件之前要添加这一句,用COM组件的入口点
 8 
 9     if (SUCCEEDED(hr)) {
10         IHelloSimpleObject* pIHelloSimpleObject = NULL;
11         hr = CoCreateInstance(CLSID_HelloSimpleObject, NULL,
12             CLSCTX_INPROC_SERVER, IID_IHelloSimpleObject, (void**)&pIHelloSimpleObject);
13         if (SUCCEEDED(hr)) {
14 
15             // 加法方法测试
16             LONG lSum = 0;
17             hr = pIHelloSimpleObject->SumLong(9, 99, &lSum);
18 
19             // 读描述属性
20             BSTR bstrDescriptionA = SysAllocString(L"");
21             hr = pIHelloSimpleObject->get_Description(&bstrDescriptionA);
22             SysFreeString(bstrDescriptionA);
23             bstrDescriptionA = NULL;
24 
25             // 写属性描述
26             BSTR bstrDescriptionB = SysAllocString(L"我运行在MFC中,我是新的描述属性!");
27             hr = pIHelloSimpleObject->put_Description(bstrDescriptionB);
28             SysFreeString(bstrDescriptionB);
29             bstrDescriptionB = NULL;
30 
31             // 读描述属性
32             BSTR bstrDescriptionC = SysAllocString(L"");
33             hr = pIHelloSimpleObject->get_Description(&bstrDescriptionC);
34             SysFreeString(bstrDescriptionC);
35             bstrDescriptionA = NULL;
36         }
37         pIHelloSimpleObject->Release();        // 不适用这个函数,引用计数减1
38     }
39 
40     CoUninitialize();        //不使用com组件对象时添加这一句,用COM组件的出口点
41 #pragma endregion
42 
43 #pragma region 使用智能指针
44     HRESULT hr = E_FAIL;
45     hr = CoInitialize(NULL);
46 
47     if (SUCCEEDED(hr)) {
48         CComPtr<IHelloSimpleObject> spHelloSimpleObject;
49         hr = spHelloSimpleObject.CoCreateInstance(CLSID_HelloSimpleObject);
50         /*
51         * 对比以下
52           hr = CoCreateInstance(CLSID_HelloSimpleObject, NULL,
53             CLSCTX_INPROC_SERVER, IID_IHelloSimpleObject, (void**)&pIHelloSimpleObject);
54         */
55         if (SUCCEEDED(hr)) {
56             // 加法方法测试
57             LONG lSum = 0;
58             hr = spHelloSimpleObject->SumLong(9, 99, &lSum);
59 
60             // 读描述属性
61             BSTR bstrDescriptionA = SysAllocString(L"");
62             hr = spHelloSimpleObject->get_Description(&bstrDescriptionA);
63             SysFreeString(bstrDescriptionA);
64             bstrDescriptionA = NULL;
65 
66             // 写描述属性
67             BSTR bstrDescriptionB = SysAllocString(L"我运行在MFC中,我是新的描述属性!");
68             hr = spHelloSimpleObject->put_Description(bstrDescriptionB);
69             SysFreeString(bstrDescriptionB);
70             bstrDescriptionB = NULL;
71 
72             // 读描述属性
73             BSTR bstrDescriptionC = SysAllocString(L"");
74             hr = spHelloSimpleObject->get_Description(&bstrDescriptionC);
75             SysFreeString(bstrDescriptionC);
76             bstrDescriptionC = NULL;
77         }
78 
79         // spHelloSimpleObject->Release();  不需要调用,也不能调用
80     }
81 
82     CoUninitialize();
83 #pragma endregion
84 
85 }
复制代码

 

 

三、智能指针与COM接口指针的比较

  • CComPtr<IHelloSimpleObject> spHelloSimpleObject 创建了一个智能指针,其它是一个类对象,对象内部有一个IHelloSimpleObjectt*的指针变量,并且被初始化为NULL。
  • IHelloSimpleObject *pIHelloSimpleObject,一个原始的COM接口指针。
  • 二者对->的操作的用法与意义一样。因为对智能指针的->操作会转换为对 _NoAddRefReleaseOnCComPtr<IHelloSimpleObjectSub>* 变量的->操作。 _NoAddRefReleaseOnCComPtr<IHelloSimpleObjectSub>是 IHelloSimpleObjectSub的子类。
  • 不过智能指针不能执行->AddRef()与->Release()。因为_NoAddRefReleaseOnCComPtr<T>类把AddReft()与Release()方法的访问权限设置为private。如果智能指针执行->AddRef()与->Release(),编译时,直接报错。
  • 智能指针禁用->AddRef()与->Release()的原因是智能指针封装了COM接口指针的AddRef与Release操作,会智能判断何时对象内部会调用COM接口的AddRef,何时调用COM接口的Release。
  • 之前对COM接口指针的赋值是需要做AddRef操作来添加引用计数,如果采用智能指针,它会智自地执行AddRef我们不必为此担心。
  • 之前不再使用COM接口指针时,需要做Release操作来减少引用计数,如果采用智能指针,它会在对象销毁时(析构时),做COM接口指针的Release操作。
  • 智能指针的变量是一个对象。
    • 如果是局部变量,将在这个局部变量生命期结束时行智能指针的析构函数;
    • 如果是成员变量,将在成员所在的类对象销毁时,执行智能指针的析构函数;
    • 如果是静态变量,将在程序结束时,执行智能指针的析构函数。

四、智能指针的注意点

  • 如果要释放一个智能指针直接给它赋NULL值就可以了。这样内部的COM接口指针也会执行Release操作,来减少引用计数;
  • 当对智能指针取地址时(&运算符操作),要确保智能指针为NULL,因为&是要返回内部的COM接口指针的,如果不为NULL,则旧的COM接口指针将没有执行Release而直接赋值了一个旧的COM接口指针;
  • 不过大家可以放心,因为如果这时智能指针不为NULL时,智能指的代码会通过assert断言报错,从而提醒程序员进行相应代码的更改。

 

 

posted @   炫迈吃到爽  阅读(584)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示