在VC中使用COM组件的几种方法

随着Internet和Intranet应用的飞速发展,COM(Component Object Model,组件对象模型)以其巨大的潜力渗透到软件学科的各个领域。在Windows

作平台下,众多以COM形式提供的组件模块,如DirectX多媒体软件包、OLE DB/ ADO 组件系统等,极大地丰富了 的功能。由于COM机制允许任意两组件之间相互通信而不必关心是在何种计算机上的何种操作系统下运行,也不用关心组件是使用何种语言编制的,这使COM技术拥有了强大的生命力。尤其是Windows 2000同COM的下一代产品COM+的结合更加紧密,将使COM/COM+技术得到更广泛的应用。本文介绍在VC++ 6.0下编写COM客户程序的三种方法,虽然每一种方法都可以达到使用代码组件的目的,但详细了解并掌握所有方法会为根据具体情况选择适当方法提供更大的余地。

为叙述清楚,本文所用的程序框架均为对话框模式的MFC EXE工程。在编程前,首先要确定待操作的代码组件是否已经在系统中注册。如果代码组件没有注册,可以通过Windows\System目录下的regsvr32. exe程序对其进行注册。

COM库函数

利用COM库函数使用代码组件的方法是本文介绍的三种方法中实现起来最麻烦和困难的方法。它要求开发人员必须具有对COM原理的深入理解。该方法实现步骤如下:

1. 首先添加COM初始和终止代码。在应用程序类的初始化实例函数InitInstance()中添加如下代码:

CoInitialize(NULL);

……

CoUnInitialize();

上述语句运行在MFC框架/非MFC框架中,但由于本文程序使用MFC框架,所以也可以利用AfxOleInit()函数对其进行初始化。

2. 然后用#include 语句包含对组件头文件的引用并创建组件对象。在头文件中包含了接口的C++定义以及说明接口ID IID和类ID CLSID的符号化常量。创建工作在初始化对话框函数中进行:

IAccount pAccount=NULL;

……

CoCreateInstance(CLSID_Account,

NULL,

CLSCTX_INPROC_SERVER,

IID_Iaccount,

reinterpret_cast (&pAccount));

3. 最后释放组件对象。该工作应在程序退出之前完成,比如在消息WM_CLOSE的响应函数中进行:

if(pAccount!=NULL)

pAccount->Realease();

对该代码组件中的其他功能函数的调用,可以通过组件对象的接口指针pAccount来进行:

……

BSTR bstrResult;

PAccount-> Post(100,bstrResult);

SysFreeString(bstrResult);

……

由于COM支持类在comdef. h中定义,所以还要包含对该头文件的引用,才可以使程序正常运行。

类向导

通过类向导可以直接阅读组件的类型库,并产生包装类型库中每个接口的类,通过这些类的成员函数可以访问组件接口的方法和属性,与使用ActiveX控件的方法有些类似。

首先添加对COM组件进行初始化的代码。我们可以通过类向导的From a Type Library加入组件的.tlb类型库文件,并从中引入其接口类。在本例中引入的类型库文件中只包含一个从ColeDispatchDriver派生的组件包装类IAccount。通过包装类的成员,可以了解到组件接口能提供哪些服务,而且可以通过它们访问组件接口的方法和属性。

在初始化对话框函数里用COleDispatchDriver类的CreateDispatch()成员函数创建Account组件对象:

IAccount m_account;

……

m_account.CreateDispatch(“ATLSample.Account.1”));

其中ProgID值“ATLSample. Account. 1”可以通过Microsoft Visual Studio Tools 6.0里的OLE View工具查找到,其前提是该组件已被成功注册过。

释放Account组件对象也可以用COleDispatch-Driver类的ReleaseDispatch()函数来完成。

对于在COM库函数方法中用过的Post方法可用下述方法调用:

CString str=m_account. Post(100);

可以看出此种方法实现了同样的功能但实现起来要比上一种方法简单些,而且对理解COM的要求也不高。

#import 指令

#import 指令方法非常简便。对于类型库文件采用该指令是非常合适的,因为不管是调试版本还是发行版本,对于类型库文件而言,其路径是固定的。#import指令在执行时将会从待引入的类型库中提取出两个文件:一个.tlh文件和一个.tli文件,后者仅仅是包装类的函数实现,而前者则包含了许多有关的重要信息。智能接口指针也在其中定义:

_COM_SMARTPTR_TYPEDEF(IAccount,__uuidof(IAccount));

在实际编译时,编译器会将其展开成下述代码,并通过_com_ptr_t模板类为接口IAccount定义一个智能指针IAccountPtr。之所以说其是智能指针,是由于它替代IAccount时,会自动处理CoCreate-Instance和所有的IUnknow方法,使用起来非常方便:

typedef _com_ptr_t<_com_IIID< Iaccount,__uuidof(IAccount)>> IAccountPtr;

由于有了智能指针,我们就可以调用_com_ptr_t模板类的CreateInstance()函数来完成对接口指针的创建工作:

IAccountPtr m_account=NULL;

m_account.CreateInstance(__uuidof(Account));

由于在生成的.tlh文件中包含结构声明和declspec(uuid(“”))声明,所以在这里可以很方便地用__uuidof(Account)获取接口的GUID。declspec(uuid(“”))声明将GUID和类及每个接口联系起来,允许开发人员以uuidof操作符来获取类和接口的GUID。

需要特别指出的是: 为防止原有代码和新引入的代码之间发生名字冲突,编译器会定义一个由类型库名称标识的命名空间,并在其中声明的任何名称内附加一个标识符。而为了避免指定命名空间标识,可以在#import 语句后加上using namespace ,而且还可以用rename_namespace来改变命名空间。比如在本例中可以进行如下处理:

#import “Account.tlb” rename_namespace(“AccountDriver”)

using namespace AccountDriver;

这样,在使用智能接口指针IAccountPtr时只需定义即可:

IAccountPtr m_account;

至于对代码组件中的函数和属性的调用则同前两种方法一样,也是通过m_account来完成访问的。由于_com_ptr_t模板类和智能指针的引入,#import 指令方法是这三种方法中使用COM组件最简单的一种。

转载于:https://www.cnblogs.com/howareyou586/archive/2008/11/19/1336800.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
组件基础 1 软件开发的阶段 1.1 结构化编程 采用自顶向下的编程方式,划分模块 和功能的一种编程方式。 1.2 面向对象编程 采用对象的方式,将程序抽象成类, 模拟现实世界,采用继承、多态的方式 设计软件的一种编程方式。 1.3 面向组件编程 将功能和数据封装成二进制代码,采用 搭积木的方式实现软件的一种编程方式。 2 组件和优点 2.1 组件 - 实际是一些可以执行的二进 制程序,它可以给其他的应用程序、操 作系统或其他组件提供功能 2.2 优点 2.2.1 可以方便的提供软件定制机制 2.2.2 可以很灵活的提供功能 2.2.3 可以很方便的实现程序的分布式 开发。 3 组件的标准 - COMComponent Object Model ) 3.1 COM是一种编程规范,不论任何开发语言 要实现组件都必须按照这种规范来实现。 组件和开发语言无关。 这些编程规范定义了组件的操作、接口的 访问等等。 3.2 COM接口 COM接口是组件的核心,从一定程度上 讲"COM接口是组件的一切". COM接口给用户提供了访问组件的方式. 通过COM接口提供的函数,可以使用组件 的功能. 4 COM组件 4.1 COM组件-就是在Windows平台下, 封装在动态库(DLL)或者可执行文件(EXE) 的一段代码,这些代码是按照COM的 规范实现. 4.2 COM组件的特点 4.2.1 动态链接 4.2.2 与编程语言无关 4.2.3 以二进制方式发布 二 COM接口 1 接口的理解 DLL的接口 - DLL导出的函数 类的接口 - 类的成员函数 COM接口 - 是一个包含了一组函数指针 的数据结构,这些函数是由组件实现的 2 C++的接口实现 2.1 C++实现接口的方式,使用抽象类 定义接口. 2.2 基于抽象类,派生出子类并实现 功能. 2.3 使用 interface 定义接口 interface ClassA { }; 目前VC,interface其实就是struct 3 接口的动态导出 3.1 DLL的实现 3.1.1 接口的的定义 3.1.2 接口的实现 3.1.3 创建接口的函数 3.2 DLL的使用 3.2.1 加载DLL和获取创建接口的函数 3.2.2 创建接口 3.2.3 使用接口的函数 4 接口的生命期 4.1 问题 在DLL使用new创建接口后,在用户 程序使用完该接口后,如果使用delete 直接删除,会出现内存异常. 每个模块有自己的内存堆(crtheap) EXE - crtheap DLL - crtheap new/delete/malloc/free默认情况 下都是从自己所在模块内存堆(crtheap) 分配和施放内存.而各个模块的 这个内存堆是各自独立.所以在DLL 使用new分配内存,不能在EXEdelete. 4.2 引用计数和AddRef/Release函数 引用计数 - 就是一个整数,作用是 表示接口的使用次数 AddRef - 增加引用计数 +1 Release - 减少引用计数 -1, 如果 当引用计数为0,接口被删除 4.3 使用 4.3.1 创建接口 4.3.2 调用AddRef,增加引用计数 4.3.3 使用接口 4.3.4 调用Release,减少引用计数 4.4 注意 4.4.1 在调用Release之后,接口指针 不能再使用 4.4.2 多线程情况下,接口引用计数 要使用原子锁的方式进行加减 5 接口的查询 5.1 每个接口都具有唯一标识 GUID 5.2 实现接口查询函数 QueryInterface 6 IUnknown 接口 6.1 IUnknown是微软定义的标准接口 我们实现所有接口就是继承这个接口 6.2 IUnknown定义了三个函数 QueryInterface 接口查询函数 AddRef 增加引用计数 Release 减少引用计数 7 接口定义语言 - IDL(Interface Definition Language ) 7.1 IDL和MIDL IDL - 定义接口的一种语言,与开发 语言无关. MIDL.EXE - 可以将IDL语言定义接口, 编译成C++语言的接口定义 7.2 IDL的基础 import "XXXX.idl" [ attribute ] interface A : interface_base { } 7.2.1 Import 导入,相当于C++的 #include 7.2.2 使用"[]"定义区域,属性描述 关键字 1) object - 后续是对象 2) uuid - 定义对象GUID 3) helpstring - 帮助信息 4) version - 版本 5) point_default - 后续对象 指针的默认使用方式 比如: uniqune - 表示指针可以 为空,但是不能修改 7.2.3 对象定义 1) 父接口是IUnknown接口 2) 在对象内添加函数,函数定义必须 是返回 HRESULT. HRESULT是32位整数,返回函数是否 执行成功,需要使用 SUCCESSED和 FAILED宏来判断返回值.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值