【问题标题】:Delphi DLL called from C++ crashes when showing a form显示表单时从 C++ 调用的 Delphi DLL 崩溃
【发布时间】:2011-02-06 15:59:21
【问题描述】:

编辑:愚蠢的问题,已经解决。 Form1nil,因为我没有为它分配新的 TForm1,我忘记了 Delphi 不会像 C++ 那样为你这样做。

我有一个 Delphi DLL,我想将它用于我的 C++ 程序的 GUI,所以对于初学者,我创建了一个表单,并有一个函数可以显示导出的表单,以便 C++ 可以调用它。但是,程序在调用该函数时会崩溃。这是我的代码。 (我使用的是 Delphi 2010)

delphi部分:

unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Tabs, ComCtrls;

type
  TForm1 = class(TForm)
    TabControl1: TTabControl;
    TabSet1: TTabSet;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

function ShowForm(i: Integer) : Integer; export; cdecl;

exports
  ShowForm name 'ShowForm';

implementation

{$R *.dfm}

function ShowForm(i: Integer) : Integer; export; cdecl;
begin
  Form1.Show();

  Result := 3; // random value, doesn't mean anything
end;

end.

这里是 C++ 代码:

HMODULE h = LoadLibrary("delphidll.dll");

if (!h) {
    printf("Failed LoadLibrary (GetLastError: %i)\n", GetLastError());

    return 0;
}

FARPROC p = GetProcAddress(h, "ShowForm");

if (p)
    printf("Found it @ %p\n", p);
else
    printf("Didn't find it\n");

((int(__cdecl *)(int))p)(34);

system("PAUSE");

return 0;

程序打印“找到它@”然后崩溃。如果我在 Delphi DLL 中注释掉 Form1.Show(),它不会崩溃,并且函数返回 3(由 printf 测试)。我错过了一些初始化还是什么?谢谢。

【问题讨论】:

    标签: c++ delphi forms dll crash


    【解决方案1】:

    它崩溃的原因是var Form1: TForm1; 没有初始化。

    var Form1: TForm1; 未初始化的原因,很可能是因为您将unit Main 放入了 DLL 项目,但它最初来自一个 Delphi VCL 项目,您在自动创建列表中有 Form1 .

    自动创建列表意味着 Delphi .dpr 将初始化表单。

    现在您需要手动创建表单,因此您需要从 DLL 中导出这 3 个新例程,并让 C++ DLL 调用它们:

    function CreateForm() : Integer; export; cdecl;
    begin
      try
        Application.CreateForm(TForm1, Form1);
        Result := 0;
      except
        Result := -1;
      end;
    end;
    
    function DestroyForm() : Integer; export; cdecl;
    begin
      try
        if Assigned(Form1) then
        begin
          FreeAndNil(Form1);
          Application.ProcessMessages();
        end;
        Result := 0;
      except
        Result := -1;
      end;
    end;
    
    function DestroyApplication() : Integer; export; cdecl;
    begin
      try
        FreeAndNil(Application);
        Result := 0;
      except
        Result := -1;
      end;
    end;
    

    此外,您应该在您的ShowForm 函数实现的实现周围放置一个try...except 块,如exceptions and other language dependent run-time features should not cross DLL boundaries

    您可能也应该做类似的事情来释放其他可能分配的动态内存。

    --杰罗恩

    【讨论】:

    • Jeroen,很好的答案,但 OP 已经得出这个结论并编辑了 Q!
    • 我的回答中有两件重要的事情不在他的编辑中:try/except 块,以及应用程序的释放。
    • @Jeroen 我不明白你为什么打电话给ProcessMessages,我认为没有理由释放应用程序。
    • 我记得曾经看过一个需要 ProcessMessages 的项目,因为表单在被销毁时会做一些愚蠢的事情。 Application 实例在首次访问时自动创建,因此需要销毁; DLL 自己不会这样做。
    • @Jeroen 如果他要在应用程序中显示在 DLL 中创建的表单,他将需要自己运行消息循环。我从不喜欢抽我主人的信息! Application 对象是在Controls.InitControls 中创建的,它是从initialization 调用的。它在从finalization 调用的匹配例程DoneControls 中被销毁。你不应该释放它。
    猜你喜欢
    • 1970-01-01
    • 2018-09-07
    • 2011-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多