求完整的调用封装在DLL中的MDI窗体(200分)

  • 主题发起人 主题发起人 tane
  • 开始时间 开始时间
T

tane

Unregistered / Unconfirmed
GUEST, unregistred user!
求完整的调用封装在DLL中的MDI窗体,要求能够检测已显示出DLL中的窗体的数量,同时最好能列示出来已打开的MDI窗体.
 
网上有很多完整的例子.

>>要求能够检测已显示出DLL中的窗体的数量

在宿主程序中声明一个插件管理类, 由它来管理,
 
我做过这方面的东西
可惜是公司的软件不能给你“完整”的例子

写一段例程给你

主窗体
{ 根据输入的动态链接库名称和库中函数名称调用库中的窗体 }
{ 2005-09-20 by muhx }
procedure TFrmMain.ShowDLLForm(ADLLName, AProcName: PAnsiChar);
var
tmpProc: procedure(AApplication: TApplication; AScreen: TScreen; AHintWindowClass:
THintWindowClass); stdcall;
begin
if FDllHandle = 0 then
begin
FDllHandle := LoadLibrary(ADLLName);
if FDllHandle >= 32 then
begin
tmpProc := GetProcAddress(FDllHandle, AProcName);
tmpProc(Application, Screen, HintWindowClass);
end;
end;
end;

{ 调用动态链接库中当前窗体的关闭过程 }
{ 2005-09-20 by muhx }
procedure TFrmMain.CloseDLLForm(ALastForm: Integer);
var
tmpProc: procedure; stdcall;
begin
if FDllHandle >= 32 then
begin
try
case ALastForm of
2: tmpProc := GetProcAddress(FDllHandle, 'CloseData');
3: tmpProc := GetProcAddress(FDllHandle, 'CloseConfig');
4: tmpProc := GetProcAddress(FDllHandle, 'CloseUser');
5: tmpProc := GetProcAddress(FDllHandle, 'CloseLog');
6: tmpProc := GetProcAddress(FDllHandle, 'CloseAlarmLog');
7: tmpProc := GetProcAddress(FDllHandle, 'CloseProcTable');
8: tmpProc := GetProcAddress(FDllHandle, 'CloseProcGuide');
else
Exit;
end;
tmpProc;
finally
FreeLibrary(FDllHandle);
FDllHandle := 0;
end;
end;
end;

{ 调用本地和动态链接库中的窗体 }
{ 2005-09-20 by muhx }
procedure TFrmMain.ActShowFormExecute(Sender: TObject);
begin
CloseDLLForm(FLastForm);
FLastForm := (Sender as TAction).Tag mod 100;
case FLastForm of
0: ShowLocalForm(0);
1: ShowLocalForm(1);
2: ShowDLLForm('DataManager.dll', 'ShowData');
3: ShowDLLForm('ConfigManager.dll', 'ShowConfig');
4: ShowDLLForm('ConfigManager.dll', 'ShowUser');
5: ShowDLLForm('ConfigManager.dll', 'ShowLog');
6: ShowDLLForm('ConfigManager.dll', 'ShowAlarmLog');
7: ShowDLLForm('ProcedureManager.dll', 'ShowProcTable');
8: ShowDLLForm('ProcedureManager.dll', 'ShowProcGuide');
else
Exit;
end;
PnlTitle.Caption := (Sender as TAction).Caption;
end;

DLL中的代码(只显示其中一部分窗体的)
{ LIP - ConfigManager.dll }
{ 工程单元 }

{ Copyright (c) 2005, CHR Corporation }
{ Date: 2005-09-14 }
{ Build: }
{ Author: muhx }

library ConfigManager;

uses
SysUtils,
Classes,
Forms,
Windows,
Controls,
UntConfig in 'UntConfig.pas' {FrmConfig},
UntAbout in 'UntAbout.pas' {FrmAbout},
UntLanguageDefine in '../System/UntLanguageDefine.pas',
UntFileDefine in '../System/UntFileDefine.pas',
UntTypeDefine in '../System/UntTypeDefine.pas',
MuFiles in '../Library/MuFiles.pas',
MuControls in '../Library/MuControls.pas',
UntLog in 'UntLog.pas' {FrmLog},
UntDataDefine in '../System/UntDataDefine.pas',
UntAlarmLog in 'UntAlarmLog.pas' {FrmAlarmLog},
UntUser in 'UntUser.pas' {FrmUser},
UntLogin in 'UntLogin.pas' {FrmLogin};

var
GApplication: TApplication;
GScreen: TScreen;
GHintWindowClass: THintWindowClass;

{$R *.res}

exports
ShowConfig, CloseConfig, ShowAboutBox, ShowLog, CloseLog, ShowAlarmLog, CloseAlarmLog,
ShowUser, CloseUser, ShowLogin;

procedure DLLUnloadProc(Reason: Integer); register;
begin
if Reason = DLL_PROCESS_DETACH then
begin
Application := GApplication;
Screen := GScreen;
HintWindowClass := GHintWindowClass;
end;
end;

begin
GApplication := Application;
GScreen := Screen;
GHintWindowClass := HintWindowClass;
DLLProc := @DLLUnloadProc;
end.

其中的ShowConfig和CloseConfig代码为
{ 创建窗体 }
procedure ShowConfig(AApplication: TApplication; AScreen: TScreen; AHintWindowClass:
THintWindowClass); stdcall;
var
tmpLongInt: PLongint;
begin
{ 读取主调窗体信息 }
Application := AApplication;
Screen := AScreen;
HintWindowClass := AHintWindowClass;
{ MainFrom只读,使用指针强行赋值 }
tmpLongInt := @(Application.MainForm);
tmpLongInt^ := Longint(AApplication.MainForm);
FrmConfig := TFrmConfig.Create(Application.MainForm);
try
FrmConfig.Show;
except
FrmConfig.Free;
end;
end;

{ 在释放DLL前先释放窗体 }
procedure CloseConfig;
begin
if FrmConfig <> nil then
FrmConfig.Free;
FrmConfig := nil;
end;
 
给个邮件地址。发给你
 
其实我经过一晚的寻找,已经搞定了,但还是要谢谢两位.
 
gatestone@163.com
 
收了代码就散分.
 
问题: 倾家荡产 192分 求一个简单完整的DLL源程序! ( 积分: 100 )
分类: 系统相关

来自: Dinky, 时间: 2002-12-13 17:59:00, ID: 1508929
Requires:
1、主窗体:有一主窗体调用DLL里的子窗体,在主窗体上,可以得到子窗体的个数(MDIChildCount)。
2、DLL子窗体:显示数据库里的数据(随便什么数据)
3、调用不出错。
谢谢!如果你愿意帮我请将程序发到我的邮箱
<a href='mailto:DinkySoft@163.com'>DinkySoft@163.com</a>
收到后,满意后给分,不满意分要少一点!还有要留下你的一句话在这里,到时不能给分的
还有92分没有加上去,不知道怎么加

来自: jsxjd, 时间: 2002-12-13 18:28:00, ID: 1509011
up

来自: 王公子, 时间: 2002-12-13 18:29:00, ID: 1509013
我这有一个,或许对你有用,拿箱子过来

来自: Dinky, 时间: 2002-12-13 18:30:00, ID: 1509016
to jsxjd,谢谢你来Up
我收到,发一个给你

来自: Dinky, 时间: 2002-12-13 18:30:00, ID: 1509020
to王公子,
你发给我吧!dinkysoft163.com

来自: youou, 时间: 2002-12-13 18:46:00, ID: 1509054
我有一个。。找不要。。。
要不什么写一个。。


来自: Dinky, 时间: 2002-12-13 19:10:00, ID: 1509083
to youou也可以啊!

来自: ty_unix, 时间: 2002-12-16 9:17:00, ID: 1512868
我也要一个。谢谢
ty_unix@163.com

来自: xuxincheng, 时间: 2002-12-20 9:14:00, ID: 1523509
可以给我一个吗?
xuxincheng@sina.com

来自: LiChaoHui, 时间: 2002-12-20 9:17:00, ID: 1523522
up

来自: brianyu, 时间: 2002-12-20 13:11:00, ID: 1524440
贴出来吧,大家共享一下:)

来自: LiChaoHui, 时间: 2002-12-20 14:14:00, ID: 1524689
我已经找到了一个方法,是用Delphi中的包技术

同时使主程序变得很小,
还可以动态加载包,运行也不出错

如果需要,给我50分,将实现方法发送

来自: LiChaoHui, 时间: 2002-12-20 14:23:00, ID: 1524719
实现的思路是将基础的包,重新封装成一个独立的大包,
然后你的程序,和另一个动态链接库(最好做成包),
都使用这个大包,你的程序和动态库会很小,
但是这个大包,就很大了,
不过对于做大型程序,这样反而更能节省内存
和减小EXE的体积

来自: 你若有情, 时间: 2002-12-20 15:04:00, ID: 1524864
to LiChaoHui
发过来,一定有分的

来自: LiChaoHui, 时间: 2002-12-20 15:50:00, ID: 1525034
先开帖子吧,要留下信箱,我好发送全部源代码(共10k)

来自: brianyu, 时间: 2002-12-20 16:51:00, ID: 1525309
LiChaoHui, 来这里拿分
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1525301
我的邮箱 sunny_sh@163.net

来自: jsxjd, 时间: 2002-12-20 17:11:00, ID: 1525384
///////////////// DLL /////////////////////
library FormDll;

uses
SysUtils,
windows,
Classes,
forms,
MyForm in 'MyForm.pas' {ChildForm};

{$R *.RES}
var
DLLApp: TApplication;
OldSc:TScreen;
procedure DLLUnloadProc(Reason : Integer);
begin
if Reason = DLL_PROCESS_DETACH then begin
Application := DLLApp;
Screen:=OldSc;
end;
end;

function ShowForm(App:TApplication;sc:TScreen): integer;
var
i:integer;
begin
application:=App;
Screen:=sc;
for i:=0 to N do
if ch=nil then
begin
ch:=TChildForm.Create(nil);
// ch.parent:=application.mainform;
ch.tag:=i;
break;
end;
Result:=0;
end;

exports ShowForm;

var
i:integer;
begin
for i:=0 to N do ch:=nil;

DLLApp := Application;
OldSc:=Screen;
DLLProc := @DLLUnloadProc;
end.

/////////// mdiform unit //////////////////

unit MyForm;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
TChildForm = class(TForm)
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const N=100;

var
ch:array[0..N] of TChildForm;

implementation

{$R *.DFM}

procedure TChildForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
ch[tag]:=nil;
end;

procedure TChildForm.FormCreate(Sender: TObject);
begin
inherited;
FormStyle := fsMDIChild;
end;

end.



////////////// 调用程序 //////////////////////////
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}
// 创建动态按钮,第一排一个,第十排十个
var
b:array of array of TButton;
procedure TForm1.FormCreate(Sender: TObject);

var
i,j:integer;
begin
SetLength(b,10);
for i:=low(b) to high(b) do
SetLength(b,i+1);

for i:=low(b) to high(b) do
for j:=low(b) to high(b) do
begin
b[i,j]:=TButton.Create(self);
with b[i,j] do
begin
parent:=self;
left:=j*30;
top:=i*30;
width:=20;
height:=20;
visible:=true;

end;
end;

end;
function ShowForm(App:TApplication;sc:TScreen): integer;external 'formdll.dll'

procedure TForm1.Button1Click(Sender: TObject);
begin
showform(application,screen);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
showmessage(inttostr(MDIChildCount));
end;

end.

来自: LiChaoHui, 时间: 2002-12-20 17:12:00, ID: 1525390
to: brianyu
程序已发送,附上一些其它的技巧:

还有一些其它的问题,就是控制Delphi程序的运行时信息

譬如,我知道某个类的类名和属性的名称,
我也可以创建这个类并修改它的属性,
我的演示程序里有根据类名称创建类实例的方法,
下面写出访问知道名字的属性的方法
需引用 TypInfo 单元
假设 MyObj 是通过上面的方法创建的对象
他的两个字符串类型的属性分别为 MyProperty1 和 MyProperty2
下面读取MyProperty1 并设置 MyProperty2
SetStrProp(MyObj, 'MyProperty1', 'test1');
vStr := GetStrProp(MyObj, 'MyProperty2');

要修改的属性只能是Published的属性
只有Published的属性才有类似的运行时信息
对于不同的数据类型
TypInfo单元提供了不同的方法




来自: catfox, 时间: 2002-12-20 17:15:00, ID: 1525403
to LiChaoHui:
你的源代码是什么程序, 若合适我也另开贴

来自: LiChaoHui, 时间: 2002-12-20 17:19:00, ID: 1525417
to: 楼主,
我的方法完全不同于楼上的方法,
使用包来实现,透明性好,代码很少,没有副作用
(据我以前的研究,楼上的方法有很大的缺陷,虽然能够显示窗口,
退出的时候,也可以不出错,但是如果在MDI子窗口上加一个弹出菜单,
你再看看,就惨了)

如果需要,说一声,我好发给你
我只要50分,如果硬要多给,我只好领受

来自: 新的自我, 时间: 2002-12-20 17:20:00, ID: 1525425
Study

来自: LiChaoHui, 时间: 2002-12-20 17:22:00, ID: 1525432
我的程序是关于动态加载包(*.bpl)
并调用其中的对象,
自己写的包可以含有MDI子窗口,
代码很少,运行效果也很好

粒子很简单,如果不懂,还可以再讨论

注意,其它收到我的程序的朋友先不要在其他地方公开
让我的辛苦多换一些分数,谢谢合作

来自: brianyu, 时间: 2002-12-20 17:30:00, ID: 1525467
to:LiChaoHui, 没有看到你只要50分,嘿嘿:)
不过还是谢谢了:)

来自: LiChaoHui, 时间: 2002-12-20 17:31:00, ID: 1525475
呵呵

来自: Dinky, 时间: 2002-12-20 17:35:00, ID: 1525495
to LiChaoHui
DinkySoft@163.com

来自: Dinky, 时间: 2002-12-20 17:39:00, ID: 1525511
to LiChaoHui其实这个问题我已经解决了,用DLL用很多不好的地方,我想用包来实现,分一定给的
什么时候发给我啊
DinkySoft@163.com

来自: LiChaoHui, 时间: 2002-12-20 17:40:00, ID: 1525517
绝对不后悔...
开帖给分先(50),呵呵...

来自: Dinky, 时间: 2002-12-20 17:42:00, ID: 1525523
给你100分,交个朋友吧!QQ:185511468

来自: catfox, 时间: 2002-12-20 17:52:00, ID: 1525533
来分了

http://www.delphibbs.com/delphibbs/dispq.asp?lid=1525529

catfox@joinmars.com

交个朋友吧 QQ:786552

来自: Dinky, 时间: 2002-12-20 17:47:00, ID: 1525544
to LiChaoHui:
分我已经发出去了!100分不是很少吧!呵呵,什么时候发给我啊!例子

来自: LiChaoHui, 时间: 2002-12-20 21:36:00, ID: 1525963
to Dinky:
源代码已经发送,请查收!

来自: LiChaoHui, 时间: 2002-12-20 21:42:00, ID: 1525979
to catfox,
已发送,谢谢

来自: doll_paul, 时间: 2002-12-22 0:55:00, ID: 1527781
to LiChaoHui,我用DLL现实以上要求,总或多或少出现问题,请老兄也发个源码吧~

EM:doll-paul@263.net,万分感谢,给个吉利数:80分~~

http://www.delphibbs.com/delphibbs/dispq.asp?lid=1527780

来自: LiChaoHui, 时间: 2002-12-22 14:20:00, ID: 1528263
你是怎么找到这个帖子的,我都找不到了?

来自: doll_paul, 时间: 2002-12-22 14:31:00, ID: 1528276
嗨,为了解决问题,我要挖地三尺~

另:程序收到,马上给分~~

来自: LiChaoHui, 时间: 2002-12-22 22:12:00, ID: 1528891
多谢

来自: SEVN, 时间: 2002-12-23 19:16:00, ID: 1531352
唉~~

来自: whsoft, 时间: 2003-02-18 11:29:00, ID: 1628847
LICHAOHVI
请重发一下,另外给分也行:D
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1526673
我的mail:bdj@whdahua.com

得分大富翁: LiChaoHui-100,
 
问题: 如何把窗体封装到DLL中并动态调用之 ( 积分: 300 )
分类: MIDAS / DCOM

来自: zhenqiang, 时间: 2004-04-09 11:59:00, ID: 2549015
如题

来自: 一飞冲天, 时间: 2004-04-09 12:00:40, ID: 2549027
看书去吧,多着呢

来自: zhenqiang, 时间: 2004-04-09 12:01:47, ID: 2549031
接受答案了.

来自: wqhatnet, 时间: 2004-04-09 12:03:41, ID: 2549038
[来在超级猛料]
DLL中导出窗体指南

作为一个经常被提起的问题,很多人不知道怎么来从DLL中导出窗体,特别是MDI的子窗体,因此Kingron愿意在这里把一些经验写出来给大家分享,让大家在碰到类似的问题的时候,少走些弯路。

大家知道,DLL有两种加载方式,至于动态的,和静态的,稍微有点儿区别。动态的加载,大家可以参考Torry's Delphi Page上面的例子,其中有一个MDI的例子,非常简单的,很好用。我的例子以静态加载为主。

据目前来看,我们要在DLL中导出这个Form的话,必须通过DLL导出函数来做到,但是我们知道DLL工程的Application和Host程序的Application是有区别的,对于一般的应用程序来说,Application是VCL固定的,一般不会修改Application对象指针,但是在DLL中,我们需要使用窗体等,或者使用Application对象的时候,使DLL的Application和Host程序一样,这样才不至于混淆。以下面的例子为例,如果不修改Application对象,那么Host程序退出的时候,可能出现AV错误!例如:

在Host中Export一个函数:

function DllFunction(App:TApplication;PForm:TForm):TForm2;stdcall;

begin

Result :=TForm2.Create(PForm);

end;

那么主程序推出的时候,很可能发生AV错误。

下面一步一步来做:

首先,我们需要一个DLL工程,在IDE中New一个DLL,然后New一个Form,Save All File,工程名为DLL.DPR,Form的Unit文件为DLLForm.pas,窗体类名为FrmDLLChild。然后随便设计这个DLLChild Form即可。

然后,在DLL.DPR中修改代码,添加:

library Dll;

uses

SysUtils,windows,

Classes,Controls,Forms,

DllForm in 'DllForm.pas' ;

{$R *.res}

var

DllApp:TApplication;

{ 用于初始化:保存DLL本身的Application,然后设置DLL的Application指向Host的Application }

procedure InitDLL(App:TApplication);stdcall;

begin

DllApp:=Application;

Application:=App;

end;

{ 善后工作:恢复DLL原来的Application }

procedure FreeDLL;stdcall;

begin

Application:=DllApp;

end;

{ 返回一个窗体对象,这是DLL的主要功能 }

function GetDllChildForm(Parent:TComponent):TFrmDLLChild;stdcall;

begin

Result := TFrmDLLChild.Create(Parent);

end;

exports

InitDLL,FreeDLL,GetDllChildForm;

begin

end.

至此DLL已经完成了,在使用DLL的时候,需要注意:首先必须调用InitDLL,并且传递主程序的Application作为参数,否则主程序退出的时候,会报AV错误。

主程序调用如下:

为了简单方便地使用,可以把DLL中包含窗体的那个单元Use进来,如果不喜欢,用类型强制也可。

function GetDllChildForm(Parent:TComponent):TFrmDllChild;stdcall;external 'dll.dll';

procedure InitDLL(App:TApplication);stdcall;external 'dll.dll';

procedure FreeDLL;stdcall;external 'dll.dll';

procedure TForm1.FormCreate(Sender: TObject);

begin

InitDLL(Application);

end;

procedure TForm1.FormDestroy(Sender: TObject);

begin

FreeDLL;

end;

调用窗体代码:

var

DForm:TFrmDllChild;

begin

DForm :=DllFunction(Application,Self);

DForm.Show;

end;

附件中的代码完整演示了一个简单的例子。 DllProject.rar

至于动态加载的演示,请参看《MDI Child Form和DLL》





得分大富翁: 一飞冲天
 
还有一个单独的例子:
http://www.ddvip.net/program/delphi/index6/three/imgC/49.zip
 
谢谢各位散分了
 
后退
顶部