子煊 發表於 2019-8-22 09:25:00

Delphi COM对象

<p><span style="color: rgba(192, 192, 192, 1)">作者:巴哈姆特&nbsp; http://www.cnpack.org(转载请注明出处并保持完整)</span></p>
<p><span style="font-size: 16px"> 如果没有接触过COM对象的话,你会觉得接口真的很麻烦,也许会有:“还不如直接定义一个类更方便”的想法。</span></p>
<p><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;的确,没有经过COM封装的接口确实比较麻烦。在我看来,没有经过COM封装的接口似乎没有存在的意义。那么,什么是COM对象呢?它有什么优点呢?接下来开始对COM对象进行一个简单的介绍:</span></p>
<p><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;COM是个二进制规范,它与实现的语言无关。这样,即使COM对象由不同的编程语言创建,运行在不同的进程空间和不同的操作系统平台,这些对象也能相互通信。COM既是规范,也是实现,它以COM库的形式提供了访问COM对象核心功能的标准接口以及一组API函数,这些API函数用于创建和管理COM对象。COM本质上仍然是客户服务器模式。客户(通常是应用程序)请求创建COM对象并通过COM对象的接口操纵COM对象。服务器根据客户的请求创建并管理COM对象。当然,客户和服务器这两种角色并不是绝对的。</span></p>
<p><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;记得我在刚刚接触COM对象的时候,我师傅曾经给我说过:“COM不是Dll,虽然它可能会以后缀名为dll文件呈现在你面前,但是它绝对不是我们传统意义上所说的dll(动态链接库)”。</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;其实在我看来,进程内的COM对象应该是一个以dll为载体而提供一些特殊服务的特殊的动态链接库。当然,也有进程外的COM。</span></p>
<p><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;现在,我们演示怎么在Delphi中利用向导建立一个简单的COM模型。</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;首先:打开Borland Delphi 7.1(不好意思,我一般都是用这个版本。什么?为什么是7.1?就是7.0加个Update1补丁包嘛-_-||)。</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;然后:把Delphi默认为我们创建的Application关掉,并在菜单中选择File-&gt;New-&gt;Other,之后在弹出的窗口中找到ActiveX页,双击ActiveX Library图标。</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;双击图标后,我们可以看到Delphi已经帮我们建立了一个ActiveX库,代码如下:</span></p>
<p><span style="font-size: 16px">library Project1;</span></p>
<p><span style="font-size: 16px">uses</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;ComServ;</span></p>
<p><span style="font-size: 16px">exports</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;DllGetClassObject,&nbsp;&nbsp;&nbsp;&nbsp;// 返回类工厂的接口</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;DllCanUnloadNow,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 是否可以释放该组件</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;DllRegisterServer,&nbsp;&nbsp;&nbsp;&nbsp;// 注册函数</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;DllUnregisterServer;&nbsp;&nbsp;// 反注册函数</span></p>
<p><span style="font-size: 16px">{$R *.RES}</span></p>
<p><span style="font-size: 16px">begin</span><br data-filtered="filtered"><span style="font-size: 16px">end.</span></p>
<p><span style="font-size: 16px">我们会看到,在工程中,Delphi已经帮我们定义好了四个输出函数(关于这几个函数更详细的说明,可以查阅更多的资料),我们先不管它们。</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;接下来,我们再使用菜单File-&gt;New-&gt;Other并在ActiveX页中创建Com Object,这时,我们可以看到一个对话框:其中ClassName是我们的对象名、Instancing是对象创建模式、Threading Module为线程模式。我们使用NewComServer作为对象名,其他默认。OK后可以看到一个标题为“Project11.tlb”的窗口,这个我们可以在这个窗口中为接口添加新的方法,例如我们添加一个GetMessage方法。然后我们打开Unit1.pas可以看到如下代码:</span></p>
<p><span style="font-size: 16px">unit Unit1;</span></p>
<p><span style="font-size: 16px">{$WARN SYMBOL_PLATFORM OFF}</span></p>
<p><span style="font-size: 16px">interface</span></p>
<p><span style="font-size: 16px">uses</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;Windows, ActiveX, Classes, ComObj, Project1_TLB, StdVcl;</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;// Project1_TLB 接口所在单元</span></p>
<p><span style="font-size: 16px">type</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;TNewComServer = class(TTypedComObject, INewComServer)</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;// 实现接口的类</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;protected</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;function GetMessage: HResult; stdcall;</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 我们刚刚添加的方法</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;{Declare INewComServer methods here}</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;end;</span></p>
<p><span style="font-size: 16px">implementation</span></p>
<p><span style="font-size: 16px">uses ComServ;</span></p>
<p><span style="font-size: 16px">function TNewComServer.GetMessage: HResult;</span><br data-filtered="filtered"><span style="font-size: 16px">begin</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;MessageBox(0, \'测试\', \'提示\', $40);</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;Result:= GetLastError; // 我添加的代码</span><br data-filtered="filtered"><span style="font-size: 16px">end;</span></p>
<p><span style="font-size: 16px">initialization</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;TTypedComObjectFactory.Create(ComServer, TNewComServer, Class_NewComServer, ciMultiInstance, tmApartment);</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;// 类工厂</span><br data-filtered="filtered"><span style="font-size: 16px">end.</span></p>
<p><span style="font-size: 16px">之后,我们编译这个工程(CTRL+F9)将会生成一个Project1.dll文件。保存并关闭这个工程。</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;接着,我们编写一段代码来测试这个COM工程:创建一个普通的应用程序工程,并引用Project1_tlb单元:</span></p>
<p><span style="font-size: 16px">var // 注意,在测试代码中也需要引用project1_tlb单元,由于我们的接口声明在该单元内</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;NewComObject: INewComObject; // 声明接口</span><br data-filtered="filtered"><span style="font-size: 16px">begin</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;NewComObject:= CreateComObject(CLASS_NewComObject) as INewComObject; // 创建COM对象,</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;//CLASS_NewComObject 的定义可以在Project1_tlb.pas里找到</span></p>
<p><span style="font-size: 16px">&nbsp;&nbsp;if NewComObject &lt;&gt; nil then</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;begin</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NewComObject.GetMessageInfo; // 调用接口中的方法</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NewComObject:= nil; // 释放接口</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;end</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;else</span><br data-filtered="filtered"><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;ShowMessage(\'对象创建不成功\');</span><br data-filtered="filtered"><span style="font-size: 16px">end;</span></p>
<p><span style="font-size: 16px">注意我们在运行这个EXE之前,需要先把我们之前的COM工程注册给系统:开始-&gt;运行-&gt;regsvr32.exe \"...Project1.dll\"。看到注册成功的提示信息后,我们现在可以运行我们刚刚编写的那个测试程序来测试我们的COM对象了,看看执行测试代码后,是否弹出了一个标题为“提示”,内容为“测试”的对话框呢?</span></p>
<p><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;我们可以看到,在COM组件创建好以后,在EXE调用的时候是相当简单的,而且,当我们某个方法的实现细节发生改动,只要方法声明不变,那么在软件升级的时候,我们可以只升级我们需要升级的COM组件,而不需要改动其它的地方。这样可以有效的减轻维护的工作量。</span></p>
<p><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;当然,这个演示只是一个进程内的COM,至于更详细的说明,可以去参阅更多的资料。</span></p>
<p><span style="font-size: 16px">&nbsp;&nbsp;&nbsp;&nbsp;友情提示:ActiveX是Windows下实现COM的一个组件规范。请不要把ActiveX和COM之间划上等号!</span></p>

</div>
<div id="MySignature" role="contentinfo">
    博客园 滔Roy https://www.cnblogs.com/guorongtao 希望内容对你有所帮助,谢谢!<br><br>
来源:https://www.cnblogs.com/guorongtao/p/11392506.html
頁: [1]
查看完整版本: Delphi COM对象