1

在我的项目中,我有一个 Windows 应用程序和一个 dll。我这样写了dll:

library MyDLL;

uses
  System.SysUtils,
  System.Classes;

{$R *.res}

function Prova: string; export;
begin
  result := 'prova';
end;

exports Prova;

begin
end.

在主程序中我调用了例程:

unit FrmMain;

interface

uses
 // declaration uses // 

function Prova: string; external 'MyDLL.dll';

type    
 // declaration type //

implementation

begin
  ...
  TAdvEdit1.Text := Prova;  // [1] // 
  ...
end;

end.

当我编译所有项目时没有报告错误,并且状态报告成功,但应用程序没有启动。如果我删除线 [1] 那么它工作正常。通常,当我调用函数 Prova 时,应用程序不会启动。我能解决这个问题吗?非常感谢。

4

2 回答 2

3

您描述的行为是您的应用程序无法加载时发生的情况。从调试器运行时,您会遇到静默失败。在没有调试器的情况下运行时,您将看到一条错误消息,“应用程序无法初始化...”。这将提供详细信息。

在您的情况下,似乎可能的原因是库加载器无法解析 DLL 的依赖关系。这就是应用程序在对外部函数的调用被删除时运行的原因。当您删除该调用时,您也删除了对外部 DLL 的依赖。通过确保可以加载 DLL 来解决问题。例如,将其放在与可执行文件相同的目录中。

调试器的静默失败相当令人沮丧。一旦你经历了几次,你就会知道该怎么做——在没有调试器的情况下运行以找出真正出错的地方。

我还建议您不要跨模块边界传递托管的 Delphi 字符串。这将迫使您对可执行文件和 DLL 使用相同的编译器。如果您要接受该约束,那么您也可以使用包。就您的代码而言,它需要使用 ShareMem 才能工作。但我不建议这样做。

于 2012-11-11T14:06:23.523 回答
2

您的程序和 DLL 有单独的内存管理器。作为一般规则,从 DLL 分配的内存不应在应用程序内部使用(反之亦然)。哪里来的分配?在Delphi中,“字符串”是托管类型,即当您将一些文本分配给字符串变量(在您的情况下为结果:='prova')时,Delphi(在幕后)使用DLL的内存管理器为该字符串分配内存。然后,例如,如果您在主应用程序中分配其他文本值,则重新分配使用应用程序的内存管理器,这很糟糕,即应用程序的 MM 正在触及它尚未分配自己的内存。

要解决此问题,您必须在应用程序(.dpr 文件)和 DLL中包含“SimpleShareMem”(Delphi >= 2010 IIRC?)单元作为 USES 子句的第一个单元:

library MyDLL;

uses
  SimpleShareMem, // **MUST BE THE FIRST UNIT**
  System.SysUtils,
  System.Classes;
...


program YourApp;

uses
  SimpleShareMem, // **MUST BE THE FIRST UNIT**
  // declaration uses // 

此方法的示例可在“开始 > 程序 > Embarcadero RAD Studio > 示例 > Delphi > RTL > SimpleShareMem ”中找到

您还可以使用 PCHAR 在 DLL 和 APP 之间传输字符串。

于 2012-11-11T12:18:32.877 回答