下面是我调用dll子窗体的函数,每次主窗体调用完dll后关闭主窗体就会出错!我想应该是没有释放子窗体的缘故,应该如何释放子窗体呢?请高手告知谢谢!调用字窗体
function TForm1.Dllfrmshow(frm:integer;dllname:string):boolean;
type
Windowmax= function :boolean;stdcall;
openform =function (pbase:basemsg):string;
var
DLLHandle: THandle;
DLLSub: InvokeDLLForm;
Tf:Windowmax;
Tf2:openform;
Tp,Tp2:TFarProc;
beginif DllHandle_rk[frm] = 0 then
begin
DllHandle_rk[frm] :=LoadLibrary(PChar(extractfilepath(application.ExeName)+'dll\'+dllname));
if DllHandle_rk[frm] = 0 then
begin
showmessage('调入失败!');
exit;
end;
Windowsid:=frm;
//////////////////////载入函数
//////////////////////载入函数//DllHandle_rk[frm]:= DLLHandle;
try
if DllHandle_rk[frm] <> 0 then
begin
@DLLSub := GetProcAddress(DllHandle_rk[frm], 'CreateDLLForm');
if Assigned(DLLSub) then
DLLForm := DLLSub(Application, Screen);////////////////////传递pbase类给dll
Tp2:=GetProcAddress(DllHandle_rk[frm],PChar('openform')); /////open dll函数
Pbase.userid :='yzl';
Pbase.phandle:=Handle;
Pbase.Windowsid:=frm;
if Tp2<>nil
then
begin
Tf2:=openform(Tp2);
BitBtn_Competence[frm]:=Tf2(pbase);
end;
////////////////////传递pbase类给dllBitBtn_Control(BitBtn_Competence[frm]); ///////初始按钮权限
end;
except
FreeLibrary(DllHandle_rk[frm]);
end;end
else
begin
BitBtn_Control(BitBtn_Competence[frm]);
Windowsid:=frm;
Tp:=GetProcAddress(DllHandle_rk[frm],PChar('Windowmax')); ////窗口最大化函数
if Tp<>nil
then
begin
Tf:=Windowmax(Tp);
Tf();
end;
end;
end;
主窗体关闭是进行释放,但还是出错我定义了一个 DllHandle_rk:array[0..150] of Thandle;//DLL文件存放入口 用于存放DLL的Handle的,不知释放的对否,请高手解答谢谢
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
i:integer;
begin
for i:=1 to 10 do
if DllHandle_rk[i] <> 0 then
FreeLibrary(DllHandle_rk[i]);
self.Close;
end;呵,在dll窗体里我也释放了这上关闭窗体时候的代码
procedure TfrmDLLForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
freeandnil(frmDLLForm);
end;在主窗体关闭的时候的代码
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
i:integer;
begin
for i:=1 to 10 do
if DllHandle_rk[i] <> 0 then
FreeLibrary(DllHandle_rk[i]);
self.Close;
end;以上是子窗体和主窗体关闭时的代码,请帮我看看有啥问题吗?最好能不能用主窗体来控制释放子窗体呢?因为用户有时候不一定是关了子窗体再关主窗体的,他们有可能直接关主窗体。请帮我看看如何用主窗体释放全部的子窗体,麻烦了,谢谢!
function TForm1.Dllfrmshow(frm:integer;dllname:string):boolean;
type
Windowmax= function :boolean;stdcall;
openform =function (pbase:basemsg):string;
var
DLLHandle: THandle;
DLLSub: InvokeDLLForm;
Tf:Windowmax;
Tf2:openform;
Tp,Tp2:TFarProc;
beginif DllHandle_rk[frm] = 0 then
begin
DllHandle_rk[frm] :=LoadLibrary(PChar(extractfilepath(application.ExeName)+'dll\'+dllname));
if DllHandle_rk[frm] = 0 then
begin
showmessage('调入失败!');
exit;
end;
Windowsid:=frm;
//////////////////////载入函数
//////////////////////载入函数//DllHandle_rk[frm]:= DLLHandle;
try
if DllHandle_rk[frm] <> 0 then
begin
@DLLSub := GetProcAddress(DllHandle_rk[frm], 'CreateDLLForm');
if Assigned(DLLSub) then
DLLForm := DLLSub(Application, Screen);////////////////////传递pbase类给dll
Tp2:=GetProcAddress(DllHandle_rk[frm],PChar('openform')); /////open dll函数
Pbase.userid :='yzl';
Pbase.phandle:=Handle;
Pbase.Windowsid:=frm;
if Tp2<>nil
then
begin
Tf2:=openform(Tp2);
BitBtn_Competence[frm]:=Tf2(pbase);
end;
////////////////////传递pbase类给dllBitBtn_Control(BitBtn_Competence[frm]); ///////初始按钮权限
end;
except
FreeLibrary(DllHandle_rk[frm]);
end;end
else
begin
BitBtn_Control(BitBtn_Competence[frm]);
Windowsid:=frm;
Tp:=GetProcAddress(DllHandle_rk[frm],PChar('Windowmax')); ////窗口最大化函数
if Tp<>nil
then
begin
Tf:=Windowmax(Tp);
Tf();
end;
end;
end;
主窗体关闭是进行释放,但还是出错我定义了一个 DllHandle_rk:array[0..150] of Thandle;//DLL文件存放入口 用于存放DLL的Handle的,不知释放的对否,请高手解答谢谢
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
i:integer;
begin
for i:=1 to 10 do
if DllHandle_rk[i] <> 0 then
FreeLibrary(DllHandle_rk[i]);
self.Close;
end;呵,在dll窗体里我也释放了这上关闭窗体时候的代码
procedure TfrmDLLForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
freeandnil(frmDLLForm);
end;在主窗体关闭的时候的代码
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
i:integer;
begin
for i:=1 to 10 do
if DllHandle_rk[i] <> 0 then
FreeLibrary(DllHandle_rk[i]);
self.Close;
end;以上是子窗体和主窗体关闭时的代码,请帮我看看有啥问题吗?最好能不能用主窗体来控制释放子窗体呢?因为用户有时候不一定是关了子窗体再关主窗体的,他们有可能直接关主窗体。请帮我看看如何用主窗体释放全部的子窗体,麻烦了,谢谢!
dll中的窗体,直接free就可以了呀,注意把资源都放在窗体的类内就可以了,哈哈
那我删除一些代码以下就只留调用dll时候的代码
调用字窗体 //我定义了一个DllHandle_rk[]:Thandle 数组用于存放dll的handle
function TForm1.Dllfrmshow(frm:integer;dllname:string):boolean;
type
Windowmax= function :boolean;stdcall;
openform =function (pbase:basemsg):string;
var
DLLHandle: THandle;
DLLSub: InvokeDLLForm;
Tf:Windowmax;
Tf2:openform;
Tp,Tp2:TFarProc;
begin
DllHandle_rk[frm] :=LoadLibrary(PChar(extractfilepath(application.ExeName)+'dll\'+dllname));
if DllHandle_rk[frm] = 0 then
begin
showmessage('调入失败!');
exit;
end; try
if DllHandle_rk[frm] <> 0 then
begin
@DLLSub := GetProcAddress(DllHandle_rk[frm],'CreateDLLForm');
if Assigned(DLLSub) then
DLLForm := DLLSub(Application, Screen);
////////////////////传递pbase类给dll
Tp2:=GetProcAddress(DllHandle_rk[frm],PChar('openform')); /////open dll函数
Pbase.userid :='yzl';
Pbase.phandle:=Handle;
Pbase.Windowsid:=frm;
if Tp2 <> nil
then
begin
Tf2:=openform(Tp2);
BitBtn_Competence[frm]:=Tf2(pbase);
end;
////////////////////传递pbase类给dll end;
except
FreeLibrary(DllHandle_rk[frm]);
end; end;
end; 以下是主窗体关闭的代码
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
i:integer;
begin
for i:=1 to 10 do
if DllHandle_rk[i] <> 0 then
FreeLibrary(DllHandle_rk[i]);
self.Close;
end;
万分感谢 [email protected]我刚才调式了以下发现问题应该是出在调用openform这个函数上,我把这段函数屏蔽掉关闭就没出错了!function TForm1.Dllfrmshow(frm:integer;dllname:string):boolean;
type
Windowmax= function :boolean;stdcall;
openform =function (pbase:basemsg):string;
var
DLLHandle: THandle;
DLLSub: InvokeDLLForm;
Tf:Windowmax;
Tf2:openform;
Tp,Tp2:TFarProc;
beginDllHandle_rk[frm] :=LoadLibrary(PChar(extractfilepath(application.ExeName)+'dll\'+dllname));
if DllHandle_rk[frm] = 0 then
begin
showmessage('调入失败!');
exit;
end;
try
if DllHandle_rk[frm] <> 0 then
begin
@DLLSub := GetProcAddress(DllHandle_rk[frm], 'CreateDLLForm');
if Assigned(DLLSub) then
DLLForm := DLLSub(Application, Screen);
/////////////////我把这段屏蔽掉关闭主窗体时候就没出错,这段应该咋改呢?
////////////////////传递pbase类给dll
Tp2:=GetProcAddress(DllHandle_rk[frm],PChar('openform')); /////open dll函数
Pbase.userid :='yzl';
Pbase.phandle:=Handle;
Pbase.Windowsid:=frm;
if Tp2<>nil
then
begin
Tf2:=openform(Tp2);
BitBtn_Competence[frm]:=Tf2(pbase);
end;
////////////////////传递pbase类给dll
/////////////////我把这段屏蔽掉关闭主窗体时候就没出错,这段应该咋改呢?
end;
except
FreeLibrary(DllHandle_rk[frm]);
end;
end;
应该用 try ..finally ..end.这样就会每次调用完DLL后,执行释放FreeLibrary(DllHandle_rk[frm]); try ..except ..end; 语句是在出现异常时才释放DLL,因此你正常情况下就会出错。DLL的释放,最好放在调用的子窗体中,用完后,及时释放。
你放在主窗体关闭的代码中, 首先一点, 你的 DLLHandle: THandle; 声明的全局与局部关系就弄错了。
function TForm1.Dllfrmshow(frm:integer;dllname:string):boolean;
type
Windowmax= function :boolean;stdcall;
openform =function (pbase:basemsg):string;
var
DLLHandle: THandle;
DLLSub: InvokeDLLForm;
Tf:Windowmax;
Tf2:openform;
Tp,Tp2:TFarProc;
begin DllHandle_rk[frm] :=LoadLibrary(PChar(extractfilepath(application.ExeName)+'dll\'+dllname));
if DllHandle_rk[frm] = 0 then
begin
showmessage('调入失败!');
exit;
end;
try
if DllHandle_rk[frm] <> 0 then
begin
@DLLSub := GetProcAddress(DllHandle_rk[frm], 'CreateDLLForm');
if Assigned(DLLSub) then
DLLForm := DLLSub(Application, Screen);
/////////////////我把这段屏蔽掉关闭主窗体时候就没出错,这段应该咋改呢?
////////////////////传递pbase类给dll
Tp2:=GetProcAddress(DllHandle_rk[frm],PChar('openform')); /////open dll函数
Pbase.userid :='yzl';
Pbase.phandle:=Handle;
Pbase.Windowsid:=frm;
if Tp2 <> nil
then
begin
Tf2:=openform(Tp2);
BitBtn_Competence[frm]:=Tf2(pbase);
end;
////////////////////传递pbase类给dll
/////////////////我把这段屏蔽掉关闭主窗体时候就没出错,这段应该咋改呢?
end;
except
FreeLibrary(DllHandle_rk[frm]);
end;
end;
openform =function (pbase:basemsg):string; Tf2:openform;Tp2:TFarProc;Tp2:=GetProcAddress(DllHandle_rk[frm],PChar('openform')); /////open dll函数
Pbase.userid :='yzl';
Pbase.phandle:=Handle;
Pbase.Windowsid:=frm;
if Tp2 <> nil
then
begin
Tf2:=openform(Tp2); ///[openform(Tp2)]这里表面看起来类型是不匹配的哦,有可能这里都是指针型的,所以没有报错给你。
///[Tf2:=openform(Tp2)]这里,你的Tf2:openform;,那么Tf2实际是一个Function,而不是一个变量了。
///要了解哦。
,
BitBtn_Competence[frm]:=Tf2(pbase);
end; 你这里可以直接写成如下的样式try一下(如果你的TFarProc和openform的格式一样的话)
Tp2:=GetProcAddress(DllHandle_rk[frm],PChar('openform')); /////open dll函数
Pbase.userid :='yzl';
Pbase.phandle:=Handle;
Pbase.Windowsid:=frm;
if Tp2 <> nil then begin
BitBtn_Competence[frm]:=Tp2(pbase); ///改动后
end;
^_^
编译到这行的时候出错,麻烦再帮看看
BitBtn_Competence[frm]:=Tp2(pbase);
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Menus, Buttons, ComCtrls, ToolWin, ExtCtrls, StdCtrls;
type
basemsg=packed Record
phandle:Thandle;
userid:string;
Windowsid:integer;
BitBtn_Control:string;
end;type
InvokeDLLForm = function(App: TApplication; Scr: TScreen): TForm;
TForm1 = class(TForm)
ToolBar1: TToolBar;
BitBtn1: TSpeedButton;
BitBtn2: TSpeedButton;
BitBtn3: TSpeedButton;
BitBtn4: TSpeedButton;
ToolButton3: TToolButton;
BitBtn5: TSpeedButton;
BitBtn6: TSpeedButton;
BitBtn7: TSpeedButton;
BitBtn8: TSpeedButton;
BitBtn9: TSpeedButton;
bitbtn11: TSpeedButton;
bitbtn12: TSpeedButton;
BitBtn10: TSpeedButton;
MainMenu1: TMainMenu;
N111: TMenuItem;
SBar: TStatusBar;
Timer1: TTimer;
N1: TMenuItem;
Image1: TImage;
N2: TMenuItem;
N3: TMenuItem;
function Dllfrmshow(frm:integer;dllname:string):boolean;
procedure N2Click(Sender: TObject);
private
{ Private declarations }
public
DllHandle_rk:array[0..150] of Thandle;//DLL文件存放入口
BitBtn_Competence:array[0..150] of string;
{ Public declarations }
end;
var
Form1: TForm1;
DLLForm: TForm;
Windowsid:integer;
Pbase:basemsg;
implementation
{$R *.dfm}function TForm1.Dllfrmshow(frm:integer;dllname:string):boolean;
type
Windowmax=function :boolean;stdcall;
openform=function (pbase1:basemsg):string;
var
DLLHandle:THandle;
DLLSub:InvokeDLLForm;
Tf:Windowmax;
Tf2:openform;
Tp,Tp2:TFarProc;begin DllHandle_rk[frm]:=LoadLibrary(PChar(extractfilepath(application.ExeName)+'dll\'+dllname));
DLLHandle:=DllHandle_rk[frm];
if DllHandle_rk[frm]=0 then
begin
showmessage('调入失败!');
exit;
end;
try
if DllHandle_rk[frm] <> 0 then
begin
@DLLSub := GetProcAddress(DllHandle_rk[frm],'CreateDLLForm');
if Assigned(DLLSub) then
DLLForm := DLLSub(Application,Screen);
/////////////////我把这段屏蔽掉关闭主窗体时候就没出错,这段应该咋改呢?
////////////////////传递pbase类给dlltry
Tp2:=GetProcAddress(DLLHandle,PChar('openform')); /////open dll函数
Pbase.userid :='yzl';
Pbase.phandle:=Handle;
Pbase.Windowsid:=frm;
if Tp2<>nil
then
begin
Tf2:=openform(Tp2);
//BitBtn_Competence[frm]:=Tf2(pbase);
end;
finally
FreeLibrary(DLLHandle);
end;
////////////////////传递pbase类给dll
/////////////////我把这段屏蔽掉关闭主窗体时候就没出错,这段应该咋改呢?end;
except
FreeLibrary(DllHandle_rk[frm]);
end;
end; procedure TForm1.N2Click(Sender: TObject);
begin
Dllfrmshow(1,'prjDLL2.dll');
end;end.以下是dll原码
unit DLLFormUnit;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Menus, StdCtrls, ExtCtrls, DB, ADODB, Grids, DBGrids; type
basemsg=packed Record
phandle:Thandle;
userid:string;
Windowsid:integer;
BitBtn_Control:string;
end;
const
WM_ModifyAA= WM_USER + 20;
WM_ModifyAB= WM_USER + 21;
type
TfrmDLLForm = class(TForm)
Label1: TLabel;
Button1: TButton;
procedure Button1Click(Sender: TObject); private
/// procedure WMSysCommand(var Msg:TMessage);message WM_SYSCOMMAND; //////最大化最小化事件
{ Private declarations }
public
{ Public declarations }
end;
function openform(pbase:basemsg):string;
function save:boolean;stdcall;
function Windowmax:boolean;stdcall;
function Cancellation:boolean;stdcall;
function Preview:boolean;stdcall;
function Print:boolean;stdcall;
function Add:boolean;stdcall;
function Delete:boolean;stdcall;
function modif:boolean;stdcall;
function View:boolean;stdcall;
function Refresh:boolean;stdcall;
function Audit:boolean;stdcall;
function Derived:boolean;stdcall;
var
frmDLLForm: TfrmDLLForm;
puserid:string;
fhandle:Thandle;
Windowsid:integer;
BitBtn_Control:string;
implementationuses Unit1;{$R *.dfm}
///在主窗体调用dll的时候dll在这个函数了接收主窗体传过来的变量
function openform(pbase:basemsg):string;
begin
fhandle:=pbase.phandle;
puserid:=pbase.userid;
Windowsid:=pbase.Windowsid;
BitBtn_Control:='110110111011'; ////////////////////////按钮权限
result :=BitBtn_Control;
end;
end.
请各位帮看看为什么调用dll函数的时候关闭时候会报错,谢谢各位了!
答案都已經告訴你了!!
對比一下你dll所export出來的函數,出錯的那個函數有返回string!!!!
所以你dll的library要uses sharemem!!!
把你dll的工程文件大家看看,先確定一下有沒有加~,再考慮是不是其他的問題~~~~
openform =function (i:inetger):string传普通的字符或数字就不会出错,那如果要传一个类过去的话要怎么传呢!!
try
Tp2:=GetProcAddress(DLLHandle,PChar('openform')); /////open dll函数
Pbase.userid :='yzl';
Pbase.phandle:=Handle;
Pbase.Windowsid:=frm;
if Tp2 <> nil
then
begin
Tf2:=openform(Tp2);
//BitBtn_Competence[frm]:=Tf2(pbase);
end;
finally
FreeLibrary(DLLHandle);
end;
我在dll的library里加了sharemem还是报错!!这是library代码library prjDLL;{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View 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 BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }uses
SysUtils,
Forms,
Windows,
Messages,
Classes,
sharemem,
DLLFormUnit in 'DLLFormUnit.pas' {frmDLLForm},
Unit1 in 'Unit1.pas' {Form1};{$R *.res}var
DLLApp: TApplication;
DLLScr: TScreen;
function CreateDLLForm(App: TApplication; Scr: TScreen):TForm;
var
ptr:PLongInt;
begin
Application := App;
Screen := Scr;
Application.CreateForm(TfrmDLLForm, frmDLLForm);
Application.CreateForm(TForm1, Form1);
result:=frmDLLForm;
end;procedure ExitDLL(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then
begin
Application := DLLApp;
Screen := DLLScr;
end;
end;
exports
CreateDLLForm,save,Cancellation,Preview,Print,Add,Delete,modif,View,Refresh,Audit,Derived,Windowmax,openform;begin
DLLApp := Application;
DLLScr := Screen;
DLLProc := @ExitDLL;end.
我感觉不是这个问题。说真的,想帮你debug一下,不过代码好多,好晕,哈哈,你可以直接把source mail给我,我帮你debug看一下。看来还是蛮倔的小伙子哦,哈哈,有点像我当年……
万分感谢!我现在就发原码给你麻烦您帮我看看,谢谢!
要看清楚這段
Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause
你看看把sharemem放在哪裡了?
要放在第一個才行!
问题有如下几个。
1)你的主程序中,在关闭是有释放handle,但没有置零,这样会导致以后使用时出错。释放的动作不会为你清零。
2)关于你总报错的问题,这个问题delphi的编译器不是每次都会有,但发生的机率还不小的,具体的原因可能要问Borland了,就是用string做为result传出,我帮你改了shortstring,你也可以用pchar。[就像你说的,如果把这个function的参数改为integer那就可以不用修改string这个result]PS:有时候我也搞不懂Borland的家伙是怎么回事,我曾经遇到过一个record里必须要写双数个integer型的变量才可以的情况,晕死吧?!
3)你的DLL资源释放问题,你有重置回Application,screen的句柄,但是没有销毁对象frmDLLForm,Form1。
好了这个问题就到这里了。to Avan_LauImportant note about DLL memory management: ShareMem must be the
first unit in your library's USES clause 这里是针对其他IDE调用delphi开发的dll时才会需要用到的,如果是delphi本身调用,是不需要的。而且还不可以随便加哦,加了没有导入那个dll,还有更离谱的事情要发生的。
^_^ 好了,回家接老婆下班了,兄弟们,明天见……
但您是否忽略了那段關於sharemem的說明?既然您說‘针对其他IDE调用delphi开发的dll时才会需要用到的’,那麼您把返回類型string改為pchar作何解釋。當然,你這樣改了,就不需要加sharemem了。
為論證這個問題,請lz先不要用您修改後的代碼,先把sharemem單元改放到第一位看看!
另外,我想你搞錯了!如果調用方与被調用方都是Delphi程序,而且要使用string或動態作參數,則雙方工程文件的第一包含單元必須是ShareMeM;如果調用方不是Delphi程序,則string、動態數組、包含string或動態的复合數據類型及類實例,都不能作為參數及返回值。sharemem應該是針對 dll中delphi string 的資源控管作用!
在sharemem上面,我的确有不求甚解得地方,呵呵……
但当你看到你的Dll原本可以呼叫,但在引用了它之后反而不行时……,我想你的习惯上就会放弃再使用string了。
当养成这样的习惯之后,也会发现机会不会在碰到sharemem了,Delphi的IDE是很强大的,但是还是有不少Bug的,不知道楼上的有多少人,遇到过多少。
Avan_Lau老兄,你也可以baidu一下sharemem,看看有多少人在用了sharemem之后会成功的,要写优良的程序,就不要去触及IDE的敏感区域了,否则,对开发人员对客户,都是很抓头的事情。
你说是否是这样?^_^?
對delphi ide 了解不是很多,不敢作評論啦。
就目前我們公司產品的運作狀況來看,一切都ok!應該是與架構設計和細節控制方面有關!
希望有機會可以向您請教請教!
兩位:我的mail是[email protected];
Forms,
DLLFrm in 'DLLFrm.pas' {FrmDLL};procedure SetApplication(mHandle: THandle); stdcall;
begin
Application.Handle := mHandle;
end;
procedure showfirst; stdcall;
begin
Application.CreateForm(TFrmDLL,FrmDLL);
try
FrmDLL.ShowModal;
finally
FrmDll.Free;
end;
end;procedure showsecond; stdcall;
begin
Application.CreateForm(TFrmDLL,FrmDLL);
FrmDLL.Show;
end;exports
SetApplication,
showsecond,
showfirst; begin
end.//调用
procedure TForm1.btnShowClick(Sender: TObject);
begin
showsecond;
end;