【问题标题】:Passing PChar from Delphi DLL to C将 PChar 从 Delphi DLL 传递给 C
【发布时间】:2013-04-19 10:32:34
【问题描述】:

我目前在动态导入 Delphi DLL 时遇到问题。 Delphi DLL 函数声明如下:

function TEST() : PChar; cdecl;
begin
  Result := '321 Test 123';
end;

在 C++ 中我这样称呼它:

typedef char *TestFunc(void);
TestFunc* Function;
HINSTANCE hInstLibrary = LoadLibrary("Test.dll");
if (hInstLibrary)
{
    Function = (TestFunc*)GetProcAddress(hInstLibrary, "TEST");
    if (Function)
    {
        printf("%s", Function());
    }
}

问题是我只收到字符串的第一个字母。 如何告诉 C++ 字符串在第一个字符之后没有结束?

谢谢

【问题讨论】:

  • 哪个版本的delphi?您需要知道 char 是 1 字节还是 2 字节。
  • 或者尝试使用 PAnsiChar。
  • 我正在使用 Delphi Xe2
  • 哇。 PAnshiChar 正是我想要的!非常感谢!
  • @user2227015 这只能解决您的一个问题。另一个问题更难解决。

标签: c++ delphi delphi-xe2


【解决方案1】:

你有两个问题:

  1. Delphi 发送给您的字符串是 UTF-16 编码的。如果要匹配 char*,则需要编码为 ANSI 并返回 PAnsiChar
  2. 当函数返回时,返回的指针所指的内存可能会被释放。您可以在函数中摆脱它,因为您返回一个字符串文字,该字符串文字作为全局常量保存,在 DLL 的生命周期内持续存在。对于字符串变量,当您的调用者尝试读取已释放的内存时,您将遇到运行时错误。令人困惑的是,这些运行时错误将是间歇性的。您的代码可能看起来有效。当您部署到最重要的客户时,预计会失败!

您解决第 2 项的选项:

  1. 安排调用方分配缓冲区,然后由被调用方填充。
  2. 在共享堆上分配和解除分配字符串。例如带有CoTaskMemAllocCoTaskMemFree 的COM 堆。使用共享堆允许您在一个模块中分配,并在另一个模块中释放。

根据经验,如果可以满足您的需求,请始终首选选项 1。

【讨论】:

  • 我真的不明白问题 2 是关于什么的。由于字符串传递正确,我可以将指针的值传递给另一个字符串,这样原始返回是否被释放就无关紧要了,可以吗?
  • 你对“指针的值”不感兴趣。您对它所指的内存感兴趣。如果该内存在函数返回时被释放,那么您的 C 代码就会有一个无效的指针。然后从该内存中读取是未定义的行为。因此,如果您有一个名为mystr 的Delphi 字符串,并且您在DLL 函数中写入了Result := PAnsiChar(mystr),那么您将遇到麻烦。 Result 引用的内存将在函数返回时被释放。
  • 选项 3:在 dll 中分配(例如 GetMem)并从 DLL 中导出释放例程
猜你喜欢
  • 1970-01-01
  • 2012-08-08
  • 1970-01-01
  • 1970-01-01
  • 2019-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多