我在dll中创建了一个打开表单然后打印报表的过程。 这个过程完全适用于exe。 我已经将包含此过程的单元和表单包装在一个dll中,并按如下方式导出过程:
{$R *.res}
Procedure PrintTopSellers; stdcall;
begin
Form1 := TForm1.create(nil);
GetMonth := TGetMonth.create(nil);
Form1.PrintTopSellers;
end;
exports PrintTopSellers;
begin
end.
现在我从exe中调用此过程PrintTopSellers,如下所示:
procedure TForm1.Button5Click(Sender: TObject);
type
TRead_iButton = function :integer;
var
DLL_Handle: THandle;
Read_iButton: TRead_iButton;
Begin
DLL_Handle := LoadLibrary('c:\Catalog.dll');
if DLL_Handle <> 0 then
begin
@Read_iButton:= GetProcAddress(DLL_Handle, 'PrintTopSellers');
Read_iButton;
end;
application.ProcessMessages;
FreeLibrary(DLL_Handle);
end;
对程序的调用完美无缺。但是,在我关闭调用exe之后,我收到了访问冲突 - “地址00BAC89C的访问冲突。读取地址00BAC89C。”
感谢任何帮助。我使用的是Delphi 7。 感谢
答案 0 :(得分:6)
您正在DLL中创建一个窗口控件Form1
。但你永远不会破坏它。然后卸载DLL,卸载实现DLL创建的所有窗口的窗口过程的代码。大概是当进程关闭时,会调用窗口过程,但不再有代码了。
通过销毁DLL创建的所有对象来解决问题。在PrintTopSellers
终止时,我认为最好的方法就是这样做。
Procedure PrintTopSellers; stdcall;
begin
Form1 := TForm1.create(nil);
try
GetMonth := TGetMonth.create(nil);
try
Form1.PrintTopSellers;
finally
GetMonth.Free;
end;
finally
Form1.Free;
end;
end;
在加载DLL的代码中,TRead_iButton
声明不正确。它应该是
TRead_iButton = procedure; stdcall;
但这实际上并没有解释这里的问题,因为签名不匹配对于无参数的过程是良性的。
答案 1 :(得分:3)
&#34; TRead_iButton = function:integer;寄存器;&#34;
&#34;程序PrintTopSellers; STDCALL;&#34;
绝对不同的约定/类型,不是吗?
让它们变得一样。 更好的沟渠DLL和使用包(BPL),然后编译器将使您免受此类错误
我们也没有在Form1.PrintTopSellers和TGetMonth中看到代码。所有这些都可以在主机exe中留下一些悬空指针,这将在DLL卸载后获得访问权。
准确显示导致AV的函数调用链 - 它被称为堆栈跟踪。 调试信息+一些像Jedi CodeLibrary(由Delphi IDE使用)的excaption中断madExcept,EurekaLog,synopse日志和许多其他存在。
Display the call stack in a Delphi Win32 application
DLL或EXE是否使用运行时包?