如何delphi动态调用封装在dll(或bpl)里的窗体?谢谢!

grjs2004 2008-03-02 12:26:46
结合exe+bpl+dll+interface
exe为主应用窗口程序
bpl为存放公用单元文件、模板的包
dll为业务动态库(有多个业务模块)
(或可以做成bpl业务包,通过判断其后缀是dll还是bpl来执行调用对象)
interface为数据接口
可以参考盒子(2ccc)里的代码

比如用一个树形菜单(TreeView),鼠标点选双击后,
先加载相应的动态库dll,再打开相应的窗体,
而这个窗体是封装在相应的dll里,
窗体的name,caption,dll实体名称都可以通过数据库查询出来,
dll与name成父子关系生成树形菜单

请问要怎么实现这样的目的?谢谢!
...全文
1449 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
grjs2004 2008-04-06
  • 打赏
  • 举报
回复
我已经解决了调用的问题!
就是用MDI窗体的话,还存在一些小问题没有处理。
虽然没有得到正确的答案,但是我还是要感谢所有回帖的人!
谢谢!
freetop_gl 2008-03-22
  • 打赏
  • 举报
回复
简单一点,可以用在DLL 中提供一个函数来创建窗体
大部分时间,你创建窗体是想交互一些数据,比如用窗体来获得某些值,或者显示某些数据,那么可以把这些数据首先定义好
所以大致上这个函数会这样,以返回一个数据为例

procedure GetEmployeeName(xxxname:string):boolean;
begin
xxxFrom.create;
if xxxFrom.showmodal=mrok then
begin
xxxname:=xxxForm.xxxname;
xxxFrom.free;
result:=true;
end;
end;



grjs2004 2008-03-21
  • 打赏
  • 举报
回复
请继续帮顶!
谢谢!
shuihan20e 2008-03-13
  • 打赏
  • 举报
回复
帮顶了,学习了
grjs2004 2008-03-13
  • 打赏
  • 举报
回复
很郁闷啊!
现在发的贴越来越少人顶了!
越来越少人帮忙了!
世态炎凉啊!
希望有人继续帮忙啊?
UndefinedCoder 2008-03-13
  • 打赏
  • 举报
回复
Package初始化时用Classes.RegisterClass或Classes.RegisterClasses注册你的窗体类
LoadPackage
GetClass获取bpl中的类引用。
UnLoadPackage
grjs2004 2008-03-10
  • 打赏
  • 举报
回复
还有谁有更好的方法啊!
或者更直接、更方便的方法实现这个目的啊?
请不吝赐教!
谢谢!
无条件为你 2008-03-04
  • 打赏
  • 举报
回复
代码至少三页,贴出来因为贴子的换行导致代码可能又需要修正,而且单元的关联和过程的写法还不好组合,没有直接给你做一个工程来的方便。如果楼主不愿意加群,那算了。

无论你再说任何对我表示不满的话,本贴本人都不再回复。
grjs2004 2008-03-04
  • 打赏
  • 举报
回复
如果楼上的有更好的方法,不妨在这里贴出来,让大家都可以学习!
谢谢!
无条件为你 2008-03-04
  • 打赏
  • 举报
回复
加群:37802783 吧,你的问题可以马上给你解决,解决方案甚至比你想象的还要完美。但是希望你能再加点分,必定这个问题有一定难度!
Harryfin 2008-03-04
  • 打赏
  • 举报
回复
DLL比较容易,可以直接用导出函数来创建窗体。BPL的话可能依赖注册的机制会比较好。
CCC的 2008-03-03
  • 打赏
  • 举报
回复
unit DllInit;

interface

uses uDllform, classes, extctrls, Controls, Forms, SConnect, SysUtils;

procedure InitDll(SenderOwner : TForm; SenderParent : TPanel; ParentApplication : TApplication; UserID : String;parentSocketConnection : TSocketConnection; providerQuery, providerSproc:string); stdcall; export;
procedure CloseDll; stdcall; export;

implementation

procedure CloseDll;
begin
try
if fDllForm<>nil then begin
fDllForm.free;
fDllForm:=nil;
end;
except
on E:Exception do raise Exception.create('(CloseDll)'+E.Message);
end;
end;

procedure InitDll(SenderOwner : TForm; SenderParent : TPanel; ParentApplication : TApplication; UserID : String;parentSocketConnection : TSocketConnection;providerQuery,providerSproc:string);
begin
try
CloseDll;

fDllForm := TfDllForm.Create(nil);
With fDllForm do
begin
ParentWindow := SenderParent.Handle;
Align := alClient;
BorderStyle := bsNone;
G_sockConnection:=parentSocketConnection;
If UserID = 'admin' Then
UpdateUserID := '0'
Else
UpdateUserID := UserID;
Show;
end;

except
on E:Exception do raise Exception.create('(InitDll)'+E.Message);
end;
end;

end.

***********************************
unit uDllform;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, uformMain,
jpeg, ExtCtrls, SConnect;

type
TfDllForm = class(TForm)
Imagemain: TImage;
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
UpdateUserID : String;
end;

var
fDllForm: TfDllForm;
G_sockConnection : TSocketConnection;

implementation

{$R *.DFM}

procedure TfDllForm.FormShow(Sender: TObject);
begin
formMain := TformMain.Create(Self);
With formMain do
begin
Parent := Self;
Align := alClient;
BorderStyle := bsNone;
ImageAll.Picture := Imagemain.Picture;
UpdateUserID := Self.UpdateUserID;
QryData.RemoteServer := G_sockConnection;
QryData.ProviderName := 'DspQryData';
QryData1.RemoteServer := G_sockConnection;
QryData1.ProviderName := 'DspQryData';

QryTemp.RemoteServer := G_sockConnection;
QryTemp.ProviderName := 'DspQryTemp1';
sproc.RemoteServer := G_sockConnection;
sproc.ProviderName := 'DspStoreproc';

Show;
end;
end;

end.
grjs2004 2008-03-03
  • 打赏
  • 举报
回复
//已经解决了
//代码比较多,所以没有完全贴出来,但我想已经可以看明白啦
//我是从别处贴上来的
//大家可以参考一下
//
tvModule : TcxTreeView
ModuleList : TStringList;
......
procedure TMain_Frm.tvModuleDblClick(Sender: TObject);
var
n: Integer;
begin
n := ModuleList.IndexOfObject(tvModule.Selected);
if n=-1 then exit;
if tvModule.Selected.HasChildren then
begin
//
end else
begin
//SplitterModule.CloseSplitter; //分割控件
IFrmFactory.MakeForm(ModuleList.Strings[n]);
//SplitterModule.Visible := False;
end;
end;

//IFormFactory 接口
unit FormFactoryInf;

interface

uses cxPC;

type
IFormFactory = interface(IInterface)
['{8C3220DC-8C31-4E39-BB89-7D757B58950F}']
procedure FreeFormEx(AModuleID: String);
procedure FreeForm(Aobj: TObject);
procedure FreeFormExt(n: Integer); stdcall;
function GetCounter: Integer;
procedure MakeFormExt(var Reference; Const AClassName: String; RunMode:
String='');
procedure MakeForm(Const ModuleID: String);
procedure MakeFormEx(Const AClassName: String; RunMode: String='');
procedure SetPageControl(const Value: TcxPageControl); stdcall;
property Counter: Integer read GetCounter;
property PageControl: TcxPageControl write SetPageControl;
end;

implementation

end.

//
procedure TFormFactory.MakeForm(Const ModuleID: String);
var
sClassName, StrRunMode: String;
n, iPower: Integer;
Instance: TBase_Frm;
begin
//据模块ID创建对应的窗体
n := FFormList.IndexOf(ModuleID);
if n<>-1 then
begin
Instance := FFormList.Objects[n] as TBase_Frm;
ShowForm(Instance);
exit;
end;

if not CheckFrmPower(ModuleID, iPower) then
exit;

n := Pub.RPos('_',ModuleID);
if (n<>0) and (UpperCase(RightBStr(ModuleID,3))<>'FRM') then
begin
sClassName := Copy(ModuleID,1,n-1);
StrRunMode := Copy(ModuleID,n+1,MaxInt);
end
else begin
sClassName := ModuleID;
StrRunMode := '';
end;
sClassName := 'T'+sClassName;
CreateForm(Instance, iPower, ModuleID, sClassName, StrRunMode);
end;
xjjrocker 2008-03-03
  • 打赏
  • 举报
回复
==>思路如下:
-----------------------------------------------------------------------------------
窗体在dll中实现,程序运行时即加载dll
每个窗体有自己的id号,这个id号作为整个程序的公共变量传递给主程序当然还有树形菜单
当菜单被点击,则主程序调用相应id的窗体,并显示出来。
------------------------------------------------------------------------------------

==>部分代码:
------------------------------------------------------------------------------------
{属性菜单被点击}
procedure TfrmNavigate.tvAllDblClick(Sender: TObject);
var
tnItem: TTreeNode;
begin
tnItem := nil;
tnItem := tvAll.Selected;

if tnItem <> nil then
if Assigned(tnItem) then
begin
if not HaveForm(Integer(OldTreeNode.Data)) then //窗口没有打开才提交打开申请
frmMain.CallEntryByMenuID(Integer(tnItem.Data));//根据菜单ID获得窗体接口
if tnItem.HasChildren then
Exit;
tnItem.StateIndex := 3;
end;

end;

{dll片段}
function Entry(DllExchangeInfo: PExchangeInfo): TForm; stdcall;
begin
DllExchInfo := DllExchangeInfo;
case DllExchInfo^.MenuID of
12000: Result := TfrmTestForm.Create(Application);//根据窗口ID创建窗体
else
Result := TfrmTemp.Create(Application);
end;
end;

exports
Entry index 1;
------------------------------------------------------------------------------------
heiyuyun 2008-03-03
  • 打赏
  • 举报
回复
UP,期待答案,有了告诉我一声啊!
xiaxia421 2008-03-03
  • 打赏
  • 举报
回复
Up!!期待方案!
grjs2004 2008-03-03
  • 打赏
  • 举报
回复
请知道帮帮忙吧!
如果解决了这个问题,所有分都是你的啦!
ydlchina 2008-03-02
  • 打赏
  • 举报
回复
顶顶
lqwxfdwj 2008-03-02
  • 打赏
  • 举报
回复
帮你顶.
九桔猫 2008-03-02
  • 打赏
  • 举报
回复
听说是要线程啥的,具体不知。
当然,如果需求允许,建议还是楼主不要把窗口封装到dll里的好。
加载更多回复(1)

2,497

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 数据库相关
社区管理员
  • 数据库相关社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧