【问题标题】:Calling a DLL function with more than one return values调用具有多个返回值的 DLL 函数
【发布时间】:2011-07-01 17:00:12
【问题描述】:

我的 DLL 可能会一次性向 exe 发送多个结果/返回值。我仍然不明白如何制作回调函数,以便 DLL 可以与主机应用程序通信。

这是场景:

应用:

type
  TCheckFile = function(const Filename, var Info, Status: string): Boolean; stdcall;

var
  CheckFile: TCheckFile;
  DLLHandle: THandle;

Procedure Test;
var
Info,Status : string;
begin
....
// load the DLL 
DLLHandle := LoadLibrary('test.dll');
    if DLLHandle <> 0 then
    begin
      @CheckFile := GetProcAddress(DLLHandle, 'CheckFile');
      if Assigned(CheckFile) then
        beep
      else
        exit;
    end;

// use the function from DLL
if Assigned(CheckFile) then
  begin
    if CheckFile(Filename, Info, Status) then
    begin
    AddtoListView(Filename, Info, Status);
    end;
  end;
...
end;

DLL:

function CheckFile(const Filename, var Info,Status: string): Boolean; stdcall;
  var
    Info, Status: string;
  begin   
    if IsTheRightFile(Filename, Info,Status) then
    begin
      result := true;
      exit;
    end
    else
    begin
      if IsZipFile then
      begin
        // call function to extract the file
        ExtractZip(Filaname);
        // check all extracted file
        for i := 0 to ExtractedFileList.count do
        begin
          IsTheRightFile(ExtractedFile, Info, Status) then
          // how to send the Filename, Info and Status to exe ?? // << edited
          // SendIpcMessage('checkengine', pchar('◦test'), length('◦test') * SizeOf(char)); error!
          // "AddtoListView(Filename, Info);" ???
        end;
      end;
    end;
  end;

实际上我仍然从上面的代码中得到一个错误。因此,就我而言,我需要您的帮助来解释和确定将数据从 DLL 发送到 appp 的正确方法。

【问题讨论】:

  • GetProcAddress(DLLHandle, 'CheckFile'); - 它返回一个有效的句柄吗?您没有忘记在 IMPORTS 部分指定您的 dll 功能吗?
  • 您的意思是InfoStatus 而不是InfoFilename?因为Filenameconst,不能修改。要修改InfoStatus,您需要在您的DLL 函数中为其设置一个值。请注意,如果您不在 uses 子句中使用 ShareMem,则传递字符串可能会导致问题。
  • @heximal :是的,它返回一个有效的句柄。我确信导入/导出功能没有问题。我尝试在 DLL 中使用虚拟函数。
  • @ba__friend。嗯..我使用 FastMM 是因为我希望非 Delphi exe 可以使用我的 DLL。
  • 您的代码是否真的包含带有Info & Status 形式参数 Info & Status 局部变量的函数?

标签: delphi dll


【解决方案1】:

您在正确的路线上,但我能看到的最明显的问题是使用 string 变量。这些是堆分配的,由于您有两个单独的内存管理器,您将在一个堆上分配(在 DLL 中),然后在另一个堆上释放(在应用程序中)。

有几个选项。一种选择是共享内存管理器,但出于各种原因,我不建议这样做。无需进入它们,您在注释中声明您希望非 Delphi 应用程序能够使用您的 DLL,这将排除使用共享内存管理器。

另一种选择是强制调用应用程序为字符串分配内存,然后让您的 DLL 复制到该内存中。这工作正常,但有点费力。

相反,我会使用可以在一个模块中分配但在不同模块中释放的字符串类型。 COM BSTR 就是这样一种类型,在 Delphi 术语中它是 WideString。更改代码以将WideString 用于任何导出的函数。


我还会简化导入/导出过程并使用隐式动态链接。

DLL

function CheckFile(
  const Filename: WideString; 
  var Info, Status: WideString
): Boolean; stdcall;

应用

function CheckFile(
  const Filename: WideString; 
  var Info, Status: WideString
): Boolean; stdcall; external 'test.dll';

procedure Test(const FileName: string);
var
  Info, Status: WideString;
begin
  if CheckFile(Filename, Info, Status) then
    AddtoListView(Filename, Info);
end;

【讨论】:

  • 我使用 FastMM。我还需要担心吗?
  • @user 确实如此,因为您将拥有两个 FastMM 分配器实例。虽然您可以共享内存管理器,但您的 DLL 的任何其他潜在客户呢?我强烈建议避免导出由私有分配器分配的内存。你可以用 WideString 来做,因为它依赖于共享的 COM 分配器。
  • 就我而言,我需要一个静态链接。我会试试 WideString。在我看来,我只需要对导出的参数(=字符串)使用 WideString 并且可以在其他函数中使用字符串,对吧?玩 DLL 对我来说是新事物。
  • DLL=动态链接。 “我需要静态链接”是什么意思?
  • @user 不要在 DLL 的边界使用字符串。非 Delphi 客户端无法调用该函数,不同的 Delphi 版本也可能失败。使用WideStringPChar
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多