【问题标题】:How do I return a string from DLL to Inno Setup Pascal Script如何将字符串从 DLL 返回到 Inno Setup Pascal 脚本
【发布时间】:2014-02-05 10:13:41
【问题描述】:

我在一个 DLL 中有两个 C 函数,它们在定义文件中定义并导出以在 Inno Setup 中使用。

char* __stdcall GetName()
{
        return "Kishore";
}
void __stdcall getName(char* strName)
{
     strcpy(strName, "Kishore");
}

Inno Setup 代码将加载自定义 DLL 并调用函数/过程以返回名称

{ Inno Setup script }
[Code]
procedure  getName(MacAddress: String);
external 'getName@files:MyDll.dll stdcall setuponly';

function  GetName():PAnsiChar;
external 'GetName@files:MyDll.dll stdcall setuponly';

function NextButtonClick(CurPage: Integer): Boolean;
var
  StrName: String;
begin
  SetLength(StrName,15);    
  getName(StrName); { displaying only single character }
  StrName := GetName(); { this call is crashing }
end

如何在 Inno Setup 脚本中检索名称而不使其崩溃?

【问题讨论】:

  • getName 函数原型更改为使用 AnsiString 而不是 string,因为您使用了 Unicode 版本的 Inno Setup 但 char 键入您的 C 代码。并且,不要使用您的 GetName 函数,因为这将是 DLL 需要为语义错误的字符串分配和释放内存。
  • 我想从 getName 中检索值并将“StrName”用于某种目的,名称显示在 dll 中,但是当它返回到 inno 脚本时,字符值是个位数。有了你的建议也没有用

标签: dll inno-setup return-value pascalscript


【解决方案1】:

GetName 应该返回一个const char *,但是它在其他方面没有问题。但是请注意,返回这样的字符串可能只适用于文字字符串常量,如上所示。您不能使用此模式返回计算的字符串值(如果您尝试这样做,它可能会崩溃或提供损坏的数据);因此getName 是错误的。

还要注意,虽然 C 区分大小写,但 Pascal 不区分,因此 getNameGetName 在 Inno 脚本中是相同的函数。在上述情况下,您可能不会这样做,因为参数不同,但我不会依赖这一点——您应该给它们不同的名称。 (也不要在 C 端使用相同的名称,因为有时查找 DLL 导出时也会不区分大小写。)

要返回一个计算出来的字符串,你应该使用这样的模式:

DLL 代码:

void __stdcall CalculateName(char *buffer, size_t size)
{
    strncpy(buffer, "whatever", size);
    buffer[size-1] = 0;
}

创新代码:

procedure CalculateName(Buffer: AnsiString; Max: Cardinal);
external 'CalculateName@files:my.dll stdcall';

...
Max := 16;
Buffer := StringOfChar(#0, Max);
CalculateName(Buffer, Max);
SetLength(Buffer, Pos(#0, Buffer) - 1);
...

存在一些可接受的变体,例如,您可以让 DLL 函数返回实际写入缓冲区的字符数,并在随后的 SetLength 中使用它,而不是调用 Pos 来查找空终止符。

但你必须:

  • 确保双方都使用相同的字符串类型,要么都是 ANSI,要么都是 Unicode。
    • ANSI Inno Setup 仅支持具有 String 类型的 ANSI 字符串。
    • Unicode Inno Setup 支持带有AnsiString 的ANSI 字符串或带有String 的Unicode 字符串。
  • 使用 Unicode 字符串时,请确保双方同意 Max 和/或返回值是以字符还是字节指定的(示例代码假定它是以字符为单位的)。
  • 在调用函数之前,使用 SetLength 或 StringOfChar 确保缓冲区的大小已调整为所需的最大可能结果长度。
  • 确保被调用函数不会尝试写入超过此最大长度(如果将其作为参数提供给函数会更容易)。
  • 确保如果您使用 Pos,被调用的函数必须确保该值以空值结尾(或者您需要比示例中显示的更加小心)。
  • 确保在调用后将字符串截断为实际长度,方法是使用返回值或查找空终止符。

这里的一个限制是一侧分配的内存必须由同一侧释放。您无法安全地释放分配在 DLL 边界“错误”一侧的内存,无论是哪个方向。

【讨论】:

  • 我将尝试您的方法并确认您.. 我还尝试将过程“void __stdcall getName(char* strName)”的参数更改为“void __stdcall getName(LPTSTR strName)”在调用“getName”之前工作正常并在 inno 中添加了 setlength
  • 如果你在 DLL 中使用了LPTSTR并且在项目中启用了 Unicode 编译,那么它将匹配 Unicode Inno 使用的 String 类型(而不是Ansi Inno 使用的 String 类型,除非您编译 DLL 没有 启用 Unicode)。正如我所说,您需要确保您的字符串类型在两边都匹配才能正常工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-19
  • 2017-02-12
  • 2021-01-21
  • 1970-01-01
  • 2013-01-22
相关资源
最近更新 更多