Inno Setup 中的 C# DLL 访问冲突

C# DLL in Inno Setup Access Violation

我正在尝试在我的 InnoSetup 项目中引用 C# DLL。我需要的是一个带有一个字符串参数和一个字符串 return 值的简单函数。但即使按照示例并尝试不同类型的封送处理,我总是以访问冲突告终。

这是我的 C# class:

public class NKToolbox
{
    [DllExport("EncryptPassword", CallingConvention.StdCall)]
    static string EncryptPassword([MarshalAs(UnmanagedType.LPStr)] string password)
    {
        File.WriteAllText(@"C:\temp\test.txt", password);
        return password.Length.ToString();
    }       
}

我放置了 File.WriteAllText 以查看是否甚至调用了该方法。但不是。我使用 Robert Giesecke 的 UnmanagedExports 包。

以及 Inno 设置代码

function EncryptPassword(pw: WideString): WideString;
external 'EncryptPassword@files:nktoolbox.dll stdcall';

function InitializeSetup: Boolean;
var
  str: WideString;
begin
  str := EncryptPassword('sdvadfva');
  log(str);
  result := False;
end;

在线 str := EncryptPassword('sdvadfva') 我得到一个 'Access violation at address ...... Write of address .....' 我正在使用 Inno Setup 5.5.9 Unicode。

我已经尝试使用在其他线程中找到的不同封送处理语句,我已经使用 out 关键字、普通 string 类型和 WideString 进行了尝试绝望。

[DllExport("EncryptPassword", CallingConvention.StdCall)]
static string EncryptPassword([MarshalAs(UnmanagedType.LPStr)] string password)

在 Delphi 代码中,这映射到:

function EncryptPassword(password: PAnsiChar): PAnsiChar; stdcall;

另请注意,C# 代码 return 是通过调用 CoTaskMemAlloc 分配的字符串。您的代码应该通过调用 CoTaskMemFree.

来释放该缓冲区

导入此函数的代码试图将文本视为 COM BSTR 字符串。事实并非如此。

使用 COM BSTR,又名 WideString 是个好主意。但请注意,对于 return 值,C# 和 Inno 假设的 ABI 之间可能存在不匹配。最好使用 out 参数。参见 Why can a WideString not be used as a function return value for interop?

换句话说,我会这样声明 C#:

[DllExport("EncryptPassword", CallingConvention.StdCall)]
static void EncryptPassword(
    [MarshalAs(UnmanagedType.BStr)] 
    string input
    [MarshalAs(UnmanagedType.BStr)] 
    out string output
)
{
    output = ...;
}       

Inno 会是这样的:

procedure EncryptPassword(input: WideString; out output: WideString);
  external 'EncryptPassword@files:nktoolbox.dll stdcall';

我对 Inno 一无所知,所以我的部分回答有点依赖猜测。