第一范文网 - 专业文章范例文档资料分享平台

OPC服务器与客户程序开发指南

来源:用户分享 时间:2025/6/11 7:43:43 本文由loading 分享 下载这篇文档手机版
说明:文章内容仅供预览,部分内容可能不全,需要完整文档或者需要复制内容,请下载word后使用。下载word有问题请添加微信号:xxxxxxx或QQ:xxxxxx 处理(尽可能给您提供完整文档),感谢您的支持与谅解。

可以看出,CBeepCnt类基于三个模板类。CComObjectRootEx操作了组件的引用计数;CComCoClass用来定义该对象的默认类工厂和聚合模型;IDispatchImpl,提供了一个双重接口IBeepCnt(接口ID是IID_IbeepCnt,支持自动化接口和自定义接口)。

CBeepCnt类同样提供了一组宏,ATL_NO_VTABLE会告诉编译器不要再为CBeepCnt类生成虚函数,因为ATL_NO_VTABLE必须只能与一个无法直接创建的基类一起使用。在项目中一定不能将declspec(novtable)与基本上是导出的类一起使用,因为该类(通常是 CComObject、CComAggObject 或 CComPolyObject)为项目初始化 vtable 指针。一定不能从任何使用declspec(novtable)的对象的构造函数调用虚函数。应该将那些调用移动到 FinalConstruct(大家要记着这个方法)方法。需要我们切记的是,我们可以尝试着添加一个虚函数,但是编译器会编译错误,切记ATL_NO_VTABLE意味着没有虚函数,不要为基于ATL_NO_VTABLE的类添加虚函数。

当对象创建时,对象实际上是CComObject。换言之,用的是把对象类型作为一个参数的CComObject模板类。一个派生的图如下图所示。

图2.7 CcomObject派生图

CComObject的主要工作是提供IUnknown方法的实现。这些必须由最低层的派生类提供,以便所有由IUnknown派生的类可以共享IUnknown方法的实现。CComObject的方法仅仅调用CComObjectRootEx中的实现。

另外需要注意的是COM接口映射,COM接口映射包含着我们实现自定义接口和IDispatch的宏。COM接口映射中包含的接口是可以通过QueryInterface返回的接口指针的接口。 这里还有一对宏。一个用来根据资源ID定义注册入口,一个用来改变对象创建的方法来保证对象不会被意外的删除。

与非采用ATL方式的COM相比,可以看到采用ATL开发的组件中没有引用计数的代码,是因为引用计数的工作由CComObjectRootEx类操作,而不需要我们来操作了。

接着讨论的新文件,beepcnt.rgs,包含了为ATL处理的代码的源脚本。大部分直接反映了为了COM运行时能够找到组件的注册入口。文件如下:

HKCR {

BeepCntMod.BeepCnt.1 = s 'BeepCnt Class' {

CLSID = s '{AE73F2F8-4E95-11D2-A2E1-00C04F8EE2AF}' }

BeepCntMod.BeepCnt = s 'BeepCnt Class' {

CLSID = s '{AE73F2F8-4E95-11D2-A2E1-00C04F8EE2AF}'

CurVer = s 'BeepCntMod.BeepCnt.1' }

NoRemove CLSID {

ForceRemove {AE73F2F8-4E95-11D2-A2E1-00C04F8EE2AF} = s 'BeepCnt C

lass'

{

ProgID = s 'BeepCntMod.BeepCnt.1'

VersionIndependentProgID = s 'BeepCntMod.BeepCnt'

ForceRemove 'Programmable' InprocServer32 = s '%MODULE%' {

val ThreadingModel = s 'Apartment' }

'TypeLib' = s '{170BBD8D-4DE8-11D2-A2E0-00C04F8EE2AF}'

} }

}

这段脚本用来注册和注销组件。默认注册时,所有的键都会添加到注册表,不管这些键是否在注册表中。当注销时,默认的方式是删除所有在脚本中列出的键。一般情况下,你不需要编辑这个文件,当你添加对象和接口时,向导会自动的实现它。

最后讨论的文件是“BeepCntMod_i.c”,在此文件中,定义了组件的CLSID。CLSID是唯一地标识类或组件的GUID,传统地,CLSID的一般形式为CLSID_。TypeLibID 是标识系统上的类型库。按照惯例,TypeLibID的一般形式为LIBID_<组件工程名>Lib。

#ifdef __cplusplus extern \#endif

#ifndef __IID_DEFINED__ #define __IID_DEFINED__ typedef struct _IID {

unsigned long x; unsigned short s1; unsigned short s2; unsigned char c[8];

} IID;

#endif // __IID_DEFINED__ #ifndef CLSID_DEFINED #define CLSID_DEFINED typedef IID CLSID; #endif // CLSID_DEFINED

const IID LIBID_BEEPCNTMODLib =

{0x170BBD8D,0x4DE8,0x11D2,{0xA2,0xE0,0x00,0xC0,0x4F,0x8E,0xE2,0xAF}};

#ifdef __cplusplus

} #endif

与添加组件对象前相比,已经存在的文件也有一些小的变化。

?BeepCntMod.cpp现在添加了#includes BeepCnt.h,并且为CbeepCnt添加了一个对象映射入口,每一个COM对象都有一个对象映射入口:

BEGIN_OBJECT_MAP(ObjectMap)

OBJECT_ENTRY(CLSID_BeepCnt, CBeepCnt) END_OBJECT_MAP()

?.idl文件里现在有了IDispatch派生的IBeepCnt接口入口,一个为BeepCnt 类的在类型库的Coclass入口。

当重新编译程序时,MIDL生成了一个新的反映新建组件对象的BeepCntMod.h文件。编译后就生成了组件的DLL文件,在编译的同时完成组件的注册。 2.5 添加组件对象的属性和方法(函数)

上面已经介绍了如何用ATL组件。然而生成的对象是个空的对象,属于这个对象的属性和方法都是空的。如何添加组件对象的属性和方法是本节要讨论的内容。

从Class View中右击IbeepCnt,选择“Add Method…”如图2所示的对话框出现。在Method Name编辑框中,选择返回值类型为HRESULT,方法名输入Beep,参数一项为空,单击OK,完成Beep方法的添加,向导会把所有Beep的定义的代码自动添加到BeepCnt.cpp和 BeepCnt.h文件中。

图2.8向接口添加方法

添加一个属性也是类似的。右击接口,选择“Add Property…”,如图2.9所示的对话框出现。选择合适的类型,输入属性的名称,单击OK完成添加。

搜索更多关于: OPC服务器与客户程序开发指南 的文档
OPC服务器与客户程序开发指南.doc 将本文的Word文档下载到电脑,方便复制、编辑、收藏和打印
本文链接:https://www.diyifanwen.net/c95xkt9d2vb3qhty4wk5h_6.html(转载请注明文章来源)
热门推荐
Copyright © 2012-2023 第一范文网 版权所有 免责声明 | 联系我们
声明 :本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
客服QQ:xxxxxx 邮箱:xxxxxx@qq.com
渝ICP备2023013149号
Top