使用函数在 Inno Setup 中填充的已分配字符缓冲区调用 DLL 函数
Calling a DLL function with an allocated character buffer that the function fills in Inno Setup
我在 Windows 10 64 位上使用 (Unicode) Inno Setup 6.0.5。
我要使用的导出符号具有签名:
typedef int(__stdcall *GetDirVST2x86) (LPWSTR lpString1);
Inno Setup [代码] 部分的声明为:
function GetDirVST2x86(var lpString1: String): Integer;
external 'GetDirVST2x86@files:R2RINNO.DLL stdcall setuponly';
其中,lpString1
将在函数 returns 之后包含一个指向 wide-string 的指针,而 R2RINNO.DLL 是一个 32 位 DLL。
现在我的问题是,如果我编译并 运行 此设置,当我尝试检索该值时会发生读取访问冲突。 当我从 C 程序执行相同的函数时得到了正确的结果。从 Inno 脚本的原型声明中删除 var
会获取空(或可能)空或空白字符串,因此这也无济于事。
我没有想要使用的 DLL 的源代码,我从 IDA 中找到了签名。脚本引擎 Inno Setup 似乎无可救药地不足,因为它根本不支持指针。
我观察到的一件有趣的事情是,如果我将 lpString1
的类型更改为 Cardinal
或 Integer
并使用 IntToStr
获取字符串,我得到的值是创建安装程序的目录。
这是一个有效的 C 代码:
#include <windows.h>
#include <stdio.h>
#define _UNICODE
#define UNICODE
typedef int(WINAPI *GetDirVST2x86) (LPWSTR );
int main() {
HMODULE hModule = LoadLibrary("R2RINNO.DLL");
if (NULL != hModule) {
GetDirVST2x86 pGetDirVST2x86 = (GetDirVST2x86) GetProcAddress (hModule, "GetDirVST2x86");
if (NULL != pGetDirVST2x86) {
LPWSTR lpszVST2x86;
pGetDirVST2x86(lpszVST2x86);
wprintf(lpszVST2x86);
}
FreeLibrary(hModule);
}
}
这是输出:
C:\Program Files (x86)\Steinberg\VstPlugins
这是我要使用的函数的 IDA 截图:
与 C 声明等效的 Pascal 脚本应为:
function GetDirVST2x86(lpString1: string): Integer;
external 'GetDirVST2x86@files:R2RINNO.DLL stdcall setuponly';
(即没有 var
,因为它是一个 input 字符指针参数)。
假设函数契约是你(作为调用者)分配一个缓冲区并提供给要填充的函数,你应该这样调用函数:
var
Buf: string;
begin
{ Allocate buffer for the result large enough according to the API specification }
SetLength(Buf, 1000);
GetDirVST2x86(Buf);
SetLength(Result, Pos(#0, Result) - 1);
end;
另见 How to return a string from a DLL to Inno Setup?
我在 Windows 10 64 位上使用 (Unicode) Inno Setup 6.0.5。
我要使用的导出符号具有签名:
typedef int(__stdcall *GetDirVST2x86) (LPWSTR lpString1);
Inno Setup [代码] 部分的声明为:
function GetDirVST2x86(var lpString1: String): Integer;
external 'GetDirVST2x86@files:R2RINNO.DLL stdcall setuponly';
其中,lpString1
将在函数 returns 之后包含一个指向 wide-string 的指针,而 R2RINNO.DLL 是一个 32 位 DLL。
现在我的问题是,如果我编译并 运行 此设置,当我尝试检索该值时会发生读取访问冲突。 当我从 C 程序执行相同的函数时得到了正确的结果。从 Inno 脚本的原型声明中删除 var
会获取空(或可能)空或空白字符串,因此这也无济于事。
我没有想要使用的 DLL 的源代码,我从 IDA 中找到了签名。脚本引擎 Inno Setup 似乎无可救药地不足,因为它根本不支持指针。
我观察到的一件有趣的事情是,如果我将 lpString1
的类型更改为 Cardinal
或 Integer
并使用 IntToStr
获取字符串,我得到的值是创建安装程序的目录。
这是一个有效的 C 代码:
#include <windows.h>
#include <stdio.h>
#define _UNICODE
#define UNICODE
typedef int(WINAPI *GetDirVST2x86) (LPWSTR );
int main() {
HMODULE hModule = LoadLibrary("R2RINNO.DLL");
if (NULL != hModule) {
GetDirVST2x86 pGetDirVST2x86 = (GetDirVST2x86) GetProcAddress (hModule, "GetDirVST2x86");
if (NULL != pGetDirVST2x86) {
LPWSTR lpszVST2x86;
pGetDirVST2x86(lpszVST2x86);
wprintf(lpszVST2x86);
}
FreeLibrary(hModule);
}
}
这是输出:
C:\Program Files (x86)\Steinberg\VstPlugins
这是我要使用的函数的 IDA 截图:
与 C 声明等效的 Pascal 脚本应为:
function GetDirVST2x86(lpString1: string): Integer;
external 'GetDirVST2x86@files:R2RINNO.DLL stdcall setuponly';
(即没有 var
,因为它是一个 input 字符指针参数)。
假设函数契约是你(作为调用者)分配一个缓冲区并提供给要填充的函数,你应该这样调用函数:
var
Buf: string;
begin
{ Allocate buffer for the result large enough according to the API specification }
SetLength(Buf, 1000);
GetDirVST2x86(Buf);
SetLength(Result, Pos(#0, Result) - 1);
end;
另见 How to return a string from a DLL to Inno Setup?