前言
在互联网发展到了今天,网络环境下的编程标准有很多,COM是其中之一,也是发展最快,应用面最广的标准。但目前在国内,没有多少真正介绍COM的书,加上COM本身理解起来也有难度,推广和使用COM比较困难,本文试图从概念和应用结合的角度,把COM展示给读者。并介绍了COM在Internet上的应用。
一。Com技术概论
COM(Component Object Model)微软的组件对象模型.它的实质是一些小的二进制可执行的程序,它可以为应用程序和操作系统以及其他的组件提供服务.微软的许多其他的技术如:ActiveX,DirectX,OLE等都是基于COM建立的.
COM的发布形式是:以win32动态链接库(DLL)或者以可执行文件(EXE)的形式发布的可执行代码组成。 其中以DLL形式发布的方式实现的组件程序,在客户调用时会把组件程序和客户程序运行在同一个进程中,所以被称为进程内的组件。以EXE的形式发布,在客户调用时,他有自己的独立的进程空间。故称为进程外的组件。
COM也不是win API那样的一个函数集:它并没有支持或者提供各种函数来对系统进行特定的操作。COM本身要实现一个称为COM库(COM library)的API,它提供诸如客户对组件的查询,以及组件的注册/反注册等一系列服务,一般来说,COM库由操作系统加以实现,程序员不必关心其实现的细节。
总体来看,COM提供了编写组件的一个标准方法。遵循COM标准的组件可以被组合起来以形成应用程序。至于这些组件是谁编写的,是如何实现的并不重要。组件和客户之间通过”接口”来发生联系。
1.COM接口是一组逻辑上相互关联的操作,这些操作定义了某种行为,也就是这组操作的规范,而非特定的实现,实质也就是接口代表了接口调用者和实现者之间的一种约定.接口的理解是非常重要的,因为所有的对COM的操作都是通过接口指针来进行的.通过接口我们把组件的功能展示给了调用者(ASP Pages等)
每个COM接口都提供一个名叫IunKnow接口,该接口包括了ADDREF(),RELEASE(),和QUERYINTERFACE()三个接口,前两个接口是用来操纵对象引用计数,因为每个COM对象的创建都需要消耗系统的资源,引入了这两个函数后,当对象被创建或其他用户将一个指针指向该对象时,调用ADDREF()方法,将引用计数加一,当不再使用该对象时,调用RELEASE()方法,将引用计数减一,当计数为0时,对象释放自己,就可以避免每次引用对象时都重新创建,使资源可以合理的分配使用。QUERYINTERFACE()接口是用来查寻该对象是否用来支持其他的接口的,您需要传递欲查寻的接口的IID以及一个指向输出参数的指针。每个COM接口都是从IunKnow接口派生出来的,在其VTBL中的开始的三个条目就是指向上述三个函数的指针。下面写出这三个接口的实现方法:
/* 引用对象*/
ULONG IUnKnown::AddRef(void)
{
m_RefCount++; /*引用计数加一*/
return m_RefCount; /* 返回当前的被引用次数的总数 */
}
/*释放对象的*/
ULONG Iunknow::Release(void)
{
m_RefCount–; /* 引用次数减一 */
if (m_RefCount==0) /* 如果计数值为0,对象释放自己 */
{
delete this;
return 0;
}
return m_RefCount; /* 返回当前的被引用次数的总数 */}
/*查询接口*/
HRESULT IunKnow::QueryInterface(REFIID riid, LPVOID FAR *ppv)
{
if(riid==IID_IUnknown || riid==IID_IDropTarget) /*检查是否对象支持所查询的接口*/
{
ppv=(LPVOID) this; /* 把被请求接口的指针赋给输出参数 */
AddRef(); /* 引用对象 */
Return S_OK; file://成功的标记
}
else{
*ppv=NULL; /* 把输出参数的指针赋为空 */
return E_NOINTERFACE; /* 返回失败的信息 */
}
}
VB实现的COM很多细节都是VB自动完成的,用户只是定义各个方法的实现部分,其它的工作全部交给系统处理,而在VC和Delphi中接口的声明和实现都要用户来实现,用户就可以自由的控制一些低层的东西。
2. 类型库:类型库是一个描述信息的集合,这些描述信息涉及组件的类、接口及接口上的方法以及这些方法的参数类型。类型库通过ITYPELIB接口来访问,对于VB等智能开发环境,无法使用C++头文件来找到接口的方法和属性的信息,这时可以把类型库当做独立于语言的头文件,用他可以轻松的解决如用户界面等问题,使程序开发更加的简单。
3.GUID:又称为全局唯一标识,用于唯一的区分COM中的条目的标识。GUID的结构定义如下: typedef struct_GUID { unsigned long Data1;
unsigned long Data2;
unsigned long Data3;
unsigned long Data4[8];
}GUID;
生成GUID来标识对象类或接口。它共有128位,在理论上不存在GUID间的冲突。在运行阶段,程序可以 通过API函数CoCreateGuid()来完成,而在开发阶段,可以通过运行应用程序:GUIDGEN.EXE来获得。在COM中有三个GUID:CLSID(标识类对象),ProgID(标识类易称)和IID(标识接口),其中的ProID和CLSID一一对应,因为ProID比较容易记忆和识别,在VB等智能开发环境里,基本上都用ProID,但在具体实现时,VB等却还是要先运行CLSIDFromProID函数来得到对象的的CLSID,再调用CoCreateInstance函数来创建COM对象.
最后介绍COM对象的创建:客户程序通过函数CoCreateInstance()创建对象(指定需要的CLSID和接口),在程序里通过CLSID标识要创建的对象,COM使用该CLSID在注册表里找到服务器的位置,然后创建对象。在VB里有两种创建对象的方法:1。new <某个对象> 它实际上还是在调用CoCreateInstance函数,这种方法要求把要创建对象的类型库包含在VB工程里。2。用CreateObject函数,需要指定要创建对象的ProgID,和在那台计算机上创建。这种方法先把ProgID转为CLSID,然后用CoCreateInstance函数创建对象。
二。MTS对COM 对象的管理
MTS::Microsoft Transaction Server微软事务处理管理器。它提供了应用程序基础结构,用于创建可扩展的、健壮的企业应用程序,它是一个基于组件的事务处理系统,用于创建、部署以及管理服务器应用程序,MTS也是WindowsNT Option Pack的一部分。
MTS对象具有及时激活JIT(Just-In-Time activation)特征。假如客户程序频繁地创建对象和删除对象,由于创建对象和删除对象是一个很消耗系统的资源的操作,所以这样做势必会影响系统的性能。MTS提供了对象的重用功能,当对象被最终释放时,它并不是马上就从内存中清楚,如果客户要求再次创建对象,MTS可以重用原来的对象,对象被重新初始化,从而避免了频繁的创建和删除对象的操作。MTS使的COM做为组件对象模型更加成熟、完善,他把对象集中管理起来,并且为对象实现了诸如事务,安全等复杂的特征,使对象免于底层琐碎的细节,但又不失去功能。
MTS的对象就是指运行在MTS环境下的COM组件的实例,MTS为每个对象维护了一个环境对象(又称为上下文对象),环境对象实现了IobjectContext接口,通过该接口,提供了事务、活动状态、安全控制能力等,当多个对象参与同一事务处理时,MTS使用相关的上下文对象来跟踪事务处理。MTS客户就是MTS对象的客户程序,可以是一个运行在MTS外的应用程序(基客户),也可以是另一个MTS对象。所以MTS的对象和客户是一个相对的概念。
MTS在安全性控制方面主要用基于角色的安全模型,该模型以MTS服务进程为安全单元,不单独定义组件的安全角色,同时MTS还提供了另一种高级的安全模型,即,在环境变量中,除了实现IobjectCountrol接口外,还实现了另一个接口IsecurityProperty, 利用该接口可以获得创建该对象的客户的SID和当前调用该对象的客户的安全标识符。应用系统可以通过这些信息来实现自定义的访问控制。
仅仅将COM DLL添加到MTS程序包是不够的,它并不为MTS所感知,还必须编写程序,为了使用事务处理并以有效的方式在MTS中工作,必须遵循下面四个规则:
1) 获得对ObjectContext对象的引用:一个对象上下文信息存储在ObjectContext对象中,ObjectContext对象跟踪MTS对象所做的工作,也记录MTS对象的安全性信息,对象通过调用GetObjectContext函数,可以获得一个对它们的上下文对象的引用。
2) 若工作成功,则调用SetComplete方法:在对象参与一个事务处理时,若成功了必须调用ObjectContext对象的SetComplete方法,该方法通知MTS,由该对象所做的工作可以提交,其所持有的资源(包括该对象本身)可以回收。
3) 若工作失败,则调用SetAbort:当对象失败时必须调用SetAbort方法,该方法通知MTS该对象所进行的所有修改及同一事务处理内其它对象进行的所有修改都必须回滚且该对象所持有的所有对象都可以回收
4) 管理对象状态:状态就是对象数据。局部变量和全局变量可以保留对象状态,但是当事务处理完毕时MTS会回收对象,这样会丢失局部和全局变量中的所有信息,因此想要将状态保留下来,必须通过一些方法如类的属性、函数返回值、地址参数等。
我再给出一个VB实现的创建MTS组件实例
‘ ***************************************
‘ FUNCTION: ListCustomer()
‘ PURPOSE: 简单的找到客户信息,然后显示出来
‘ ***************************************
Public Function ListCustomers() As ADODB.Recordset
On Error GoTo ErrorHandle
Dim objADOConn As ADODB.Connection
Dim strSQL As String
Set objADOConn = GetObjectContext.CreateInstance(“ADODB.Connection”) file://请注意这里用的不是用一般的CreateObject()方法,而是用GetObjectContext中的CreateInstance()方法来返回一个指向ADO连接对象的指针。
strSQL = “SELECT CustomerID, CompanyName, Address, City, Country, Phone FROM Customers”
objADOConn.Open “Northwind”, “sa”, “password” // ‘打开连接SQLSERVER数据库
Set ListCustomers = objADOConn.Execute(strSQL) file://取出所需的记录集
GetObjectContext.SetComplete file://成功操作后释放对象
objADOConn.Close
Set objADOConn = Nothing
strSQL = “”
Exit Function
ErrorHandle:
Err.Clear file://清理错误
GetObjectContext.SetAbort file://释放对象
用SetComplete 告诉MTS,该组件对象已经调用完成,可以释放他的资源到MTS的线程池去了
对应的SetAbort方法则告诉MTS该组件的调用取消了,同样释放他的资源到MTS线程池中去。
这时把该应用了MTS技术的组件编译后,就可以在asp页面里通过调用Server.CreateObject(“Northwind.Customer”)而得到ListCustomer()的方法
三。COM 技术在互联网上的应用
com技术的主要应用是由于目前网络应用程序的三层结构的趋势和分部式应用程序程序windows DNA 的发展和推广。目前大多数应用程序均为两层式(C/S)结构,在一个两层式的体系结构中受用户数目的限制非常的大,因为两层式结构的每个客户都直接连到数据库服务器上,服务器的压力非常的大。在引入了三层结构后,我们定义了和用户直接打交道的表示层(Presentation Layer),用于处理用户提交的商业层(Business Logic Layer)和一心一意用于数据库处理的数据访问层(Data Access Layer)。
现在三层结构越来越广泛的使用:有理由相信在不久的将来,COM 将成为构建互联网应用程序最普遍的方法。
目前构建电子商务的网络应用程序时,有非常多的选择,如目前,在国外非常流行的jsp,他有跨平台的优点,因而被倍加推崇。也可以用象php+mysql,这是在linux环境下的对付中小型应用的黄金组合,然而,微软的平台在中国的企业中仍然占有了绝对的地位,微软的asp以其易用性迅速占有了很大的电子商务市场,而目前微软的.net计划更是大大提升了微软在网络商务平台的地位。然而,asp或未来的asp.net都有比较大的局限,安全性和效率是两大问题,现在通过com技术是一种解决方案,用com把asp从商业层中解放出来,让他专心的用于表示层的处理,同时用vb,vc,java,delphi等来构建商业层的组件.
COM的优势在于:1。在internet时代,软件的开放性很重要,开放性也就意味着要遵从标准。而在Windows平台上,COM就是这样的标准。2。微软提出的ActiveX技术包含了所有的基于COM的internet相关的软件技术,而ActiveX技术毫无疑问是互联网上最具应用前景的技术,不久的将来,随着ActiveX控件的完善,我们有理由相信在Internet上的任何开发都将会以它为模板和基础,而COM正是ActiveX的基础。从服务器方面来看,ASP把IIS和其他的软件产品结合起来,提供了非常强大而易用的WEB应用实现方案,从客户方软件产品看,其内容更为丰富,Internet SDK提供了很多可以直接利用的组件或特征,如:XML对象模型,WebBrower控制等,通过这些组件,为Internet用户提供了更多的便利,也提供了更为丰富多彩的信息。3.现在COM已经渗透到了产品Internet 各种软件中,包括一些基本的协议软件。以后不仅软件开发商要应用COM,连基本的主页维护者都恐怕要用COM来完善其页面了。4.用com来扩展asp网络应用程序很大的优点就在于使我们的应用程序更加具有可维护性和在执行时更有效率!同时他还达到了封装源代码,以保护知识产权。5。Internet应用程序大部分属于分布式应用程序,而COM(主要是指分布式COM)一个重要特点就是是它的处理能力能够随着用户的数量、数据量所需性能的提高而增加。6。COM的无逢扩展集COM+,有着如内存数据库,负载平衡等强大的功能。
当然应用COM也有缺点:首先是COM的标准还有待完善(事实上,包括 COM+的标准都在不断的完善中),其次编写和调试COM比较麻烦,即使是使用VB等智能环境,要充分的实现COM特点不是一件容易的事。
从COM执行的效率来说,到连接用户比较少的时候,使用COM就是等于增加了一层接口,当然多少影响一点效率。但当用户数量很多的时候,由于DCOM可以把负载平衡到几台服务器上,已经MTS的JIT技术等,可以大幅度的提高效率。
COM本身提供了两种类型的安全性,访问安全性(指定那些用户可以调用组件,包括了如何被安全的启动和如何保护公共的资源等)和激发安全性(哪些用户可以在一个新进程中创建新的组件对象),这些主要都是对进程外组件来说的,对于进程内组件,一般不考虑其安全性。安全性对于互联网上的应用程序尤为重要,由于ASP程序是把代码写在一个页面上,导致了很容易暴露商业规则,而商业规则对于应用程序来说是非常重要的,而利用COM我们可以把商业规则编译成为二进制代码,就达到了保护代码的目的。同时利用COM还可以把对数据库的连接访问等都封装在代码里,因为DLL已经编译完成,而ASP是解释型,执行的效率相比也差很多。
下面,用一个增加access数据库记录的实际例子来说明:
首先在vb中创建一个新类:如clsadd 然后在其中定义一个接口函数:add
Public Sub Add(ByVal UID As String, ByVal Pwd As Integer, ByRef vntError As Variant)
Dim objConnection As ADODB.Connection
Dim objCommand As ADODB.Command
On Error GoTo Error_Handler
vntError = “” ‘ make sure vntError isn’t holding anything
Set objConnection = New ADODB.Connection ‘create Connection and Command object
Set objCommand = New ADODB.Command
下面的代码通过一个DSN,连接到数据库,
实现对数据库的操作:
‘ open a connection to the datasource
With objConnection
.ConnectionString = “DSN=ExpandingASP”
.CursorLocation = adUseClient
.Mode = adModeReadWrite
.Open
End With
一旦connection连接被创建,就用insert语句把UID和PWD
插入数据库中!
‘ add the UID
With objCommand
Set .ActiveConnection = objConnection /*建立连接*/
.CommandText = “INSERT INTO Authors(UID, PWD) VALUES(‘” & UID & “‘, ” & PWD & “);” /*sql命令*/
.CommandType = adCmdText /*设定执行的类型*/
.Execute
End With
Exit_Handler:
‘clean up
Set objCommand = Nothing
If objConnection.State = adStateOpen Then objConnection.Close /*把连接关闭*/
Set objConnection = Nothing /*清空连接*/
Exit Sub
Error_Handler:
vntError = Err.Description & ” (” & Err.Number & ” – ” & Err.Source & “)” /*vntError用于记录详细的错误信息*/
Resume Exit_Handler
End Sub
然后我们把这个dll用注册上去,如果完整的dll名为dbhandle
那么:regsvr32.exe C:\YourDir\dbhandle.dll
就可以用asp页面来测试了!
首先我们定义
Dim objAuthor ‘Custom Class (ActiveX Server)
Dim strError ‘Error String
这有助于我们以后调试找出错误。当然这不是必须的!
然后我们来创建对象(这里我们没有用到MTS)
Set objAuthor = Server.CreateObject(“ExpandingASP.Authors”)
objAuthor.Add Request.Form.Item(“txtUID”), Request.Form.Item(“txtPWD”), _
strError
如果发现strError不为空,表示objAuthor.add操作有问题,就显示错误信息
If len(strError) then
Response.Write “Error Saving Author: ” & strError
‘. . .
Response.End
End If
四。从 DCOM到COM+的发展
由Microsoft 公司推出的DCOM组件,全称是Distributed Component Object Model,是com
发展的新阶段.他扩展了组件对象模型技术,使其能够支持在局域网、广域网甚至Internet上不同计算机的对象之间的通讯。使用DCOM,你的应用程序就可以在位置上达到分布性,从而满足你的客户和应用的需求。 DCOM有些特征如:
1。位置独立性2.语言无关性3.可扩展性4.安全性5.协议的无关性等
DCOM的发展有利的推动了COM在网络环境中的发展,而目前最新的COM+不仅继承了COM,DCOM,和MTS的许多特征,同时也增加了一些新的服务,如内存数据库,事件模型,负载平衡等,这些新增的服务使的COM+变的异常的强大。
(这是笔者的大学毕业论文,现在为了赚分,把它贴了出来,简陋之处,请大家原谅)
指导老师:吴京慧
主要参考书籍与网站:
COM原理与应用 潘爱民 清华大学出版社 1999年
COM精髓 David S.Plaut 机械工业出版社 2000年
www.CSDN.net 程序员大本营
www.15seconds.com
>> 本文固定链接: http://www.vcgood.com/archives/1477