一个破问题困扰我好几天了!!(关于DLL里面创建VCL控件)(300分)

  • 主题发起人 一个过客
  • 开始时间

一个过客

Unregistered / Unconfirmed
GUEST, unregistred user!
一个主form,提供一个Panel供其他DLL使用,我希望其他人能够在这个Panel上面
随便放置自己的东西,比如一个TMemo,并且我会传递给DLL必要的数据进行处理。
也就是说有点类似Plugins的机制:我把Panel的句柄传递给DLL,DLL在Panel上面
做自己想做的事。
可是这么一个简单的东西居然怎么也出不来,问题处在参数的传递上面,
最起初我为了能够照顾到VC的程序员,于是决定传递Panel.Handle过去,这是个
标准的Windows句柄,什么语言都可以使用,并且我也用Delphi写了一个DLL的
例子代码,用纯SDK的方式(Createwindow...)实现了添加一个Memo到Panel上面,
但是后来考虑到SDK方式开发效率太低,于是决定放弃对VC的支持,只支持
Delphi就够了,这样我就可以把Panel这个VCL对象传递过去,就可以在DLL里面
使用强大的VCL类库了(想当然的),但是结果却并不如人意,例子如下:
//DLL 代码片断
function FilterData(ParentPanel:TPanel):integer;stdcall;
var memo:tmemo;
begin
memo:=tmemo.create(ParentPanel);
//ParentPanel就是主窗口传递过来的Panel
memo.parent:=ParentPanel;
memo.align:=alclient;
memo.text:='ok!';
end;

主程序调用的时候出错,说什么:
Cannot assign a TFont to a TFont
什么意思?
或者大家有更好的办法实现我的要求??
 
这说来话长,编译时 Delphi 会为每个 Class 都会生成一个 MetaClass(元类) 结构,该结构
包含了指向 ClassName, Parent Class, Dynamic Methods Table 和 TypeInfo(RTTI) 的指
针和 VMT 信息,而每个对象实例的头四个字节是就一个指向该对象所属类别的 MetaClass
结构的指针. 象 if (MyForm is TForm) then
... 中, is 运算符就是通过 MyForm 所指向
的对象实例的这头四个字节是否指向 TForm 的 MetaClass 结构(当然可能需要沿 TForm 的
父类继续向上搜索) 来判断的.
那么 Exe 中,会有一套 TObject,TPersistent,TComponent,... 程序用到各个类相应
MetaClass 结构,而 DLL 同样也会有有这样一套结构,这样 DLL 加载后 , 它所包含 TObject
与 Exe 中的 TObject 是不同的,因为各自的 MetaClass 占有不同的地址空间,同样其他类也
是各有一套.因此 Exe 中的 TFont <> DLL 中的 TFont. 因此不能跨 Module 使用 is 和
as 运算符.
可以用 Runtime Package 解决这个问题, Package 是特殊的 DLL, Delphi 编译时会通过
输出函数将 Package 中定义的类的 MetaClass 结构和全局VCL对象暴露给外部,同时将
Package 中用到的其他 Module 的类和全局VCL 对象通过输入其他 Module 的输出函数来
引入.这样在程序中各 Module 就共用一套各类的 MetaClass 结构了.就不会出现上述 is,as
运算符的问题了.Delphi 自己就是使用了 Runtime Package 机制的.
 
就是不想用runtime package,要带一大堆bpl,太麻烦了!
没有别的办法吗?我的要求很简单,就是在DLL里面创建一个随便什么VCL/window
之类的东西,把它放在主窗口里面。
 
现在暂时解决了无法放置VCL的问题,我通过传递ParentPanel的Handle,然后
memo:=tmemo.create(nil);
memo.ParentWindow:=handle;
就可以了!
但是这样一来又出现一个问题,就是这样出来的Memo不能保留住焦点,当你在
Memo里面按下 上下左右 光标键的时候,焦点就移到主窗口别的控件上面去了,
看上去好像这个外来的Memo根本没有键入到窗口的Taborder的列表里面,窗口
认为ParentPanel是不需要焦点的,于是一按光标键就把焦点移走了。
请问怎样解决?
或者谁有更好的全面解决方案?

 
如果要 DLL 另外创建一个 Form 还比较容易,但要在一个由主 Exe 创建的窗口上创建一个
子控件,还没想到很好的办法,也许你可以把一个类从主 Exe 传给 DLL, DLL 创建该类的
实例,再返回给主 Exe.比如 DLL 中输出一个函数:
function CreateComponent(ComponentClass: TComponentClass;Owner: TComponent;
Par: TWinControl);
var
memo: TMemo;
begin
memo := TMemo(ComponentClass).Create(Owner);
memo.Parent := Par;
end;
然后 Exe 中类似这样调用:
CreateComponent(TMemo, Self,Panel1);
//Self 指 Form 实例
这样 DLL 也用的是 Exe 中的类.
或者你可以把要创建的 memo 做成 ActiveX 控件,然后创建时指定它的 ParentWindow 就
可以了。另外,Help 中说了,ParentWindow 应该是用于指定一个非 VCL 窗口为父窗口的。
 
1、方法不好,因为实际应用时主窗口并不知道DLL会往Panel上面放什么乱七八糟的
东西,就是说他并不知道是什么类,只有DLL自己知道。
2、如果做Activex,怎样想你说的动态创建它并指定它的ParentWindow?
 
再dll中最好传递用地止
 
传地址好像也不行,什么都试过了
 
就这样吧
 
顶部