如何构造有层次结构的COM模型,和VBA中的Word对象结构一样的那种(200分)

  • 主题发起人 主题发起人 lofa
  • 开始时间 开始时间
L

lofa

Unregistered / Unconfirmed
GUEST, unregistred user!
我早就想做一个那样的有层次结构的Com组件集合了,一个组件的平面属性和方法是没有
问题,可以如何生成像OfficeVBA那样的层次结构呢?即Application对象有其他集合对象
,我现在用的是属性,属性类型是我定义的一个接口,比如Server.Sender属性是一个ISender
的接口,然后此属性只读,在生成Server的时候用 CoSender.Create生成一个对象,同时
将此对象的接口变量保存在Server的一个变量中FSender(ISender类型),然后在外部程序
请求Sender属性的时候返回FSender。
我想FSender是接口指针,只要有对象实例应该上是可以调用的,可是不行,不知道问题出
在什么地方,高手们请帮我一下。另外能不能谈谈你们自己的方法,说说都看什么书可以
获得这些知识。ISender是继承自IDispatch
 
小弟也是初学的哈,把这类问题的个人处理方法跟大家探讨一下,
还请促各位大侠多多指教:

不知你有没有看过 OfficeVBA 这些东西的类型库?我把 AutoCAD 的类型库(应该说是
由类型库引入的接口文件)看了一下,
再做了一个简单的实验,如下:
//////////
// 这是接口定义单元
unit Unit2;

interface

type
///////////////////////////
// 单个 Sender 接口的声明, 只定义了一个属性。
ISender = interface
function Get_Name:widestring;safecall;
property Name: widestring read Get_Name;
end;
// 实现类。。
TSender = class(TInterfacedObject, ISender)
private
FName: widestring;
public
constructor Create(const nm : Widestring);
function Get_Name:widestring;safecall;
end;
////////////////////////////////
// sender 接口集合的声明, 这里就是一般的 Automation 服务器构造他们的
// 层次结构的接口的形式,
ISenders = interface
function Item(index: oleVariant):Isender;safecall;
function Add(NM: widestring):ISender;safecall;
// 属性 Count 表示 当前共有多少个 ISender
function Get_Count:OleVariant;safecall;
property Count: OleVariant read Get_Count;
end;
// 实现
TSenders = Class(TInterfacedObject, ISenders)
private
FSenders: array of ISender;
FCount: cardinal;
public
constructor Create;
function Item(index: oleVariant):ISender;safecall;
function Add(NM: widestring):ISender;safecall;
function Get_Count:OleVariant;safecall;
end;
///////////////////////////////////
// 一个包装它们的接口 。。
IServer = interface
function Get_Senders: ISenders;safecall;
property Senders: ISenders read Get_Senders;
end;

TServer = class(TInterfacedObject ,IServer)
private
FSenders: ISenders;
public
function Get_Senders: ISenders;safecall;
end;
implementation

{ TSender }

constructor TSender.Create(const nm: Widestring);
begin
FName := nm;
end;

function TSender.Get_Name: widestring;
begin
result := FName;
end;

{ TSenders }

function TSenders.Add(NM: widestring): ISender;
var
cnt : integer
//用以临时保存当前Sender 的个数。
begin
////// 采用数组的方式来保存 ISender ,应该还有更好的数据结构吧!
cnt := Get_Count;
FCount := cnt+1;
SetLength(FSenders,FCount);
FSenders[cnt] := TSender.Create(nm)
// 创建接口,添加到 FSenders 数组里。
result := FSenders[cnt];
end;

constructor TSenders.Create;
begin
FCount := 0;
SetLength(FSenders,FCount);
end;

function TSenders.Get_Count: OleVariant;
begin
if high(FSenders)=-1 then
result := 0
else
result := high(FSenders)-low(Fsenders)+1;
end;

function TSenders.Item(index: oleVariant): Isender;
begin
if (index<=high(FSenders)) and (index>=low(FSenders)) then
Result := FSenders[integer(index)]
else
Result := nil;
end;

{ TServer }

function TServer.Get_Senders: ISenders;
begin
if not Assigned(FSenders) then
FSenders := TSenders.Create;
result := FSenders;
end;

end.

下面做一个测试的主程序。
直接在按钮的事件里,
var
test : IServer;
begin
test := TServer.Create;
test.Senders.Add('Coffee');
test.Senders.Add('hello');
showmessage(test.Senders.Count);
showmessage((test.Senders.Item(0)).name);
end;

我的环境是 D7+XP 通过测试。
 
多谢darnis,您的程序可以支持Com吗?我现在对Com的数个对象搞不清楚。
 
应该没有问题吧!
这是手工建立的,你用COM向导来生成之后,再加类似地加入应该行的。
不知试过没有?
待会儿我来加到COM中试试。
 
的确没有问题可以实现的。
如果有必要,你留个Email ,我把测试的代码发给你。
要不你自己想想怎么做,自己多动手试试。
反正在方法就是这样就可以做到的。
:)
 
我已经自己试过很久了,还是不行啊,主要是生成的类对象搞不清楚,昨天研究了一下午
我的邮箱是 lofa@263.net,多谢您了!
 
信件已经发了,请查收后测试一下,多多探讨哈!
 
多谢,象darnis这样的好同志不给他分给谁分呢?,现在开始散分,rockjie 留下Email,我也
给你发一个.另外我想问一下,为什么用的都是AutoObject,其他的Com类可以吗?
 
:)
多谢哈。。

至于为何要从 AutoObject 去继承是因为这样的:

TComObject
TTypedComobject
TAutoObject // 支持 Marshaling (要想COM服务器支持像Office之类的
// Automation 功能,COM服务器必须支持
// 跨越进程边界的函数传递),如果你不从 TAutoObject
// 来继承做 Automation 服务器的话,你自己必须实现
// Marshaling 策略。
TActiveXControl
这是用于实现 COM 对象、Automation对象、 ActiveX 控件的类的继承关系。
关于 Marshaling 策略方面的,有一段从书中看到的原话:
基于标准的远程过程调用(RPC), IDispatch 接口提供了通用的 Marshaling 策略。
COM对象也可以自定义 Marshaling 策略。不过,自定义的 Marshaling 策略不具有通用性。
----------摘自《Delphi 5 高级编程-COM、CORBA与Internet编程》第4页

TAutoObject 实现了 IDispatch。现在明白为什么要从 TAutoObject 继承了吧!
 
哦,多谢你给我这个源程序啊!~~:)
我的邮箱是rockbao@sina.com
 
不好意思,昨天把那个文件下载到家里的机器里面了,今天下午要要回济南,没法回家
了,darnis麻烦您再把您的程序包给rockjie发一个吧,我要发也只能十一之后回来发了

对了,darnis,我按照你的那个包做了一个一样的,可以在使用Senders的时候会提示我
需要typecomfactory来生成Com对象,于是乎我又在initialize中加入一个factory.create
方法才可以,我看你的程序中只有生成TServer的句子也可以啊,这是怎么回事?
 
这个问题我在最先也想到过了,只是作为测试,没有想那么多,
我看 AutoCAD 的 AutoCAD_TLB 文件中,每一个接口都有一个对应的 CoXXX 类,
测试代码里的 CoDrsServer 是在创建 Ole Automation 的时候系统自己建立的,
ISender 和 ISenders 是我从 TypeLibary 编辑器里加入的,不知为何它没有
自己创建 CoSender 和 CoSenders ?这个区别可能是导致这各情况出现的原因。

在程序中直接创建 ISenders 的引用,,,目前这样子的代码可能是不行的,只有通过
Server 中的 Senders 来赋值实现。。
实现接口对象的实例都是通过 类工厂 来创建的。

等国庆节后,再进一步探讨这个问题。。。
 
后退
顶部