求“DLL里面封装了子窗”的成熟调用方法。 ( 积分: 100 )

A

abigfish

Unregistered / Unconfirmed
GUEST, unregistred user!
有可能是创建了一些类似数据控件,在关闭DLL的时候没有释放,造成的.
你可以试下操作query1:=Tadoquery.create;然后关闭DLL,再关闭系统,必然有错.
看两个错误是不是一样的.
 
J

jdz84

Unregistered / Unconfirmed
GUEST, unregistred user!
好贴 我一直也在搞这个 关注中
 
L

lcm40

Unregistered / Unconfirmed
GUEST, unregistred user!
大家好,我在《Delphi 5开发人员指南》找了一个比较好的例子,不过没有动态释放,请各位高手指点,成功就给分。谢谢。(给个Email也可以发给大家)
//****调用代码*****
{
Copyright ?1999 by Delphi 5 Developer's Guide - Xavier Pacheco and Steve Teixeira
}
{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
View-Project Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the DELPHIMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using DELPHIMM.DLL, pass string information
using PChar or ShortString parameters. }
library CalendarMLLib;
uses
ShareMem,
SysUtils,
Classes,
DLLFrm in 'DLLFrm.pas' {DLLForm};
exports
ShowCalendar,
CloseCalendar;

begin
end.

{
Copyright ?1999 by Delphi 5 Developer's Guide - Xavier Pacheco and Steve Teixeira
}
//*******
unit DLLFrm;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, Grids, Calendar;
type
TDLLForm = class(TForm)
calDllCalendar: TCalendar;
end;

{ Declare the export function }
function ShowCalendar(AHandle: THandle;
ACaption: String): Longint;
stdCall;
procedure CloseCalendar(AFormRef: Longint);
stdcall;

implementation
{$R *.DFM}
function ShowCalendar(AHandle: THandle;
ACaption: String): Longint;
var
DLLForm: TDllForm;
begin
// Copy application handle to DLL's TApplication object
Application.Handle := AHandle;
DLLForm := TDLLForm.Create(Application);
Result := Longint(DLLForm);
DLLForm.Caption := ACaption;
DLLForm.Show;

end;

procedure CloseCalendar(AFormRef: Longint);
begin
if AFormRef > 0 then
TDLLForm(AFormRef).Release;
end;

end.

//*****dll代码******
{
Copyright ?1999 by Delphi 5 Developer's Guide - Xavier Pacheco and Steve Teixeira
}
{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
View-Project Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the DELPHIMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using DELPHIMM.DLL, pass string information
using PChar or ShortString parameters. }
library CalendarMLLib;
uses
ShareMem,
SysUtils,
Classes,
DLLFrm in 'DLLFrm.pas' {DLLForm};
exports
ShowCalendar,
CloseCalendar;

begin
end.

//****
{
Copyright ?1999 by Delphi 5 Developer's Guide - Xavier Pacheco and Steve Teixeira
}
unit DLLFrm;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, Grids, Calendar;
type
TDLLForm = class(TForm)
calDllCalendar: TCalendar;
end;

{ Declare the export function }
function ShowCalendar(AHandle: THandle;
ACaption: String): Longint;
stdCall;
procedure CloseCalendar(AFormRef: Longint);
stdcall;

implementation
{$R *.DFM}
function ShowCalendar(AHandle: THandle;
ACaption: String): Longint;
var
DLLForm: TDllForm;
begin
// Copy application handle to DLL's TApplication object
Application.Handle := AHandle;
DLLForm := TDLLForm.Create(Application);
Result := Longint(DLLForm);
DLLForm.Caption := ACaption;
DLLForm.Show;

end;

procedure CloseCalendar(AFormRef: Longint);
begin
if AFormRef > 0 then
TDLLForm(AFormRef).Release;
end;

end.
 
L

lcm40

Unregistered / Unconfirmed
GUEST, unregistred user!
不好意思,调用代码贴错了,应该是下面的
//********
program CalendarTest;
uses
Forms,
MainFfm in 'MainFfm.pas' {MainForm};
{$R *.RES}
begin
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end.
//**********
{
Copyright ?1999 by Delphi 5 Developer's Guide - Xavier Pacheco and Steve Teixeira
}
unit MainFfm;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TMainForm = class(TForm)
btnShowCalendar: TButton;
btnCloseCalendar: TButton;
procedure btnShowCalendarClick(Sender: TObject);
procedure btnCloseCalendarClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
FFormRef: TForm;
end;

var
MainForm: TMainForm;
function ShowCalendar(AHandle: THandle;
ACaption: String): Longint;
StdCall;
external 'CALENDARMLLIB.DLL';
procedure CloseCalendar(AFormRef: Longint);
stdcall;
external 'CALENDARMLLIB.DLL';
implementation
{$R *.DFM}
procedure TMainForm.btnShowCalendarClick(Sender: TObject);
begin
if not Assigned(FFormRef) then
FFormRef := TForm(ShowCalendar(Application.Handle, Caption));
end;

procedure TMainForm.btnCloseCalendarClick(Sender: TObject);
begin
if Assigned(FFormRef) then
begin
CloseCalendar(Longint(FFormRef));
FFormRef := nil;
end;
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
FFormRef := nil;
// Initialize the FFormRef field to nil.
end;

end.
 
P

pal2003

Unregistered / Unconfirmed
GUEST, unregistred user!
uranuszh 可以发一份例子看一下吗?
谢谢 csb_xj@126.com
 
D

dzx2004

Unregistered / Unconfirmed
GUEST, unregistred user!
uranuszh可以发一份例子参考一下吗?
多谢 ry100@163.com
 
L

lcm40

Unregistered / Unconfirmed
GUEST, unregistred user!
大家好,我又在大富翁论谈上面找了一个例题,能够动态释放,不过一个dll里面有多个子窗体时还会有问题;在子窗体上面加Table等控件后关闭子窗体,主窗体也会跟着隐藏;子窗本最大化时盖住了主窗体。请高手出招,小弟被这问题搞得要下岗了,救命呀。
//*****调用的主窗体代码****
unit MainForm;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, AppEvnts;
type
TShowForm = function(AHandle: THandle;
UniqueMsgID: Cardinal): THandle;
stdcall;
TCloseForm = procedure(FormHandle: THandle);
stdcall;
TfrmMain = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
UniqueMsgID: Cardinal;
DLLHandle, FormHandle: THandle;
//DLL的地址,要显示的Form的句柄
ShowForm: TShowForm;
CloseForm: TCloseForm;
public
{ Public declarations }
procedure WndProc(var Msg: TMessage);
override;
end;

var
frmMain: TfrmMain;
implementation
{$R *.DFM}
procedure TfrmMain.Button1Click(Sender: TObject);
begin
{ 动态调用的过程 }
if DLLHandle = 0 then
begin
DLLHandle := LoadLibrary('TestDLL.dll');
try
if DLLHandle = 0 then
raise Exception.Create('装入动态链接库DLLFile.dll失败!');
{ 在这里,将本次要用到的例程全部引入。对于某些必须成功装入的例程来说,如果
装入失败,则立即释放DLL }
@ShowForm := GetProcAddress(DLLHandle, 'ShowForm');
if @ShowForm = nil then
Abort;
@CloseForm := GetProcAddress(DLLHandle, 'CloseForm');
if @CloseForm = nil then
Abort;
FormHandle := ShowForm(Application.Handle, UniqueMsgID);
except
FreeLibrary(DLLHandle);
DLLHandle := 0;
end;
end;
end;

procedure TfrmMain.Button2Click(Sender: TObject);
begin
if DLLHandle <> 0 then
begin
CloseForm(FormHandle);
FreeLibrary(DLLHandle);
DLLHandle := 0;
end;
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
DLLHandle := 0;
UniqueMsgID := RegisterWindowMessage('shiwei is a girl 10:50:20');
end;

procedure TfrmMain.WndProc(var Msg: TMessage);
begin
if Msg.Msg = UniqueMsgID then
begin
if DLLHandle <> 0 then
begin
PostMessage(FrmMain.Handle,Wm_User+1,0,0);
end
end
else
if Msg.Msg=Wm_User+1 then
if DllHandle<>0 then
begin
CloseForm(FormHandle);
FreeLibrary(DLLHandle);
DLLHandle := 0;
end;
inherited WndProc(Msg);
end;


{
procedure TfrmMain.WndProc(var Msg: TMessage);
begin
if Msg.Msg = UniqueMsgID then
if DLLHandle <> 0 then
begin
CloseForm(FormHandle);
FreeLibrary(DLLHandle);
DLLHandle := 0;
end;
inherited WndProc(Msg);
end;
}
end.


//*****DLL****
unit NonModalForm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TfrmNonModal = class(TForm)
private
{ Private declarations }
procedure WMSysCommand(var Msg: TWMSysCommand);
message WM_SYSCOMMAND;
public
{ Public declarations }
end;

function ShowForm(AHandle: THandle;
UniqueMsgID: Cardinal): THandle;
stdcall;
procedure CloseForm(FormHandle: THandle);
stdcall;
exports
ShowForm, CloseForm;

var
frmNonModal: TfrmNonModal;
UniMsgID: Cardinal;
FormHandle: THandle;
implementation
{$R *.dfm}

function ShowForm(AHandle: THandle;
UniqueMsgID: Cardinal): THandle;
begin
Application.Handle := AHandle;
UniMsgID := UniqueMsgID;
FormHandle := THandle(TfrmNonModal.Create(Application));
Result := FormHandle;
//将新建窗体的句柄返回给主程序
with TfrmNonModal(FormHandle)do
try
Show;
except
Free;
Result := 0;
end;
end;

procedure CloseForm(FormHandle: THandle);
begin
if FormHandle <> 0 then
//FormHandle <> 0,表示已经建立的实例,则可以执行关闭、释放
begin
with TfrmNonModal(FormHandle)do
begin
Close;
Free;
end;
end;
end;

{ TfrmNonModal }
procedure TfrmNonModal.WMSysCommand(var Msg: TWMSysCommand);
begin
if Msg.CmdType = SC_CLOSE then
SendMessage(HWND_BROADCAST, UniMsgID, 0, 0)
else
inherited;
end;

end.
 
X

xianjun

Unregistered / Unconfirmed
GUEST, unregistred user!
1、报内存错误可能就是因为字符串传递等问题,确保在工程的第一个uses中引用sharemem单元;
2、如果是在DLL中创建的窗体,一定要在DLL中释放(可以Export出一个过程来做这种事情);同理,EXE中创建的对象就在EXE中释放;
3、如果比较复杂,且用到第三方控件不多,建议还是用BPL的方式,这样跟一个程序就没什么分别了。
4、所谓成熟方法,都是经过大量测试出来的,人家的系统除非开放源码,否则也比较难把所有细节都告诉你。
 
L

lcm40

Unregistered / Unconfirmed
GUEST, unregistred user!
xianjun:
谢谢指点,我能不能发个例子给你,帮我修改一下可以吗?
 
X

xianjun

Unregistered / Unconfirmed
GUEST, unregistred user!
如果有需要,你可以发到这里去:
http://xianjun.vicp.net:8080/

http://xianjun.kmip.net:8080/
 
L

lcm40

Unregistered / Unconfirmed
GUEST, unregistred user!
xianjun:
已经上传,麻烦帮我修改一下
 
X

xianjun

Unregistered / Unconfirmed
GUEST, unregistred user!
我看了你的代码,没有什么特殊操作。
你是说这个DEMO也会报错吗?怎么操作?
 
L

lcm40

Unregistered / Unconfirmed
GUEST, unregistred user!
xianjun:
大家好,我又在大富翁论谈上面找了一个例题,能够动态释放,不过一个dll里面有多个子窗体时还会有问题;在子窗体上面加Table等控件后关闭子窗体,主窗体也会跟着隐藏;子窗本最大化时盖住了主窗体。
注意:主要是能不能解决“一个dll里面有多个子窗体时的动态释放问题”;
另外我的QQ是39745011,我们直接聊一聊可能方便一些
 
B

bjyplbx

Unregistered / Unconfirmed
GUEST, unregistred user!
我认为这样做是不好的,即使你传了application和screen之后
虽然我这么说,但是我还前几天是做了一个试试
留下邮件,发给你
 
L

lcm40

Unregistered / Unconfirmed
GUEST, unregistred user!
bjyplbx:
我的Email:wlls790708@163.com
 
X

xianjun

Unregistered / Unconfirmed
GUEST, unregistred user!
>>一个dll里面有多个子窗体时的动态释放问题
你现在不能解决是因为你在主程序及DLL中使用一个FormHandle来记录,这样就限制了只能一个。
稍作修改即可:把DLL中的记录去掉,这是不需要的,直接在EXE中记录即可。
EXE每次调用ShowForm都把返回结果记录下来,释放的时候再调用CloseForm,并把记录的那个值传入。
 
L

lcm40

Unregistered / Unconfirmed
GUEST, unregistred user!
大家好:
我把我做的这个程序的部分代码(完全能说明调用过程)传到http://xianjun.kmip.net:8080/上面,请各位高手下载后帮我修改一下(主要是要解决以下几个问题:1、程序使用一段时间(30分钟)后会报内存地址溢出等错误;2、DLL(封装了多个子窗体)如何动态释放?3、说明一下,我想求比较成熟的方法,最好是已经商用的方法),修改好后麻烦通知我一下(QQ:39745011,Email:wlls790708@163.com),在下谢谢了。
 
L

lcm40

Unregistered / Unconfirmed
GUEST, unregistred user!
大家好:
文件名叫htcyerp.rar
 
X

xianjun

Unregistered / Unconfirmed
GUEST, unregistred user!
看了一下,你的主程序没有uses ShareMem。
由于你在EXE中DLL之前传递了string类型的值,所以必须在所有工程的第一个uses列表中加入sharemem单元。
 
L

lcm40

Unregistered / Unconfirmed
GUEST, unregistred user!
xianjun:
谢谢你的指点,那多个子窗体的动态释放问题如何解决好呀?
 
顶部