我在DLL中有两个C函数,它们在定义文件中定义并导出以便在Inno Setup中使用。
char* __stdcall GetName()
{
return "Kishore";
}
void __stdcall getName(char* strName)
{
strcpy(strName, "Kishore");
}
Inno安装代码将加载自定义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脚本中检索名称而不会崩溃?
答案 0 :(得分:3)
GetName
应该返回一个const char *
,但是如果写的那样则不然。但请注意,返回像这样的字符串只能用于文字字符串常量,如上所示。您不能使用此模式返回计算的字符串值(如果您尝试这样,它可能会崩溃或提供损坏的数据);因此getName
是错误的。
另请注意,虽然C区分大小写,但Pascal不区分,因此getName
和GetName
与Inno脚本中的功能相同。在上述情况下你可能正在逃避这个因为参数不同,但我不会依赖它 - 你应该给它们不同的名字。 (也不要在C端使用相同的名称,因为DLL导出有时也会不区分大小写。)
要返回计算字符串,您应该使用如下模式:
DLL代码:
void __stdcall CalculateName(char *buffer, size_t size)
{
strncpy(buffer, "whatever", size);
buffer[size-1] = 0;
}
Inno代码:
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来查找空终止符。
但你必须:
String
类型的ANSI字符串。AnsiString
的ANSI字符串或带有String
的Unicode字符串。这里的一个限制是一方分配的内存必须由同一方释放。您无法安全地释放分配在"错误" DLL边界的一侧,在任一方向。