计算机ATL全攻略_第1页
计算机ATL全攻略_第2页
计算机ATL全攻略_第3页
计算机ATL全攻略_第4页
计算机ATL全攻略_第5页
已阅读5页,还剩92页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

用ATL创建COM组件

一、创建一个模型(工程)MyProj。

二、给模型(工程)增加一个组件MyCom。

三、给组件增加方法(函数)MyF1、MyF2、MyF3、MyF4«

一、创建模型(工程)MyProj

在VC++6.0工作平台中,点击菜单File下的New菜单项,在出现的New对话框中选中Projects卡

片,在列表框中选中ATLCOMAppWizard(活动模板库组件导航)。

在ProjectName编辑框中输入项目名如MyProj,并选择合适的Location后,按确认按钮进入下一个

对话框:ATLCOMAppwizard-step1of1,在ServerType中选择DynamicLinkLibrary

[DLL],即进程内服务器,这是最快的组件。

选中SupportMFC选择项。

在按下Finish和0k按钮后,一个组件的框架已经建立。

二、给模型增加组件MyCom

在VC++菜单Insert中选中NewATLObject…菜单项,出现ATLObjectWizard对话框。

在左边的Category中选择Objects,右边的Objects中选中SimpleObject项。按Next按钮。

在出现的ATLObjectWizard属性对话框中Names卡片中的八个编辑框中左上方的ShortName编

辑框中输入短名如MyCom,其他七个编辑框的内容会自动生成。然后按确认按钮退出。

三、给组件增加方法(函数)MyF1、MyF2、MyF3.MyF4

在VC++工作平台的左边的Workspace的ClassView卡片中找到接口IMyCom项,按右键,在出现的

快捷菜单中选择AddMethod...,出现AddMethodtoInterface对话框,在对话框中输入要增加的函

数的函数名、参数和返回值类型。然后,按确认按钮退出。

先增加函数MyF1:

函数名为:MyF1

参数:无

在MyCom.cpp文件中插入代码:

STDMETHODIMPCMyCom::MyF1()

(

AFX_MANAGE_STATE(AfxGetStaticModuleState())

//TODO:Addyourimplementationcodehere

AfxMessageBox("欢迎使用我的组件”);

returnS_OK;

)

用同样的方法给组件增加函数MyF2:

函数名为:MyF2

参数为:

[in]BSTRstr,

[out,retval]int*val

插入代码:

STDMETHODIMPCMyCom::MyF2(BSTRstr,int*val)

(

AFX_MANAGE_STATE(AfxGetStaticModuleState())

//TODO:Addyourimplementationcodehere

CStringsStr(str);

intn=sStr.GetLength();

*val=n;

returnS_OK;

)

用同样的方法给组件增加函数MyF3:

函数名为:MyF3

参数为:

[in]BSTRstr,

[out,retval]BSTR*retstr

插入代码:

STDMETHODIMPCMyCom::MyF3(BSTRstr,BSTR*retstr)

(

AFX_MANAGE_STATE(AfxGetStaticModuleState())

//TODO:Addyourimplementationcodehere

CStringsStr(str);

CStringsRetstr二”组件收到你的信息:v"+sStr+”>\n特此告之。

CComBSTRtemp(sRetstr);

*retstr=temp;

returnS_OK;

)

用同样的方法给组件增加函数MyF4:

函数名为:MyF4

参数为:

[in]intx,

[out,retval]int*val

插入代码:

STDMETHODIMPCMyCom::MyF4(intx,int*val)

(

AFX_MANAGE_STATE(AfxGetStaticModuleState())

//TODO:Addyourimplementationcodehere

*val=x+1;

returnS_OK;

)

编绎工程,生成组件DLL。

如果是在Win2k或者WinXp的计算机上完成了上面的三步操作,就会在debug子目录下生成组件的

DLL文件,并且完成自动注册。但是在Win98的计算机上,注册要运行如下命令才能完成:

regsrv32C:\MyProj\Debug\MyProj.dll

创建COM组件客户

1,创建一个基于对话框的客户程序。

2,把服务器类型库导入客户工作平台。

3,初始化COM库。

4,获得服务器的GLSID.

5,创建COM组件服务器组件的实例。

6,使用COM对象。

7,终止COM库。

1.创建一个客户程序

用MFCAppWizard(exe)创建一,个基于对话框的应用程序MyExe:

在对话框中放置四个按钮,分别为MyF1.MyF2、MyF3和MyF4*

用ClassWizard生成单击按钮的四个响应函数OnMyF1(),OnMyF2()、OnMyF3()和OnMyF4()。

2,把服务器类型库导入客户

2-1在StdAfx.h文件中加入代码:

#import"..\MyProj\MyProj.tlb"

最后的StdAfx.h文件如下:

//stdafx.h:includefileforstandardsystemincludefiles,

//orprojectspecificincludefilesthatareusedfrequently,but

IIarechangedinfrequently

II

#if!defined(AFX_STDAFX_H_2B646017_28AD_4CDE_9792_CB8F9A5C6B39_INCLUD

EDJ

#defineAFX_STDAFX_H_2B646017_28AD_4CDE_9792_CB8F9A5C6B39_INCLUDED

#if_MSC_VER>1000

#pragmaonce

#endif//_MSC_VER>1000

#defineVC_EXTRALEAN//Excluderarely-usedstufffromWindowsheaders

#include<afxwin.h>//MFCcoreandstandardcomponents

#include<afxext.h>//MFCextensions

#include<afxdisp.h>//MFCAutomationclasses

#include<afxdtctl.h>//MFCsupportforInternetExplorer4CommonControls

#ifndef_AFX_NO_AFXCMN_SUPPORT

#include<afxcmn.h>//MFCsupportforWindowsCommonControls

#endif//_AFX_NO_AFXCMN_SUPPORT

#import,,..\MyProj\MyProj.tlbH

//{{AFX_INSERT_LOCATION}}

IIMicrosoftVisualC++willinsertadditionaldeclarationsimmediatelybeforethepreviouslin

#endif//!defined(AFX_STDAFX_H_2B646017_28AD_4CDE_9792_CB8F9A5C6B39_IN

CLUDEDJ

编译StdAfx.cpp,

这样在客户端的debug目录下生成组件的类型库头文件(.tlh)和类型库实现文件(如)。

2・2在使用组件的源文件上方使用名字空间,最后的源文件上面部分代码如F

//MyExeDIg.cpp:implementationfile

//

#include"stdafx.h"

include"MyExe.h"

include"MyExeDIg.h"

#ifdef_DEBUG

#definenewDEBUG_NEW

#undefTHIS_FILE

staticcharTHIS_FILE[]=_FILE_;

#endif

usingnamespaceMYPROJLib;

以下代码略

3,初始化COM库

HRESULThr=Colnitialize(NULL);

4,获得服务器组件的CLSID

CLSIDclsid;

hr=CLSIDFromProglD(OLESTR(wMyProj.MyComn),&clsid);

if(FAILED(hr))

AfxMessageBox("COMFailed");

return;

)

5,创建COM服务器组件实例,获得组件接口指针

IMyCom*ptr=NULL;

hr=CoCreatelnstance(clsid,NULL,CLSCTX_INPROC_SERVER,_uuidof(IMyCom),(LPVOID*)&ptr);

6-1,在OnMyF1()中使用COM对象MyF1()

ptr->MyF1();

ptr->Release();II释放实例

6-2,在0nMyF2()中使用COM对象MyF2()

charstr[32];

sprintf(str,',Len=%d",ptr->MyF2("abcdefg"));

AfxMessageBox(str);

ptr->Release();/Z释放实例

6-3,在OnMyF3()中使用COM对象MyF3()

AfxMessageBox(ptr->MyF3(Habcdefg"));

ptr->Release();//释放实例

6-4,在OnMyF4()中使用COM对象MyF4()

intx=8;charstr[32];

,

sprintf(strt"x=%d,x+1=%d',x,ptr->MyF4(x));

AfxMessageBox(str);

ptr->Release();//释放实例

7,终止COM库

CoUninitialize();

下面为客户测试端四个函数的完整代码。

//MyExeDIg.cpp:implementationfile

//

#include"stdafx.h1'

#include"MyExe.hH

include“MyExeDIg.h”

#ifdef_DEBUG

#definenewDEBUG_NEW

#undefTHIS_FILE

staticcharTHIS_FILE[]=_FILE.

#endif

usingnamespaceMYPROJLib;

HBIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHIIII

//CAboutDIgdialogusedforAppAbout

classCAboutDIg:publicCDialog

public:

CAboutDlg();

IIDialogData

//{{AFX_DATA(CAboutDlg)

enum{IDD=IDD_ABOUTBOX};

//}}AFX_DATA

//ClassWizardgeneratedvirtualfunctionoverrides

//{{AFX_VIRTUAL(CAboutDlg)

protected:

virtualvoidDoDataExchange(CDataExchange*pDX);//DDX/DDVsupport

//}}AFX_VIRTUAL

//Implementation

protected:

//{{AFX_MSG(CAboutDlg)

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

CAboutDlg::CAboutDlg():CDialog(CAboutDlg::IDD)

(

//{{AFX_DATA_INIT(CAboutDlg)

//}}AFX_DATA_INIT

L)

voidCAboutDlg::DoDataExchange(CDataExchange*pDX)

{

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CAboutDlg)

//}}AFX_DATA_MAP

L)

BEGIN_MESSAGE_MAP(CAboutDlg,CDialog)

//{{AFX_MSG_MAP(CAboutDlg)

//Nomessagehandlers

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

^lllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll

IICMyExeDIgdialog

CMyExeDlg::CMyExeDlg(CWnd*pParent/*=NULL*/)

:CDialog(CMyExeDlg::IDD,pParent)

(

//{{AFX_DATA_INIT(CMyExeDlg)

//NOTE:theClassWizardwilladdmemberinitializationhere

//}}AFX_DATA_INIT

//NotethatLoadicondoesnotrequireasubsequentDestroylconinWin32

m_hlcon=AfxGetApp()->Loadlcon(IDR_MAINFRAME);

}

voidCMyExeDlg::DoDataExchange(CDataExchange*pDX)

ES{

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CMyExeDlg)

//NOTE:theClassWizardwilladdDDXandDDVcallshere

//}}AFX_DATA_MAP

L)

BEGIN_MESSAGE_MAP(CMyExeDlg,CDialog)

//{{AFX_MSG_MAP(CMyExeDlg)

ON_WM_SYSCOMMAND()

ON_WM_PAINT()

ON_WM_QUERYDRAGICON()

ON_BN_CLICKED(IDC_BUTTON1,OnMyFI)

0N_BN_CLICKED(IDC_BUTT0N2,OnMyF2)

ON_BN_CLICKED(IDC_BUTTON3,OnMyF3)

0N_BN_CLICKED(IDC_BUTT0N4,OnMyF4)

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

^lllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll

IICMyExeDIgmessagehandlers

BOOLCMyExeDlg::OnlnitDialog()

(

CDialog::OnlnitDialog();

//Add"About…”menuitemtosystemmenu.

//IDM_ABOUTBOXmustbeinthesystemcommandrange.

ASSERT((IDM_ABOUTBOX&OxFFFO)==IDM_ABOUTBOX);

ASSERT(IDM_ABOUTBOX<OxFOOO);

CMenu*pSysMenu=GetSystemMenu(FALSE);

if(pSysMenu!=NULL)

CStringstrAboutMenu;

strAboutMenu.LoadString(IDS_ABOUTBOX);

if(!strAboutMenu.lsEmpty())

pSysMenu->AppendMenu(MF_SEPARATOR);

pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMen

)

}

//Settheiconforthisdialog.Theframeworkdoesthisautomatically

//whentheapplication'smainwindowisnotadialog

Setlcon(m_hlcon,TRUE);//Setbigicon

Setlcon(m_hlcon,FALSE);//Setsmallicon

//TODO:Addextrainitializationhere

returnTRUE;//returnTRUEunlessyousetthefocustoacontrol

)

voidCMyExeDlg::OnSysCommand(UINTnID,LPARAMIParam)

EH3{

if((nID&OxFFFO)==IDM_ABOUTBOX)

CAboutDIgdlgAbout;

I

dlgAbout.DoModal();

I

卜)

I

else

I

触{

I

CDialog::OnSysCommand(nlD,IParam);

I

卜)

I

L)

//Ifyouaddaminimizebuttontoyourdialog,youwillneedthecodebelow

//todrawtheicon.ForMFCapplicationsusingthedocument/viewmodel,

//thisisautomaticallydoneforyoubytheframework.

voidCMyExeDlg::OnPaint()

(

if(lslconic())

(

CPaintDCdc(this);//devicecontextforpainting

SendMessage(WM_ICONERASEBKGND,(WPARAM)dc.GetSafeHdc(),0);

IICentericoninclientrectangle

intcxlcon=GetSystemMetrics(SM_CXICON);

intcylcon=GetSystemMetrics(SM_CYICON);

CRectrect;

GetClientRect(&rect);

intx=(rect.Width()-cxlcon+1)/2;

inty=(rect.Height()-cylcon+1)/2;

//Drawtheicon

dc.Drawlcon(x,y,m_hlcon);

)

else

CDialog::OnPaint();

}

L}

//Thesystemcallsthistoobtainthecursortodisplaywhiletheuserdrags

//theminimizedwindow.

HCURSORCMyExeDlg::OnQueryDraglcon()

(

return(HCURSOR)m_hlcon;

)

voidCMyExeDlg::OnMyF1()

日已{

I

IITODO:Addyourcontrolnotificationhandlercodehere

I

HRESULThr=Colnitialize(NULL);

I

CLSIDclsid;

I

hr=CLSIDFromProglD(OLESTR("MyProj.MyCom")1&clsid);

I

if(FAILED(hr))

I

点由{

I

AfxMessageBox('*COMFailed");

I

return;

I

卜)

I

IMyCom*ptr=NULL;

I

hr=CoCreatelnstance(clsid,NULL,CLSCTX_INPROC_SERVER,—uuidof(IMyCom),(L

PVOID*)&ptr);

ptr->MyF1();

ptr->Release();//释放实例

CoUninitialize();

voidCMyExeDlg::OnMyF2()

//TODO:Addyourcontrolnotificationhandlercodehere

HRESULThr=Colnitialize(NULL);

CLSIDclsid;

hr=CLSIDFromProglD(OLESTR("MyProj.MyCom"),&clsid);

if(FAILED(hr))

AfxMessageBox("COMFailed");

return;

)

IMyCom*ptr=NULL;

hr=CoCreatelnstance(clsid,NULL,CLSCTX_INPROC_SERVER,_uuidof(IMyCom),(L

PVOID*)&ptr);

I

charstr[32];

I

sprintf(str,,'Len=%d",ptr->MyF2("abcdefgn));

I

AfxMessageBox(str);

I

ptr->Release();//释放实例

I

CoUninitialize();

I

L}

voidCMyExeDlg::OnMyF3()

I

//TODO:Addyourcontrolnotificationhandlercodehere

I

HRESULThr=Colnitialize(NULL);

CLSIDclsid;

hr=CLSIDFromProglD(OLESTR(,'MyProj.MyCom"),&clsid);

if(FAILED(hr))

I

点由{

I

AfxMessageBox(MCOMFailed");

I

return;

I

卜)

I

IMyCom*ptr=NULL;

I

hr=CoCreatelnstance(clsid,NULL,CLSCTXJNPROC_SERVER,_uuidof(IMyCom),(L

PVOID*)&ptr);

I

AfxMessageBox(ptr->MyF3(nabcdefg"));

I

ptr・>Release();〃释放实例

I

CoUninitialize();

I

L}

voidCMyExeDlg::OnMyF4()

(

//TODO:Addyourcontrolnotificationhandlercodehere

HRESULThr=Colnitialize(NULL);

I

CLSIDclsid;

I

hr=CLSIDFromProglD(OLESTR("MyProj.MyCom"),&clsid);

I

if(FAILED(hr))

I

触{

I

AfxMessageBox('*COMFailed");

I

return;

I

卜}

I

IMyCom*ptr=NULL;

I

hr=CoCreatelnstance(clsid,NULL,CLSCTX_INPROC_SERVER,_uuidof(IMyCom),(L

PVOID*)&ptr);

I

intx=8;charstr[32];

I

sprintf(str,,'x=%d,x+1=%dM,x,ptr->MyF4(x));

AfxMessageBox(str);

ptr->Release();//释放实例

CoUninitialize();

)

通过这个简单的例子,我们做了最简单的COM组件,及测试组件的客户端,在这里只是教大家如何用VC

ATL做COM组件,在接下来这一篇里DevelopingCOMComponentsusingVC-ATL(2)将对COM的基本

原理进行介绍,以及对这一例子的源代码进行剖析。

COM基础知识

COM的产生

应用程序被开发来支持公司业务运转,应用程序获取作为输入的数据,处理基于业务规则的数据,和

提供作为输出的数据和信息。基于这•事实,所有的应用程序都有三个要素:

■用户界面或呈现要素,通过它们可以输入数据。

■应用程序逻辑或业务规则要素,它们有助于实现对输入数

据执行有效性、可用性操作。

■数据存储或数据管理要素,它们管理数据的存储和恢复。

这三个要素养组成了用于应用程序开发模型或体系结构的基础。

根据具体的用途和配置,开发都在他们的应用程序中决定采用何种体系结构时有三种选择:

■单层模型

■双层模型

■三层或多层模型

作为个开发者,在决定应用程序的体系结构之前,你要考虑以下因素:

■伸缩性:这指的是应用程序适应新的硬件环境的性能。例

如,当一个应用程序从一个单处理器计算机移到一个多处

理计算机时,它是否能使用新增加的处理器,这些处理器

在新硬件上是否发挥了作用。

■可用性:这指的是应用程序满足用户增加要求的能力。可

能有一百个用户正在请求同样的数据,但是只有少数用户

获得数据,其他的用户则显示一则消息“请稍后再试”。

■扩展性:这指的是应用程序有时递增地增加特色来提高性

能和提供更好的功能给用户的能力。

■维护性:这指的是根据人力和时间使用最小化的资源和最

大化的有效性来响应修修复改错误的能力。

■安全性:这指的是应用程序维持数据完整性、可靠性的能

力。任何未经认可的用户都不允许篡改数据。

■性能:这指的是应用程序在最短的时间内响应用户请求的

能力。用户不要等待很长时间就能获得请求数据。

为了设计更健壮的应用程序体系结构,三(多)层体系结构就运用而生。三层体系结构是一种逻辑应用

程序观点,在这种体系结构中应用程序分成以下三层逻辑组成部分:

■用户服务层。用户服务层管理用户界面。

■业务服务层。业务服务层管理由应用程序实现的业务逻

辑。业务逻辑由支配应用程序处理的规则组成。这一层对

用户封装了业务逻辑,因而用户不必了解业务逻辑或'业务

规则是如何使用的。业务规则的任何变化将导致仅对业务

服务层的更改,而应用程序的其余部分保持不变。业务服

务层实现用于应用程序的多条规则。这一层扮演了用户服

务层和数据服务层间连接的角色。

■数据服务层。数据服务层负责维护数据,通常为RDBMS。

这一层维护数据的有效性和完整性,并且负责从数据存储

中增加、修改和删除数据。

现在,我们如何来做业务服务招呢?答案就是COM:

什么是COM?

COM即为组件对象模型,它为开发组件定义了标准。它定义了组件交互标准、协议标准和组件的物理

结构来确保组件间的互用性。一个组件就是一个执行特定操作的程序或二进制对象.下面我们就从组件的

一些特点和功能来理解吓COM:

■COM是种规范。COM规范描述了为创建能共同操作的

组件而必须遵守的标准。这个标准描述了COM是什么和

它们是如何运转的,以及说明了如何可动态交替更新组件。

■COM是一套服务。COM规范是由套服务或APIs来支

持的。COM库提供这些服务,它们是WIN32平台操作系

统的一部分并且可用于当作其他操作系统的一个单独的

包。

■COM是面向对象的。COM组件对象有标识、状态和行为。

■COM能够容易的用户化和升级你的应用程序。COM组件

动态地相互联结,并且COM定义了定位其他组件和鉴定

其功能的标准。因此,组件可以交换而不必重新编绎整个

应用程序。

■COM能够分布式应用。位置透明性是COM的特性之一、

这使得你可以编写COM组件而不必考虑它们的位置。组

件可以移动而不要求对使用它们的应用程序作任何改变。

■COM组件可以用任何语言编写。任何能够处理二进制语

言都能用于创建COM对象。能创建组件的语言和工具包

括C心++、JAVA、VISUALBASIC和VISUALC++等。

到目前为止,微软提倡的这套COM软件开发模式是最为符合现在计算机工业软件生产的方法。

Microsoft的许多技术,如ActiveX,DirectX以及OLE等都是基于COM而建立起来的。并且Microsoft的

开发人员也大量使用COM组件来定制他们的应用程序及操作系统。在COM构架下,程序员可以开发出

各种各样的功能专一的组件,然后将它们按照需要组建起来,构成复杂的应用系统。由此带来的好处是多

方面的:

■使用组件的最大好处首先是可以将它们动态的插入或卸

出应用系统,是真正意义上的软件模块即插即用。组件可

以在运行时刻,在不被重新链接或编译应用程序的情况卜

可以将系统中的组件用新的组件替换掉,以便即时方便地

进行系统的升级和定制。这样做的最大好处是程序员可以

利用最新的技术写出的最新组件取代以有的旧组件而整个

系统的其他部分不需要一点改动。应用程序可以随新组件

不断取代旧的组件而渐趋完善且健壮。而且利用已有的组

件,用户还可以快速的建立全新的应用。(注意:替换的组

件均为自定义的组件,不是COM本身的运行时间库中的

组件)

■二进制重用。按照COM规范,组件可以在多个应用系统

中重复利用同一组件。

■分布式应用。利用COM/DCOM组件技术,可以方便的将

应用系统犷展到网络环境下。

■COM与语言无关。可以使用多种语言编写COM组件,

如DELPHI、VISUALBASIC…这使得程序员可以利用自

己擅长的语言来编写组件,而无须学习其他专门的语言来

编写组件。

■COM与平台无关。利用已编写的组件可以方便地在不同

平台间移植。

在三层体系结构中,创建COM组件来实现业务服务层。因为COM组件能够相互作用,每个组件必

须严格地贯彻由COM拟定的完整的标准。

COM具有显著的优点在于它提供了三个独有的特性:

■调用组件间功能的二进制标准。COM确保用VISUAL

BASIC开发的客户端和用VISUALC++开发并且运行于

Solaris或Mac服务端的组件间完全的二进制的兼容性。

因此,COM允许你创建确实是独立于语言和操作系统的代

码模块。

■代码重用。因为接口是文档化的,所以创建对象的代码能

被不同的客户使用。

■版本控制。基于COM的组件是自我版本化的。暗示新的

功能可以增加到组件中,而不影响已使用该组件的用户(/

客户)

由此可见,COM组件是真正地面向对象,提供简易的用户化,提供地址透明并且能用任何语言编写。

正由于COM具有这些优点,COM得到了广泛应用。

COM组件是真正地面向对象

■传统的面向对象编程

面向对象编程是一个被广大编程人员和工业界认同已久的概念。面向对象程序设计语言让开发者按照

现实世界里人们思考问题的模式来编写程序,它让开发者更好地用代码直接表达现实中存在的对象,这样

开发代码简单并且易于维护。面向对象语言有以下三个最重要的概念:

■封装(Encapsulation)强调隐藏对象的实现细节,

对象的使用者仅仅通过定义好的接口使用对象。

■继承(Inheritance)新的对象可以利用旧的对象的

功能。

■多态(Polymorphism)根据所使用的对象展现多

种不同行为的能力。

而从程序的整体来看,面向对象编程提供给用户的最重要的概念则是源代码重用,它对于提高编写程

序的效率极为重要。但是代码的共享与重用一旦应用于实践中仍然存在种种问题,如版本的升级、接I1[1]

的变化、在不同程序设计语言之间共享代码等等。对于这些困难原有的面向对象程序设计方法并没有相应

的答案,这就是组件对象模型提出的背景。

■基于组件编程

它与传统面向对象模型有着根本的区别,传统的面向对象编程模型的重点是源程序以及系统分析和设

计过程,面向对象归根到底还是基于源代码的重用,不是真正意义上的面向对象。相反,COM组件的概念

则强调大的软件系统如何由不同的小组件构成整体应用程序体系结构。

将工程分解为逻辑组件是面向组件分析和设计的基础,这也是组件软件的基础。组件软件系统由可重

用的二进制形式的软件组件模块组成,只需要相当小的改动就可以将这些来自不同开发商的组件模块组合

在一起。特别重要的是这样的组合并不需要源代码,也不需要重新编译,组件之间是通过基于二进制的规

范进行通讯的,这被称为二进制重用。组件模块是独立于编程语言的,使用组件的客户程序和组件之间除

T通过标准的方法进行通讯以外,彼此不做任何限定。

组件可以划分为不同的类型,包括可视化组件如按钮或者列表框;功能组件如打印或者拼写检查。例

如个基于组件的架构可以提供将多个开发商的拼写检查组件插入到另一个开发商的字处理应用程序中的

机制,这样用户可以根据自己的喜好方便地选择和替换字处理软件。

COM允许你创建相互联合起来形成应用程序的独立的、可重用的组件。在COM中,组件间的相互作

用是基于Client/server模型的(即客户机和服务器模型)。基于这个模型,COM组件可以分类为:

■Client使用由其他组件提供的功能。

■Server有其他组件可能使用的预先确定的功能的组件。

客户程序和组件程序是相对的,进行功能请求调用的是客户程序,而响应该请求的是组件程序。组件

程序也可以作为客户程序去调用其它的组件程序,即提供服务给客户端的COM服务器可能是客户本身。

正是这种角色的转换和相互调用关系使组件程序最终构成一个软件系统。

服务器组件的类型

COM设计为允许组件相互通信而不管它们的地址。例如,用户接口组件将最好定位于接近客户端。另

一方面,提供远程数据统计计算的组件将随同将被操作的数据可能定位在一台分离的计算机上.COM服务

端组件可分为三类:

■进程内组件进程内服务器[2]是装入客户端的进程空间

内的组件,即客户程序和组件程序在同一个进程地址空间

内。在客户端和服务端组件间有大量数据转移操作的情况

下是理想的。进程内服务器会更快地装载。由于它占用和

客户端应用程序同样的地址空间,它可以与客户端更快的

通信。进程内服务器是通过将组件作为动态连接库(DLL)

的形式来实现的。DLL允许特定的一套功能以分离于可执

行的、以DLL为扩展名的文件进行存储。只有当程序需

要它们时,DLL才将其装入内存中,客户程序将组件程序

加载到口己的进程地址空间后再调用组件程序的函数。

本地(即进程外)组件进程外组件指客户程序和组件程序

分别处在不同的进程空间地址中。进程外服务器对需要运

行于独立的处理空间或作为独立客户端应用程序的线程

的组件是理想的。这种服务器的类型自身是EXE,因此具

有独立的进程的资格。由于数据必须从•个地址空间移到

另一个地址空间,因此这些服务器就会慢得多。由于进程

外服务器是可执行的,它们运行在自己的线程内。当客户

端代码正在执行时,客户端不锁住服务器。进程外服务器

对需要表现为独立的应用程序的组件也是理想的。例如,

MicrosoftInternetExplorer的应用程序是本地服务器的例

子。客户端和服务端的通信是通过进程内的通信协议进行

的,这个通信协议是IPC。

■远程组件远程服务器与本地服务器类似,除了远程服务

器是运行在通过网络连接的分离的计算机上。这种功能是

使用DCOM实现的。DCOM的优点在于它并不要求任何

特别的编程来使具有功能。另外服务端和客户端通信是通

过RPC通信协议进行的。

对于这三种不同的服务器组件,客户程序和组件程序交互

的内在方式是完全不同的。但是对于功能相同的进程内和进程

外组件,从程序编写的角度看,客户程序是以同样的方法来使

用组件程序的,客户程序不需要做任何的修改。

COM的真相

COM是一种软件体系结构,这种体系结构允许用不同的软件商提供的组件来构造应用程序和系统。它

是一套二进制的和网络标准,允许任何软件相互通信而不管硬件、操作系统OS和用于开发的编程语言。

COM不是•种编程语言而是一套规范,它定义了组件怎么样可以相互通信。

每个COM组件被编写成满足由COM规定的二进制标准。这一些标准是:

■组件要求注意它们自己(即组件对象网)的创建和销毁

■组件要求以标准方式提供它们的功能(即通过接口[4])

组件的位置要求对用户透明

使用组件的优点在于具有将它们动态装载或卸出应用程序系统的能力。为了达到这一目的,组件必须满

足两个需求:

■组件必须动态链接[5]。这允许它们在运行时改变。如果

应用程序是由每次组件改变时静态链接的组件组成,那么

应用程序就等同于一个单一的应用程序。

■在实现时组件必须隐藏。每个组件具有唯识别自己的

ID作为标识。这些ID出现在系统注册表

HKEY_CLASSES_ROOT目录里。

动态链接对于组件而言是一个至关重要的要求,而实现细节隐藏则是动态链接的一个必要条件。

COM的工作方式

到目前为止,显然COM并不仅仅是书面形式的规范。它也包含系统级的代码,即它自身的实现。COM

规则出现在COM运行库里。

组件对象库,即COM运行时间库是一个系统组件,这个系统组件提供能够在进程内、进程外或通过

网络进行调用的COM。

COM核心,简单地讲,是组件对象和客户端使用二进制标准如何交互的规范。COM在操作系统内的

实现为COM运行时间库。COM运行时间库包括:

■API函数

■服务

■允许应用程序在进程内控制内存分配的标准机制

■...

组件对象库是通过Windows3.1中的COMPOBJ.DLL以及WindowsNT和Windows9X中的

OLE32.DLL实现的。

接口

■概述

■组件对象高度地封装。组件对象的内部实现对用户

完全隐藏,根本无法知道组件对象在使用何种数据结

构和这些数据是如何被函数处理的。每个组件有一个

接口,这个接口是一种且唯一的访问组件对象功能的

方式。接口是由一组虚函数的声明组成。它使得预期

的行为和响应清淅化。接中并不具有这些函数的实

现。函数是通过组件类(CoClass)实现的。组件类实

例化时生成组件对象。

■接口是用称为虚函数表(VTable)的内存结构实现的。

无论何时创建组件对象,组件对象也在内存中创建■

张对应的虚函数表。虚函数表是由一系列指针组成,

这些指针存储了由组件对象实现的成员函数的地址。

■客户端创建一个接口指针,接口指针指向一个虚指

针,虚指针指向虚函数表。使用接口指针和虚指针,

客户端就可以访问组件对象实现的成员函数。

VTable是一个函数指针数组的内存结构。每一个数组元素

包含的是一个由蛆件所实现的函数地址。对于COM而言,

接口也就是此内存结构,其他东西,均是COM不关心的

实现细节。

特征

■接是集合在同一个名称(是一个系统唯一的旧值,

称IID)下的相关函数(/方法)的集合。这说明接口必须

是全球唯一的。

■如前所述,当组件类实例化时产生组件对象。接口

是由组件对象实现的函数的集合。接口不可以被实例

化,因为它没有实现。

■组件之间的通讯是基于接口的。接口是组件和其客

户之间严格类型化的契约。实现相同接口的两个对象

就被认为是多态的,这里的多态不包含诸如基类指针

指向派生类对象的意义,这里是指同一个接口可以由

多个组件对象以不同方法实现。

组件对象可以实现多个接口。例如,银行交易组件

(BankTransaction)支持两个接口,IDebit和ICredit,

即借和贷:又例如,MicrosoftSQLSERVER数据库

服务器组件(Sqllmplementation)支持两个接口,一个

是维护数据处理,另一个是维护

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论