使用COM对象,本论坛中就有,
在离线库里一下就找到了,给你铁一下
蚯蚓 (2000-05-21 22:54:00)
关于使用COM对象的方法,以Microsoft Word为例,作简要说明:
Step0: 从Word的类型库(Type Library)文件生成声明文件(xxx_TLB.pas),
要使用自动对象,必须先读取相应的类型库文件(*.TLB),从其中得到自动对象的类型信息,
方法:在Delphi IDE中打开....../Microsoft Office/Office/M$Word8.olb
Delphi将根据类型库中的信息生成声明单元Word_TLB.pas,
注意,Delphi在转换过程中将以下符号(symbol)进行了重命名(rename):
--------------------------------------------------------
类型库中的符号 重命名为
--------------------------------------------------------
Application WordApplication
Document WordDocument
Font WordFont
ParagraphFormat WordParagraphFormat
OLEControl WordOLEControl
LetterContent WordLetterContent
--------------------------------------------------------
这个问题后面会详细讨论
Word_TLB.pas中包含的如下信息:
...
...
const
...
//coClass "Application" 的ClassID
CLASS_WordApplication: TGUID = '{000209FF-0000-0000-C000-000000000046}';
...
...
...
我们也将在后面用到
蚯蚓 (2000-05-21 22:56:00)
Step1: 创建WordApplication对象,如下:
函数CreateCOMObject将根据指定的ClassID创建对应的COM自动对象,声明如下:
//unit COMObj
function CreateCOMObject(const ClassID: TGUID): IUnknown;
在本例中,我们创建WordApplication对象的代码如下:
// 引用COMObj单元和Word_TLB单元
uses
..., ..., ..., COMObj, Word_TLB;
type
TfmMain = class(TForm)
...
...
private
// 声明一个变量,保存WordApplication的引用
// WordApplication在Word_TLB单元中声明
WordApp: WordApplication;
protected
procedure StartWordApp;
procedure TerminateWordApp;
end;
其中StartWordApp方法将分别创建一个WordApplication对象,
实现如下:
procedure TfmMain.StartWordApp;
begin
if not Assigned(WordApp) then
try
// 创建WordApplication对象
WordApp:=CreateCOMObject(CLASS_WordApplication) as WordApplication;
with WordApp do
begin
// 指定COM对象的属性
Caption:='This copy of WinWord is launched by '+Forms.Application.ExeName;
Visible:=True;
end;
ShowMsg('启动 Word Application 成功');
except
ShowError('启动 Word Application 失败');
end;
end;
procedure TfmMain.btStartWordAppClick(Sender: TObject);
begin
StartWordApp;
end;
soul (2000-05-21 22:58:00)
????????什么意思??????
蚯蚓 (2000-05-21 23:00:00)
Step2: 创建WordApplication对象后就可以使用其属性和方法了,如下:
// 创建新文档
procedure TfmMain.btNewDocClick(Sender: TObject);
var
DocTemplate,
NewTemplate : OleVariant;
begin
StartWordApp;
DocTemplate := UnAssigned; // 打开新文档时使用的模板
NewTemplate := False; // 是否将文档作为模板打开
WordApp.Documents.Add(DocTemplate,NewTemplate);
end;
// 关闭当前文档
procedure TfmMain.btCloseDocClick(Sender: TObject);
var
SaveChanges,
OriginalFormat,
RouteDocument : OleVariant;
begin
SaveChanges := WdDoNotSaveChanges; // 不保存修改
OriginalFormat := UnAssigned; // 未赋值
RouteDocument := UnAssigned; // 未赋值
WordApp.ActiveDocument.Close(SaveChanges,OriginalFormat,RouteDocument);
end;
蚯蚓 (2000-05-21 23:04:00)
Step3:COM对象使用完毕后,注意释放
TerminateWordApp方法将释放WordApp指向的COM对象,
实现如下:
procedure TfmMain.TerminateWordApp;
var
SaveChanges,
OriginalFormat,
RouteDocument : OleVariant;
begin
if Assigned(WordApp) then
begin
SaveChanges := WdDoNotSaveChanges; // 不保存修改
OriginalFormat := UnAssigned; // 未赋值
RouteDocument := UnAssigned; // 未赋值
try
// 调用COM对象方法
WordApp.Quit(SaveChanges,OriginalFormat,RouteDocument);
ShowMsg('关闭 Word Application 成功');
except
ErrorMsg('关闭 Word Application 失败');
end;
// 将WordApp赋值为Nil,则原来指向的COM对象的引用记数减1
// 当引用记数为0时,COM对象将被释放
WordApp := Nil;
end;
end;
procedure TfmMain.FormDestroy(Sender: TObject);
begin
TerminateWordApp;
end;
soul (2000-05-21 23:05:00)
sorry!
soul (2000-05-21 23:06:00)
可惜没有收藏夹。
soul (2000-05-21 23:08:00)
估计很快会被hubdog收藏到葵花宝典里
蚯蚓 (2000-05-21 23:08:00)
后记:
1、以上所述方法是完全通过编程直接调用COM实现的,
所有使用COM的地方都可以通过上面的方法实现,
步骤为:
(0)根据类型库文件生成声明单元
(1)得到需要的ClassID后使用CreateCOMObject函数创建COM对象
(2)使用COM对象的属性和方法完成操作
(3)释放COM对象
2、我们的目的不仅仅是为了控制Word,而是为了说明使用COM的根本方法,
选择Word作为例子,是因为大家都比较熟悉,
对Word的控制,Delphi已经提供了一些支持,包括:
....../Delphi5/Ocx/Servers/Word97.pas
等于前面所说的Word_TLB.pas,
....../Delphi5/Demos/Activex/Oleauto/Word8/autoimpl.pas
将以上对COM对象的操作封装成了一个Delphi类
还可以参考两个示例:
....../Delphi5/Demos/Activex/Oleauto/Word8/word8auto.dpr
和
....../Delphi5/Demos/Activex/Oleauto/SrvCOMp/Word/pwordCOMp.dpr
3、一般情况下会同时提供很多COM Server,
应该使用什么对象、使用什么方法、使用什么属性
需要参考帮助文件,上面的例子中M$Word8.olb的帮助文件为:
..../Microsoft Office/Office/VBAWRD8.HLP
在没有帮助文件的情况下就需要研究类型库中的信息了
4、关于类型库本身
类型库包含非常丰富的信息,包括:
Interface、DispInterface、CoClass、Enumeration、
Alias、Record、Union、Module等等
这些是类型库的基本信息,此外还包括:
指定的帮助文件、所依赖的其它类型库等等
类型库一般以单独的类型库文件(*.TLB)提供,或包含在Server程序中(*.EXE、*.DLL)
类型库信息包含在EXE中的例子有:
..../Delphi5/Demos/Activex/Oleauto/Autoserv/memoedit.dpr
在DLL中的例子有:
..../Delphi5/Bin/StdVcl40.DLL
这两种情况下,实际上类型库信息都包含在EXE/DLL中的名为"TypeLib"的资源中
查看M$Word8.OLB可以看到,它实际上是一个DLL格式文件
5、关于类型库的Register和Unregister
Windows下有注册类型库的程序RegSvr32.exe,Borland自己也有TRegSvr.exe
除此之外,在Delphi IDE中打开类型库后,可以使用菜单Run|Register ActiveX Server
或Run|Unregister ActiveX Server
那么类型库的Register和Unregister具体是怎么实现的呢,
打开..../Delphi5/Demos/Activex/TRegSvr/TRegSvr.dpr,查看源代码,我们可以看到:
(1)对于*.tlb:
调用OleAut32.DLL中的LoadLibrary函数,得到一个ITypeLib接口,
调用ITypeLib的GetLibAttr方法,得到tagTLibAttr结构,其中包括
GUID、LCID、Major Version、Minor Version、SysKind信息
Register的方法是:
调用OleAut32.DLL中RegisterTypeLib函数
Unregister的方法是:
调用OleAut32.DLL中UnregisterTypeLib函数,参数由前面的tagTLibAttr结构中各域指定
详见TRegSvr.dpr中的RegisterTLB过程
(2)对于*.dll:
调用LoadLibrary函数载入dll
Register的方法是:
调用DLL中的DllRegisterServer函数
Unregister的方法是:
调用DLL中的DllUnregisterServer函数
(3)对于*.exe
Register的方法是:
调用EXE,命令行参数为"/RegServer"
Unregister的方法是:
调用EXE,命令行参数为"/UnregServer"
也就是说,对于DLL和EXE,应该实现自注册(Self Register),
即ActiveX Server本身完成Register和Unregister动作。
对于Delphi编写的ActiveX Server,这些工作都在COMServ.pas完成,
详细的过程比较罗嗦,有兴趣可以去看看,
主要的代码在RegisterTypeLibrary和UnregisterTypeLibrary过程中
和上面的TRegSvr.dpr中对TLB的注册过程大致一样
经过上面的分析可以看到,最终都是通过OleAut32.DLL中的
RegisterTypeLib和UnregisterTypeLib完成的,
我们注意到一点奇怪的现象:
上面提到的源代码在调用RegisterTypeLib时都是直接调用,
该函数的声明在ActiveX.pas中,指定到OleAut32.DLL中的RegisterTypeLib函数
就在相同的地方,我们也看到了UnregisterTypeLib的声明,
但是,上面提到的源代码在调用UnregisterTypeLib时都没有直接调用,
而是先GetModuleHandle('OLEAut32.DLL'),然后用GetProcAddress查找UnregisterTypeLib,
再根据查找的结果进行调用
而且所有相关的地方都是这样进行,估计不是失误,这样看来,
似乎Borland在写这段程序时考虑到了OLEAut32.DLL中不包括UnregisterTypeLib函数的情况,
难道OLEAut32.DLL的早期版本中的确不包括UnregisterTypeLib函数??
但M$DN对UnregisterTypeLib的说明没有提到
6、关于打开类型库时符号重命名(symbol rename)
类型库中某些符号在生成声明单元时被重命名,
大部分是因为符号名与Pascal关键字重名,因此Delphi必须重命名
但前面说到的几个符号的重命名显然不是这个原因,我们注意到:
(1)这几个符号都是CoClass,而且是类型库中几乎全部的CoClass,
只有一个CoClass:"Global"不在其中
(2)这几个符号被重命名后都加上了"Word"前缀,
而这个类型库的名称正好就是"Word"
其中是否存在联系??
7、对于任意的一个CoClass,从类型库中可以得到其中的interface信息,
因此创建和释放COM对象的代码可以自动生成,
对于所有的interface,也可以从类型库中得到其属性、方法信息,
因此访问这些属性、方法的代码也可以自动生成
由此,Delphi 5 将在声明单元中为所有的CoClass
创建相应的代理类(OLE Server Proxy class),
这些代理类以Delphi类的形式提供封装,而内部实现了对COM对象的全部操作,
包括创建、释放以及访问各种属性和方法
另外,Delphi 5还会将这些代理类作为组件注册到组件板的'Server'页面上
详情请在xxx_TLB.pas中查找"OLE Server Proxy class"
通过这些代理类,我们可以很方便地使用COM对象,
而不必向上面所说的那样一切都通过自己实现,
当然,前面所说的是一切的基础,应该作为原理了解
soul (2000-05-21 23:12:00)
所以,象这样的帖子是否可以让出题人选出关键贴,然后在加一个显示并发送此贴精华呢?
沈前卫 (2000-05-21 23:28:00)
不错,不错,就是这类文章太少了。
白马小将 (2000-05-22 0:07:00)
听君一席话,胜读十年书。
蚯蚓 (2000-05-23 23:00:00)
<font color=darkgreen><b>版权没有
欢迎转载
</b></font>
adminis (2000-05-23 23:20:00)
哈哈,这个死蚯蚓,化成灰我也认得你。
在网上水平又高,又不贪财的有几个?
你是不是名望太高怕惹人耳目?
所以改做幕后工作?
佩服佩服。
蚯蚓 (2000-05-23 23:25:00)
这篇是我自己写的,
起因是几个月前有个家伙问我COM对象该怎么调用,
于是我就打开类型库看啊看啊。。。。。
最近还看到几篇好文章,很适合入门者,可惜是E文的,
打算熬几夜翻译出来,再贴给大家看。。。
amo (2000-05-24 0:07:00)
钦佩,
本来上次参与sonie的题目对COM也有了一点了解,
也想写点心得,
不过总是瞎忙这瞎忙那,
最后没写
到底是earthworm,
在地下勤勤恳恳
向你学习,
不过我就不钻到地下去的;-)
avant (2000-05-24 19:40:00)
太好了,谢谢,还有吗?
继续关注!
小虎 (2000-05-25 12:03:00)
终于忍不住贴上来了。
不过,我最后还是用别的方法搞定的。
等哪天有空,写出来给你看
蚯蚓 (2000-05-25 23:22:00)
>> 终于忍不住贴上来了
实在是闲的无聊啊, 没办法
再说了,人都是有表现欲的嘛,
你难道没写过 'xxx到此一游' ?
乾隆老爷子不也写了一万多首"诗"??
cheka (2000-05-25 23:54:00)
大富翁真应该有个精华区的,放一些非FAQ的专题文章.
网易广州社区的C版精华区就狠酷.
沈前卫 (2000-05-26 2:04:00)
精华区没多大必要,还是学习学习ex-ex,限制人的发言权,注册为专家才分发言,
答错以红色显示,专家分不能用来提问。
蚯蚓 (2000-06-07 13:48:00)
接受答案了.
沈前卫的回答最终被接受。