在Microsoft推出Windows NT4.0之后,以往只有在大型主机或者工作站上才可能出现的分布式处理终于可以在PC的世界中工作了。造成Windows NT可以成为企业计算环境除了NT的日渐成熟和执行效率增加以外,最重要的就是加入了DCOM(Distributed Component Object Mode1)的功能。Microsoft在NT4.0中第一次推出了该项技术,但是Microsoft很明显希望DCOM成为组件(Component)沟通的标准通信协议。所以接着推出了DCOM For Windows95,在其去年推出的Windows 98中更内置了DCOM,它代表着使用PC 环境也可以处理非常庞大和复杂的计算工作。通过该技术,PC级的程序员终于可以进入分布式对象的世界了。
一、 DCOM:分布组件对象模型
Microsoft 的COM模型能够让同一台计算机中的各种对象互相沟通和使用对方提供的服务,而DCOM则更进一步地让不同的应用程序和对象可以在网络中不同的计算机之间沟通。这意味着可以在应用程序中或者动态链接程序库中建立对象,并且提供这个对象的各种服务,然后在另外一台不同的机器中的应用程序可以调用这个对象的方法或者是访问它的属性值。DCOM为什么如此重要呢?因为目前软件发展的趋势是走向以组件为基础的分布式计算,而在不同的组件中需要一个相互沟通的通信协议。这就像PC中的各种适配器,它们是插在PCI和ISA等总线之上,通过总线和其他计算机组件进行沟通。组件也需要一个相互沟通的总线,使用一致的通信协议来沟通,而DCOM就是这种组件的总线。它负责各种组件之间的信息传递。如果没有DCOM,那么就达不到分布计算环境的要求。
DCOM是构造于COM之上的。在COM中,程序通过指定一个对象的ID(Class GUID)和要访问的接口ID,就能够访问这个对象的特定接口中的方法和属性。如图1所示。
图1 COM模型中访问对象接口中的方法或属性
从图1可以看出,在COM的基本模型中,不同的应用程序和对象之间可以通过指定对象和接口ID来取得对方的服务,但这种模型是发生在同一台计算机中。如果在A计算机中的应用程序或者对象希望访问在计算机B中的特定对象的服务,应该怎么办呢?在基本的COM模型中无法做到这一点,Microsoft用DCOM解决了这个问题。如图2所示:
图2 DCOM建立对象和接口的方法
从图2可以看出,在使用DCOM时和使用COM建立对象的方式是相同的,只需再加入一个机器名称的参数。如果在COM中是使用Windows API的CoGetClassObject建立对象的话,那么只需要再输入机器名称的参数即可在远程指定的计算机中建立对象,并且取得指定接口的信息。简单的说,DCOM是COM的延伸,它让对象和接口的建立可以跨越不同的机器,并且保持和COM的兼容性。它构造于RPC (Remote Procedure Call)的技术之上,并且使用TCP/IP作为网络通信协议。目前,NT4.0和Win98都直接支持DCOM,Win95中可以安装DCOM For Windows95来支持它。Microsoft对DCOM也在进行不断的完善,例如在NT4.0的 Server Pack 1、Server Pack 2、Server Pack 3 以及刚刚发布的Server Pack 4中,对DCOM的支持越来越好,其中在Server Pack 2中有一个DCOM非常重要的功能是开发N—Tier(多层)应用程序必须使用的。现在DCOM已经占据了非常重要的地位,Microsoft的SQL Server、Transaction Server、Message Queuing Server等都充分利用DCOM来进行企业中的分布式计算。DCOM也是Microsoft用来对抗CORBA(Common Object Request Broker Architecture)的武器之一。
二、 DCOM的使用
在很多面向对象的编程语言(如:Visual C++、Delphi、Visual Basic)中,编译器都使用Windows API的CoCreateInstance 建立COM或DCOM对象。事实上在一般的工具或中介服务器中(如:MS SQL Server等),建立COM或DCOM对象的标准方式是使用Windows API的IClassFactory。要使用这种方式建立DCOM对象,首先我们必须取得能够建立特定的DCOM对象的IClassFactory接口,再使用这个接口建立DCOM对象。
为了取得指定的 IClassFactory 接口,可以使用CoGetClassObject 这个API,Microsoft声明的该API的原型如下:
STDAPI CoGetClassObject(
REFCLSID rclsid,
DWORD dwClsContext,
COSERVERINFO * pServerInfo,
REFIID riid,
LPVOID * ppv
);
其中,第二、三两个参数非常重要。第二个参数可以使用如下数值:
typedef enum tagCLSCTX
{
CLSCTX_INPROC_SERVER_=1,从In-Proc Server 建立COM对象
CLSCTX_INPROC_HANDLER=2,从Out-Proc Server 建立COM对象
CLSCTX_LOCAL__SERVER=4,
CLSCTX_REMOTE_SERVER=16,使用DCOM从远
}CLSCTX 程机器中的Out-Proc
Server建立COM对象
从CLSCTX的声明中可以看到,只要在CoGetClassObject的第二个参数中使用CLSCTX_REMOTE_SERVER就可以从远程机器中建立COM和接口对象。
如果计算机的系统注册表中没有指明远程COM对象所在位置,那么在CoGetClassObject时,必须指定第三个参数的值。CoGetClassObject 的第三个参数在OLE1.X中是保留参数,Microsoft的文件说这个参数必须是NULL。但是到了OLE2X以后,由于必须支持DCOM,所以该参数被用来指定应用服务器的信息。该参数的原型如下:
typedef struct_COSERVERINFO
{
DWORD dwReserved1;
LPWSTR pwszName;指定应用程序服务器的名称
COAUTHINFO * pAuthInfo;安全验证信息
DWORD dwReserved2;
COSERVERINFO;
}
CoGetClassObject 配合此参数,就可以启动远程计算机中的COM对象。
三、 范例
假设现有一个如图3所示的应用系统结构:
在客户端的应用程序中需要建立位于LJSERVER机器中的COM对象,那么在客户端的应用程序中可以编写如下代码。
Var
ClassFactory:IclassFactory;
WideCharBuffer:array[..256] of WideChar;
Info:TcoServerInfo;
SwMachineName:WideString;
Begin
ClassFactory:=nil;
StringToWideChar (*LJSERVER*,PwideChar(swMachineName),256);
Info.PwszName:=PwideChat(sqMachineName);
OleCheck(CoGetClassObject(ClassID,CLSCTX_RE
MOTE_SERVER,@Info,IID_IclassFactory,ClassFactory);
If classFactory=nil then
ShowMessage(‘错误!无法建立 IclassFactory接口’)
Else
ClassFactory.CreateInstance(nil,IID_Iunknown,Unknown);
Try
Result:=Unknow;
Finally
ClassFactory.Release;
Unknown.Release;
End;
在上面的程序代码中使用了CLSCTX_REMOTE_SERV
ER和Tco ServerInfo 这两个参数用于建立LJSERVER这台计算机中的COM对象,并且取得它的IclassFactory接口。注意,在使用TcoServerInfo设置机器名称时,必须先把机器名称转换为WideChar,因为在NT中机器的名称是可以使用中文这种双字节名称的,例如LJSERVER也可以称为“鲁锦的服务器”,所以必须使用双字节。
在取得了ClassFactory接口之后,就可以使用它来建立这个接口可以产生的特定COM对象和接口。接下来的程序代码是取得这个ClassFactory能够建立的COM 对象的Iunknown接口,最后返回这个Iunknown接口。请注意,如果您使用的编程语言不支持COM接口,则不能直接把Iunknown接口指定给Result变量,就必须进行一定的转换。例如:Result:=VarFromInterface(Unknown)。
四、 DCOM的设置
最后讨论一下DCOM的设置。当在Windows95/98/NT中使用DCOM作为多层应用程序的通信协议时,必须注意DCOM的设置,以便能够顺利执行远程的应用服务器以及考虑安全性的问题。您可以使用DCOMCNFGEXE(它位于Windows95/98的System目录或是Windows NT的System32目录下)这个应用程序来调整DCOM应用程序的属性。
当启动DCOMCNFG后,它会显示目前机器中的Automation Server以及应用服务器,可以通过单击要设置的应用程序服务器来进一步设置它的属性。一般来说,建立了一个应用服务器后,它的“身份验证”是设置为“启动的用户”。这代表任何在这个域(Domain)有权的用户都可以使用他的帐号启动这个应用服务器。如果直接使用“启动的用户”,那么在客户端执行应用程序时,应用程序服务器若还没有在中介服务器中执行,应用服务器会被启动,但不会显示任何用户界面。但如果把“身份验证”设置为“交互性用户”,则应用程序服务器的用户界面就会在中介服务器中显示。但是要使用“交互性用户”,则客户端登录的用户必须在中介服务器中有帐号并且中介服务器是使用此帐号登录的,否则会出现访问错误。
当然你也可以设置应用服务器可以被什么人启动或访问。有关权限设置的其他详细信息,请参考Windows NT的权限管理的信息。