【问题标题】:Delphi: Access violation after calling procedure in dllDelphi:在dll中调用过程后访问冲突
【发布时间】:2012-09-12 17:03:21
【问题描述】:

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

感谢任何帮助。我正在使用德尔福 7。 谢谢

【问题讨论】:

  • 安装堆栈跟踪器,如 Jedi CodeLibrary(由 Delphi IDE 使用)、Eureka、madExcept 中的异常对话框等...使用调试信息运行。检查异常的堆栈跟踪以了解火车在轨道上的位置。
  • 你已经解决了这个问题吗?我有一些问题。但仅限于XP。在Win7上运行良好。我只需要在dll中创建并释放表单,然后在exe关闭后出现该错误。我正在使用 DelphiXE。

标签: delphi delphi-7


【解决方案1】:

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

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

【讨论】:

  • 我们无法确定 GetMoth 是什么,但可能更简单的方法是 GetMonth := TGetMonth.create(Form1)
  • @Arioch'The 这也是一个猜测。也许TGetMonth 构造函数会收到其他东西。
  • 当进程关闭时,窗口过程被调用由谁?他可以通过调用 TForm1.create(Application) 来修复它吗?
  • @Paul DLL 有自己的应用程序实例。卸载 DLL 时,该实例将被销毁。这意味着它拥有的对象也会被销毁。所以表单将被释放。
  • 除非这是您第一次看到“未声明的标识符”错误,否则您已经知道在收到Application 时该怎么做。在uses 子句中添加声明Application 的单元。文档和经验都应该告诉您它是 Forms 单元。
【解决方案2】:

"TRead_iButton = 函数:整数;寄存器;"

"程序 PrintTopSellers;stdcall;"

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

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


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


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

Display the call stack in a Delphi Win32 application


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

【讨论】:

  • 是的,但对于无参数的过程并不重要。
  • GetMonth 表单仅显示一个用于选择月份的组合框。 Form1 显示 GetMonth,然后使用月份打印报告。
  • 首选使用 dll,因为理想情况下我们希望在此应用中使用以其他语言编写的 dll。
猜你喜欢
  • 1970-01-01
  • 2010-11-19
  • 1970-01-01
  • 1970-01-01
  • 2011-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多