将字符串数组从 C# 返回到 Inno Setup

Returning a string array from C# to Inno Setup

我正在使用 Robert Giesecke 的 Unmanaged Exports NuGet 并在 C# 中使用以下方法:

[DllExport("DummyMethod", CallingConvention = CallingConvention.StdCall)]
public static void DummyMethod(
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out string[] test, out int count)
{
    count = 3;
    test = new[] {"test1", "test2", "test3"};
}

在 Inno Setup 中,这是我的代码:

[Code]
procedure DummyMethod(out Test: TArrayOfString; out Count: Integer);
external 'DummyMethod@files:MyDll.dll stdcall';

procedure InitializeWizard();
  var Test : TArrayOfString;
  var Count : Integer;
begin
  DummyMethod(Test, Count);
  MsgBox(Test[0], mbError, MB_OK);
end;

出于某种原因,Count 始终为 0 而 Test 始终为空。

我查看了几个示例,但找不到 Inno Setup 从 C# DLL 获取字符串数组的示例。

带有 stringUnmanagedType.LPArray 映射到指向 char 的指针数组(C 风格 char**)。在 Unicode Pascal 脚本中是 array of PAnsiChar。 Pascal 脚本无法神奇地将其转换为 TArrayOfString (array of string).

你可以这样转换:

type
  TArrayOfPAnsiChar = array of PAnsiChar;

procedure DummyMethod(out StringPtrs: TArrayOfPAnsiChar; out Count: Integer);
  external 'DummyMethod@files:ArrayInno.dll stdcall';

function DummyMethodWrapper: TArrayOfString;
var
  ArrayOfPAnsiChar: TArrayOfPAnsiChar;
  I, Count: Integer;
begin
  DummyMethod(ArrayOfPAnsiChar, Count);

  SetArrayLength(Result, Count);
  for I := 0 to Count - 1 do
  begin
    Result[I] := ArrayOfPAnsiChar[I];
  end;
end;

(使用 Unicode Inno Setup 测试)


旁注:

  • 不清楚,谁为 TArrayOfAnsiChar 和单个字符数组分配内存。我充其量闻到内存泄漏的味道。
  • 您可能想要使用 16 位字符缓冲区,而不是 8 位字符缓冲区以允许完整的 Unicode。但请注意,这在 Pascal 脚本中更难实现,因为它缺少 16 位字符指针类型。

可以编组 BSTR/WideString 的数组,这应该允许完整的 Unicode。

在 C# 中:

[DllExport("ReturnsArrayOfStrings", CallingConvention.StdCall)]
public static void ReturnsArrayOfStrings(
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.BStr, SizeParamIndex = 1)] out string[] values,
    out int numValues)
{
    values = new[] { "one", "two", "three" };
    numValues = values.Length;
}

在 Inno 设置中:

type
  TArrayOfWideString = array of WideString;

procedure ReturnsArrayOfStrings(out values: TArrayOfWideString; out numValues: Integer);
external 'ReturnsArrayOfStrings@files:Thing.dll stdcall';

procedure DoAThing;
var
  values: TArrayOfWideString;
  numValues, i: Integer;
begin
  ReturnsArrayOfStrings(values, numValues);
  for i := 0 to numValues - 1 do
  begin
    Log(values[i]);
  end;  
end;