李巍
天津市汉沽区公用房屋管理所 天津 300480
随着Intranet/Intement的飞速发展,使软件应用置身于更加广阔的环境中,从而对应软件提出了更高的要求。在这样的环境下,面向对象的思想已经难以适应这种分布式的软件模型,于是组件化程序设计思想得到了迅速的发展。
按照组件化程序设计的思想,复杂的应用程序被设计成一些小的、功能单一的组件模块,这些组件模块可以运行在同一台机器上,也可以运行在不同的机器上,甚至可以是不同的操作系统。为了实现这样的应用软件,组件程序和组件程序之间需要一些极为细致的规范,只有组件程序遵守了这些共同的规范,软件系统才能正常的运行。为此,OMG(Object Management group,对象管理组织)和Microsoft分别提出了CORBA和COM(Component Object Model,组件对象模型)标准,目前CORBA模型主要应用于UNIX操作系统平台,而COM则主要应用于Microsoft Windows操作系统平台上。
Windows系统提供了一个用于注册进程内组件的使用工具Regsvr32.exe,只要进程内组件提供了相应的入口函数,则Regsvr32就可以完成注册或称注销,而Regsvr32程序本身并不进行注册工作。
除了利用Regsvr32程序进行注册之外,还有其他一些安装程序在安装或卸载的过程中也可以调用组件程序中的DLLRegisterServer函数和DLLUnregisterServer函数完成组件程序的注册和注销操作。
COM本身除了规范以外,也有实现的部分,其中包括一些核心的系统级代码,也正是这部分核心代码,才使得对象和客户之间可通过接口在二进制代码级进行交互。在Microsoft Windows操作系统环境下,这些库以.DLL文件的形式存在,其中包括以下内容:
(1)提供了少量的API函数实现客户和服务器端COM应用的创建过程。在客户端,主要是一些创建函数;而在服务器端,提供一些对对象的访问支持。
(2)COM通过注册表查找本地服务器即EXE程序,以及程序名与CLSID的转换等。
(3)提供了一种标准的内存控制方法,使应用控制进程中内存的分配。
设计接收器对象与连接点对象之间如何建立关系的过程,这个过程是由客户方控制的,所以客户首先询问对象是公为可连接对象,它只需调用对象的QueryInterface成员函数,请求IConnection pointContainer接口,如果请求成功,则表明为可连接对象,并返IConnection pointContainer接口指针,否则说明对象不是可连接对象。客户得到了IConnection pointContainer接口后,调用其成员函数获取出接口的连接点对象,如果对象支持此出接口,则可以得到连接点对象,然而调用连接点对象的IConnection point接口的成员函数建立连接。如果客户要取消连接,同样调用IConnection point接口的成员函数即可。
首先在应用类的InitInstance成员函数中加入COM或OLB库初始化函数,InitInstance函数开始处理调用AfxOleInit辅助函数代码如下:
BOOL CTestCtrlApp::InitInstance()
{
// Initialize OLE libraries
if(!AfxOleInit())
{
AfxMessageBox("Initializing OLE library failed");
return FALSE;
}
AfxEnableControlContainer();
为对话框类加入内嵌的接受对象,因为对话框类也是从CCmdtarget派生而来的,所以在对话框类中可以使用BEGIN_INTERFACE_PART/END_INTERFACE_PART宏定义接受器对象类。定义接受器对象类:
BEGIN_INTERFACE_PART(EventSink,IDispatch)
INIT_INTERFACE_PART(CTestCtrlDlg,EventSink)
STDMETHOD(GetTypeInfoCount)(unsigned int*);
STDMETHOD(GetTypeInfo)(unsigned int,LCID,ITypeInfo**);
STDMETHOD(GetIDsOfNames)(REFIID,LPOLESTR*,unsigned int,LCID,DISPID*);
STDMETHOD(Invoke)(DISPID,REFIID,LCID,unsigned short,DISPPARAMS*,
VARIANT*,EXCEPINFO*,unsigned int*);
END_INTERFACE_PART(EventSink)
对话框的操作,首先,在InitInstance成员函数中加入如下创建源对象的代码:
GUID sourceobjCLSID;
HRESULThResult=::CLSIDFromProgID(L"SourceComp.S ourceObj",&sourceobjCLSID); if(FAILED(hResult))
{
return FALSE;
}
hResult = CoCreateInstance(sourceobjCLSID,NULL,
CLSCTX_INPROC_SERVER,IID_IDispatch,(void**)&m_pDispatch);
if(FAILED(hResult))
{
return FALSE;
}
按照消息控制函数0nConnection和OnDisconnection分别调用辅助函数Connection和Disconnection作为响应,并根据不同的返回值进行不同的处理。
按钮消息控制Onsetproperty为源对象的属性赋值,在赋值之后,源对象会引发事件。
所以,在连接已经建立的状态下,当用户按下“设置属性”按钮时,会出现事件响应消息框。
最后我们还必须对对话框类的析构函数中的清除工作,包括断开连接、释放源对象等操作。在CTestCtrlDlg析构函数加入下面代码:
if(m_pDispatch != NULL){
if(m_dwCookie != 0)
Disconnection();
m_pDispatch->Release();
}
在VC++环境下COM的编程,VC++对CO3M开发提供了很好的支持,技术非常成熟,功能非常强大,使用VC++可以开发出功能强大,接口集合度高,占用资源少的应用程序。使用VC++的MFC类,模板类,以及AppWizard,ClassWizard等用于产生应用程序的特点,加快应用程序的设计,用组件技术可以很好地开发出一个完整的应用程序。
[1]苏长龄.C/C++程序设计教程.中国水利水利出版社.2007.
[2][美]帕拉特著.COM精髓.信达工作室译.2001.
[3]吴金平.VisualC++6.0编程与实践.中国水利水电出版社.2001.