关于FreeLibrary的疑问(50分)

  • 主题发起人 主题发起人 cnhotel
  • 开始时间 开始时间
C

cnhotel

Unregistered / Unconfirmed
GUEST, unregistred user!
目标:调用dll中的窗体显示

Dll:
function ShowCgGysForm(AHandle:THandle):boolean;
begin
Result := True;
try
CoInitialize(nil);
Application.Handle:=AHandle;//挂靠到主程序容器中
dm:=Tdm.Create(Application);
cggysgl_f := Tcggysgl_f.Create(Application);
try
cggysgl_f.ShowModal;
except
on e:exception do
begin
cggysgl_f.Free;
dm.Free;
end;
end;
except
Result:=False;
end;
end;

主程序中这样调用:
var
ShowCgGysForm: TShowCgGysForm;
TmpHandle:THandle;//句柄
begin
try
begin
TmpHandle:=LoadLibrary('stock.dll');
if TmpHandle<32 then
begin
Messagebox(Handle,'没有找到附带DLL文件,请确认程序是否完整!','加载DLL失败',MB_OK+MB_ICONEXCLAMATION);
Exit;
end ;
@ShowCgGysForm:=GetProcAddress(TmpHandle,'ShowCgGysForm') ;
if @ShowCgGysForm<>nil then
try
ShowCgGysForm(Application.Handle);//DLL中的窗口创建在应用程序中
except
raise Exception.Create('加载DLL失败');
end;
end;
finally
FreeLibrary(TmpHandle);
//上面这样写关闭的时候产生异常.没有正常释放stock.dll?
//改成: FreeLibrary(Application.Handle);
//这样不出错,奇怪了,看到很多例子上都是写的FreeLibrary(TmpHandle);
//有人提示问题可能出在 Dll的Application.Handle与应用程序的Application.Handle 的引用上.
//导致在我需要在主程序关闭时多一道手续检测dll释放(麻烦):
// if HandleCall<>0 then
begin
FreeLibrary(HandleCall);
HandleCall:=0;
end;
end;
end;

请大家帮看看什么原因,好多例子上释放dll的时候都是写的FreeLibrary(TmpHandle);
为什么我那样写就出错,非要换成FreeLibrary(Application.Handle);
 
关闭那个dll调用的窗口时错误提示是:
"External Exception C000001E"
 
自己顶自己了~~~
 
一早再顶下~
 
Application.Handle:=AHandle;//挂靠到主程序容器中
应该是这句有问题吧,在DLL中不能使用APPLICATION吧
 
ShowCgGysForm(Application.Handle);//DLL中的窗口创建在应用程序中
FreeLibrary(TmpHandle);

除非这段代码 ShowCgGysForm(Application.Handle); 在执行 FreeLibrary(TmpHandle);之前释放相关数据当然也包括窗体 否则会产生冲突!.
 
这种东西用接口的方法来实现效果会比好些, 控制起来也方便些呀. 如果想立即释放Dll应该是由Dll主动发起的.目前我还没找到更好的方法实现之.关注一下.
 
动态调用。
自已看
dll 调用部分:

{****************************************************************}
{ }
{ Project: DllDebug             }
{ Copyright(c) 2003, 2005                 }
{ Unit for UCommonUnit                   }
{ Create : 2003-01-05 by 林红卫             }
{ Modify : 2003-01-16 by 林红卫             }
{ }
{****************************************************************}

unit UCommonUnit;

interface

uses
Windows,
SysUtils,
Forms;

type
TRunDLL = procedure(DLLName, FormName, FormCaption: PChar;
aApp: TApplication; Scr: TScreen) stdcall;

procedure RunDLLForm(DLLName, FormName, FormCaption: string;
aApp: TApplication; Scr: TScreen) stdcall;

implementation

procedure RunDLLForm(DLLName, FormName, FormCaption: string;
aApp: TApplication; Scr: TScreen) stdcall;
var
RunDLL: TRunDLL;
GetDllHWND: HWND;
begin
GetDllHWND := LoadLibrary(PChar(DllName));
try
if GetDllHWND < 32 then
begin
MessageBox(0, '没有找到附带DLL文件,请确认程序是否完整!',
'加载DLL失败', MB_OK);
Exit;
end;

@RunDLL := GetProcAddress(GetDllHWND, 'RunDLL');
if @RunDLL <> nil then
try
RunDLL(PChar(UpperCase(Trim(DLLName))), PChar(UpperCase(Trim(FormName))),
PChar(FormCaption), aApp,Scr);
except
raise Exception.Create('T' + FormName + '不存在!');
end;
finally
FreeLibrary(GetDllHWND);
end;
end;

end.

dll :

{****************************************************************}
{ }
{ Project: UDllTest               }
{ Copyright(c) 2003, 2005                 }
{ Unit for UDllTest                   }
{ Create : 2003-01-05 by 林红卫             }
{ Modify : 2003-01-16 by 林红卫             }
{ }
{****************************************************************}

library UDllTest;

uses
SysUtils,
Forms,
Messages,
Variants,
Windows,
Classes,
UFrmTestForm1 in 'UFrmTestForm1.pas' {Form1},
UFrmTestForm2 in 'UFrmTestForm2.pas' {Form2};

var
DLLApp: TApplication;
DLLScreen: TScreen;

procedure RunDLL(DLLName, FormName, FormCaption: PChar;
aApp: TApplication; Scr: TScreen) stdcall;
var
TheClass: TPersistentClass;
aForm: TForm;
begin
Application := aApp;
Screen := Scr;
RegisterClasses([TForm1, TForm2]);

TheClass := GetClass('T' + FormName);
if (TheClass = nil) then
GetLastError;

if TheClass.InheritsFrom(TForm)
and (TheClass <> TForm) then
begin
aForm := TForm(TheClass.Create).Create(nil);
aForm.Caption := FormCaption;
try
aForm.ShowModal;
finally
FreeAndNil(aForm);
end;
end;
end;

procedure DLLUnloadProc(dwReason: DWORD);
begin
if dwReason = DLL_PROCESS_DETACH then
begin
Application := DLLApp; //恢复
Screen := DLLScreen;
end;
end;

exports
RunDLL;

begin
DLLApp := Application; //保存 DLL 中初始的 Application 对象
DLLScreen := Screen;
DLLProc := @DLLUnloadProc; //保证 DLL 卸载时恢复原来的 Application
DLLUnloadProc(DLL_PROCESS_DETACH);
end.
 
谢谢hzjone的例子,很好
 
后退
顶部