5

我在 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。谢谢

4

2 回答 2

6

您正在Form1DLL 中创建一个窗口控件。但你永远不会破坏它。然后,您卸载 DLL,该 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;

但这实际上并不能解释这里的问题,因为签名不匹配对于无参数过程是良性的。

于 2012-09-20T10:42:57.057 回答
3

“TRead_iButton = 函数:整数;寄存器;”

“程序 PrintTopSellers;标准调用;”

完全不同的约定/类型,不是吗?

使它们相同。并且更好地抛弃 DLL 并使用包(BPL),然后编译器将使您免受此类错误的影响


我们也看不到 Form1.PrintTopSellers 和 TGetMonth 中的代码。所有这些都可以在主机 exe 中留下一些悬空指针,这些指针会在 DLL 卸载后获得访问权限。


准确显示导致 AV 的函数调用链 - 它称为堆栈跟踪。调试信息 + 一些 excaption 中断,如 Jedi CodeLibrary(由 Delphi IDE 使用)madExcept、EurekaLog、概要日志和许多其他存在。

在 Delphi Win32 应用程序中显示调用堆栈


DLL 或 EXE 是否使用运行时包?

于 2012-09-20T10:43:20.320 回答