1、应用COM和接口第六讲 应用COM和接口前面我们已经说明,.NET战略的一个重要方面,就是弱化COM的应用,这似乎是说,我们不再需要研究COM了,但事实并非如此,其中一个重要的原因,是COM已经流行了十年,而且,COM也是微软和其它众多软件开发的基础,更不用说,.NET平台本身还使用了COM+技术。基于这一系列的原因,我们不得不来研究在.NET中应用COM和接口的有关问题。在这一讲里,我们将首先对COM做一个简要的回顾,其实COM的问题并不太复杂,但是令人费解的是,很多软件方面的著作,都把COM作为一个重要的主题来研究,其实这是没有太多的必要的。我们研究这一讲的内容的时候,首先要记住的是,在很
2、大程度上.NET是从COM演变来的,按照进化的观点,COM类似于Lucy(古埃塞俄比亚的南猿),所以如果它显得比较笨的话,你不要太介意,因为没有笨拙的COM,就没有流畅的.NET。一、 COM简介COM(Component Object Model )也就是组件对象模型,是微软为编程创建语言独立性所做的第一次好的尝试。COM 是一种用于说明如何建立软件组件的规范,由于使用了统一的接口规范,不同的开发人员创建的COM 组件,可被组合进不同的应用程序中,而且这些COM 组件所使用的语言,可以是完全不同的。例如,你可以在VC+程序中调用VB组件,反之亦然。这对于一个开发软件的集体来说,是有很大的意义
3、的。 DCOM(Distributed Component Object Model)分布式组件对象模型,这是一种分布式应用程序集成到网络的技术,一个分布式应用程序由多个进程组成,这些进程协作完成一项工作。 DCOM为COM 组件之间的通信透明的提供可靠、安全和有效的支持,这些组件包括ActiveX ,脚本和Java小程序。DCOM可将其应用程序分布到最适合于其顾客和应用程序的位置。在很大程度上,DCOM是带宽、部署和防火墙问题的综合,所以也就决定了它不会为太多的人所认可。际上并不知道自己在开发COM对象。讨论这个问题的意义在于,假定一个企业的系统,已经长期的很好的使用一个COM对象,现在,企
4、业系统要用.NET升级,这就面另两个选择:第一种,一切重新开始,用新的平台特性,开发新的内容,当然这是很好的,但有时候并不一定合算。第二种,一些经过考验被认为合理的组件,还可以在.NET平台上使用,这将会大大减少开发时间和难度,我们下面要讨论的就是这种方法。我们首先在VC+中开发一个COM组件,然后讨论在.NET上的应用问题。二、在C+中开发COM组件VC+ 一直是专业开发人员最青睐的语言之一,现在的VC+.NET,不但保留了原来的VC+ 6.0的能力,而且还提供的平台托管代码的编写能力,可谓如虎添翼。这里主要利用VC+开发标准的COM组件,然后用C#调用。开发COM组件,首先必须生成四个标准
5、函数:DllRegisterServer:实现在注册表中注册COM服务的功能。 DllUnregisterServer: 和上面的功能刚好相反,实现在注册表中注销的功能。DllCanUnloadNow: 用来检测是否可以从内存中卸载COM服务器。如果COM客户第一个调用COM服务,系统会自动把COM服务载入内存,但又有客户访问COM服务的时候,只是增加COM服务被调用的计数,当计数为0时,则自动卸载。DllGetClassObject:返回COM类对象的指针。 COM技术的原理是比较复杂的,好在VC+提供了活动模板库(ATL),可以帮组我们完成标准的框架部分,我们只要关心我们必需处理的属性和方
6、法就可以了。下面讨论一个最简单的例子,但是这个例子表达了VC+生产COM组件最重要的要素,通过这个例子,更复杂的东西也能够做出来。首先生成一个ATL项目。名字为:myCom 因为要处理字符串(CString),所以选择支持MFC。这里不需要属性化。 添加一个类。 选择:ALT简单对象。 给对象恰当的名字。注意,对象可以有多个。名字为:MyShow 添加一个属性:Name,返回值为BSTR。这是可以在COM对象之间传递的字符串格式。 添加方法:HelloiWorld。主要目的是把Name属性的字符串处理以后输出。参数为:BSTR*,这表达一个输出的字符串指针。 加入一个求和方法:Sum注意:返回
7、类型必须是HRESULT,真正的返回值是在参数属性中选择“类型*”(指针),然后,选择retval。不选则为void。in,表达为传入值,一般用值类型。out 为参数表的传出值(out),调用的时候必须out, retval为返回值。 乘法:Multiply 同样的方法,加入乘法的方法:Multiply 处理代码,文档:MyShow.cpp/保留属性的值。/因为要处理汉字,这里使用CStringW/此外还有CString、CStringACStringW strName;STDMETHODIMP CMyShow:get_Name(BSTR* pVal) AFX_MANAGE_STATE(Afx
8、GetStaticModuleState(); / TODO: 在此添加实现代码 /返回值,注意CString向BSTR的转换 *pVal=strName.AllocSysString(); return S_OK;STDMETHODIMP CMyShow:put_Name(BSTR newVal) AFX_MANAGE_STATE(AfxGetStaticModuleState(); /传入值 strName=newVal; / TODO: 在此添加实现代码 return S_OK;STDMETHODIMP CMyShow:HelloWorld(BSTR* s) AFX_MANAGE_STA
9、TE(AfxGetStaticModuleState(); / TODO: 在此添加实现代码 /注意,字符串是如何拼接的 CStringW message(你好,你的名字是: ); message+=strName; *s=message.AllocSysString(); return S_OK;STDMETHODIMP CMyShow:Sum(DOUBLE x, DOUBLE y, DOUBLE* s) AFX_MANAGE_STATE(AfxGetStaticModuleState(); / TODO: 在此添加实现代码 /注意,如何把处理的结果返回 *s=x+y; return S_O
10、K;STDMETHODIMP CMyShow:Multiply(DOUBLE x, DOUBLE y, DOUBLE* s) AFX_MANAGE_STATE(AfxGetStaticModuleState(); / TODO: 在此添加实现代码 /同样要把处理的结果返回 *s=x*y; return S_OK;生成的时候同时注册。 必要的时候,可以人工注册和卸载: Regsvr32/s .DLL -注册 Regsvr32/u .DLL -注销在.NET中应用。 myComLib.IMyShow obj=new myComLib.MyShowClass(); /加法 private void
11、button1_Click(object sender, System.EventArgs e) textBox3.Text=obj.Sum(double.Parse(textBox1.Text),double.Parse(textBox2.Text).ToString(); /减法 private void button2_Click(object sender, System.EventArgs e) textBox3.Text=obj.Multiply(double.Parse(textBox1.Text),double.Parse(textBox2.Text).ToString();
12、/写属性 private void button3_Click(object sender, System.EventArgs e) obj.Name=textBox1.Text; /读属性 private void button4_Click(object sender, System.EventArgs e) textBox3.Text=obj.Name; /调HelloWorld private void button5_Click(object sender, System.EventArgs e) textBox3.Text=obj.HelloWorld(); 结果应该是没有问题的。
13、三、在Delphi中开发COM组件很多语言都有生成COM组件的能力,下面做一个Delphi的例子。1新建ActiveX库file - new - other - ActiveX - ActiveX LibrayOK产生一个项目文件 DllGetClassObject, DllCanUnloadNow, DllRegisterServer, DllUnregisterServer;2创建COM对象File - new -Other -ActiveX -COM objectOK类对话框:输入类名:比如MyShow出现一个统一的类生成器:IMyShow -接口MyShow -实现这个接口的对象在IM
14、yShow 右键 -New - Property 添加一个属性,Name名字起为:Name 再添加一个方法:Method Name名字起为:HelloName关于属性,一般的形式是: protected function Get_name: WideString; stdcall; procedure Set_name(const Value: WideString); stdcall; end;.function TMyShows.Get_name: WideString;beginend;procedure TMyShows.Set_name(const Value: WideString
15、);beginend; 也就是说返回的是function,进入的是procedure。当使用字符串的时候(WideString),对应的为BSTR。 为了达到这个目的,在建立属性的时候,要注意: Get:Type-BSTR Parameters-删除 set: Type-Void Parameters-Value BSTR in 这样就能造成上面的效果。 refresh-刷新 形成程序的框架,并在框架中写入自己的内容: 具体处理的程序可以这样写: var Username:string; function TMyShows.Get_name: WideString; begin Result
16、:= WideString(Username); end; procedure TMyShows.Set_name(const Value: WideString); begin Username := String(Value); end; 关于方法,去掉返回值就是过程,否则是函数: procedure TMyShows.helloName; begin showmessage(您的名字是:+ Username); end; 这里要注意一个问题,messagebox(0,mb_ok)和showmessage()需要Dialogs 库,需要把它Uses进来。 完成的源程序如下: -unit U
17、nit1;$WARN SYMBOL_PLATFORM OFFinterfaceuses Windows, ActiveX, Classes, ComObj, Project1_TLB, StdVcl,Dialogs;type TMyShows = class(TTypedComObject, IMyShows) protected function Get_name: WideString; stdcall; procedure Set_name(const Value: WideString); stdcall; procedure helloName; stdcall; end;imple
18、mentationuses ComServ;var Username:string;function TMyShows.Get_name: WideString;begin Result := WideString(Username);end;procedure TMyShows.Set_name(const Value: WideString);begin Username := String(Value);end;procedure TMyShows.helloName;begin showmessage(您的名字是:+ Username);end;initialization TType
19、dComObjectFactory.Create(ComServer, TMyShows, Class_MyShows, ciMultiInstance, tmApartment);end.-File - Save all 保存Project - Build 编译Run - Register ActiveX Server 注册3)注册和注销组件 使用COM 组件以前,先要确认它在计算机上是可以使用的,所以必须注册,注册DLL 有两种方法:1 在delphi中编译DLL ,编译的同时自动在所编译的计算机上注册,(文件 - 生成工程.DLL)。2使用Regsvr32.exe(在Windowssys
20、tem中,或WINNTsystem32中 ),方法:Windows开始 - 运行 Regsvr32/s .DLL -注册 Regsvr32/u .DLL -注销比如上面的例子:Regsvr32 “d:MyShow Helloname.dll” 注册是注册在系统注册表中,所以也可以用regedit.exe来查看,对于注销组件,可以在系统注册表中删除该组件的引用,然后再删除该组件的DLL或EXE 文件。注意:COM 类的注册表条目位于系统注册表的HKEY_CLASSES_ROOT中。四、在.NET中应用COM组件首先建立一个Windows工程。 Project1.MyShow obj=new Pr
21、oject1.MyShowClass(); private void Form1_Load(object sender, System.EventArgs e) private void button1_Click(object sender, System.EventArgs e) obj.Name=textBox1.Text; private void button2_Click(object sender, System.EventArgs e) obj.HelloName(); 可以看出来,和普通的类使用上是一样的。 五、Activex控件 ActiveX 控件 是充分利用OLE和Ac
22、tiveX 技术的自定义控件。 ActiveX 控件是基于与应用程序无关的思想而设计的。 可以简单的认为ActiveX 控件合并了VBX 技术和ActiveX 标准。VBX是Visual Basic提出的一个技术标准。Microsoft 的Visual Basic 是第一个引入向市场供应软件组件构想。但软件组件重复性使用的概念是早于Visual Basic 提出的,而且它早已根植于面向对象编程的理论中。 Visual Basic 提出了组件的概念,定义了建立与描述新控件的标准方式。 Visual Basic 提出的第一个技术标准是VBX。这是16位版本Delphi中完全可以使用的一个16位标准
23、。在32位的操作平台中,Microsoft 使用了功能更强,更为开放的Activex控件来代替VBX标准。 ActiveX控件的结构 ActiveX控件的好处在于它的可编程性和可重用性。它能够嵌入到目前大多数的开发环境中,包括Delphi、Visual Basic、Oracle、Developer 2000等。它在这些开发环境中的表现,和Delphi的组件在IDE环境中的表现完全相同,都有自己的属性、方法和事件。ActiveX控件最理想的用途是在网上作为传送小型程序的载体。 何时使用ActiveX控件 没有可用的Delphi组件能满足你特殊的需要。 你想使用多中编程语言进行开发,想在多个开发平
24、台之间共享一些控件。 ActiveX控件的缺点 最明显的问题是,Delphi组件能够直接内建到应用程序的可执行文件中,直接与应用程序和其他组件进行通信的;但ActiveX控件是通过COM与应用程序通信的。ActiveX控件是一种“最小公分母”的解决方案,因而没有完全挖掘出开发工具的能力。 第一个自制的ActivX控件 希望做一个ActiveX控件,能显示系统时间,同时显示的周期可以由外部参数控制。 一、首先清空Form; 二、File-New-Other-ActiveX-Active Form -Ok 三、其中遇到 New ActiveXName:自己给控件起名; 比如这里写上Showtime
25、。 下面的多选框选择可选可不选。 这样就产生了三个单元,其中第三个是类库(TLB),一般不要动。 四、在System页 -加入 Timer Standard页-加入 Label(改变字体和字号) 五、Timer的Interval属性定为1000,表示每隔1000毫秒触发一下。给 Timer 的 Timer1Timer 事件加一句显示系统时间: label1.Caption:=timetostr(Time); 六、现在要给控件增加一个属性,用外部数据来控制触发间隔,也就是Timer的Interval属性。 菜单-Viwe-type Library-可以看到Form的属性 增加属性: New pr
26、oporty(注意是图标)-Name:属性的名字。 如果是可读写的,就有两个属性函数,一个是Get,另一个是Set。 刷新(Refresh Implementation)后在ShowtimeImpl1单元里可以看到两个get函数和set过程,把相应的程序写进去。var i:integer;procedure TShowtime.Button1Click(Sender: TObject);beginif i=1 thenbegin Panel1.Color:=clRed; i:=0;endelsebegin Panel1.Color:=clGreen; i:=1;end;end;function
27、 TShowtime.Get_mytime: Integer;begin result:=timer1.interval;end;procedure TShowtime.Set_mytime(Value: Integer);begin timer1.interval:=value;end; 七、在project-build进行编译、保存。 八、注册:Run-Register ActiveX Server -产生一个OCX 文件。 实际上一个Activex已经完成了。 注意一下,ActiveX控件有个新的属性AxBorderstyle-边界风格: 另外:mytime是自己给出的控制内部元件的属性
28、,这里是时钟的触发周期。 在.NET中使用这个控件。 可以看出来,由于COM接口的标准化,不管你是用什么语言写的COM组件,都可以很好的用在.NET系统里面,所需要注意的就是由于COM组件的特点,这些组件使用以前必须经过注册,否则无法使用。六、在.NET程序中使用Word微软的Office,是一套功能强大的办公软件,更重要的,它也是一套COM自动化系统,你可以在任何支持COM的语言体系中调用它的功能。首先引入Word的COM 组件在Microsoft Word 9.0 Object Libray。 Dim WOR As New Word.ApplicationClass() 定义公文 Dim
29、WOD As New Word.DocumentClass() Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click WOD = WOR.Documents.Add WOR.Caption = 我的标题栏 WOR.Options.CheckSpellingAsYouType = False WOR.Options.CheckGrammarAsYouType = False WOD.Sentences.Last.Paste() WOD.Range.InsertAfter(我的文字) WOD.Range.InsertAfter(其它的文字) WOR.Visible = True WOR.PrintPreview() = True WOR.Pri
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1