Inno Setup 获取宽字节类型的字符串

因为 Inno Setup 没有提供 PWideChar 类型(Dephi 中有?),而只提供了 PAnsiChar,如果需要接收第三方 dll 返回的宽字节类型(如: C++ 的 wchar_t * 或者 LPWSTR 类型),使用 PAnsiChar 只能接收到第一个字符,如果需要获取完整的字符串内容,就我们需要自己处理。

处理的思路也很简单:

第一步:获取到字符串首字符的地址;

用 Cardinal 类型来接收字符串的首地址,为了方便理解,直接把 Cardinal 定义为 PWideChar 类型,如

type
    PWideChar = Cardinal; { Inno doesn't have a pointer type, so we use a Cardinal instead }

第二步:获取字符串的长度;

通过调用 windows 系统 api 中的 lstrlenW() 方法来获取字符串的长度,返回类型也是 Cardinal:

{ This function allows us to get us the length of a string from a PWideChar }
function lstrlenW(lpString: PWideChar): Cardinal;
external 'lstrlenW@kernel32.dll stdcall';

第三步:生成一个长度为上述获取到的字符串长度的字符串变量;

通过 SetLength() 方法,设定字符串变量的长度;

第四步:把获取到的字符串的内容拷贝到这个新的字符串变量中;

通过调用 lstrcpyW() 方法:

{ This function copies a string - we declare it in such a way that we can pass a pointer
  to an Inno string as destination
  This works because Inno will actually pass a PWideChar that points to the start of the
  string contents in memory, and internally the string is still null-terminated
  We just have to make sure that the string already has the right size beforehand! }
function lstrcpyW_ToInnoString(lpStringDest: String; lpStringSrc: PWideChar): Integer;
external 'lstrcpyW@kernel32.dll stdcall';

实现例子:

[Code]
type
  PWideChar = Cardinal; { Inno doesn't have a pointer type, so we use a Cardinal instead }

{ This function allows us to get us the length of a string from a PWideChar }
function lstrlenW(lpString: PWideChar): Cardinal;
external 'lstrlenW@kernel32.dll stdcall';

{ This function copies a string - we declare it in such a way that we can pass a pointer
  to an Inno string as destination
  This works because Inno will actually pass a PWideChar that points to the start of the
  string contents in memory, and internally the string is still null-terminated
  We just have to make sure that the string already has the right size beforehand! }
function lstrcpyW_ToInnoString(lpStringDest: String; lpStringSrc: PWideChar): Integer;
external 'lstrcpyW@kernel32.dll stdcall';

function GetStringFromPWideChar(pointer : PWideChar): String;
var
    stringLength: Cardinal; { Length of the string we got }
    innoString: String; { This is where we'll copy the string into } 
begin
    { The pointer is actually just a renamed Cardinal at this point: }
    Log('String pointer = ' + IntToStr(pointer));

    { Now we have to manually allocate a new Inno string with the right length and
    copy the data into it }

    { Start by getting the string length }
    stringLength := lstrlenW(pointer);
    Log('String length = ' + IntToStr(stringLength));

    { Create a string with the right size }
    innoString := '';
    SetLength(innoString, stringLength);

    { This check is necessary because an empty Inno string would translate to a NULL pointer
        and not a pointer to an empty string, and lstrcpyW cannot handle that. }
    if StringLength > 0 then begin
        { Copy string contents from the external buffer to the Inno string }
        lstrcpyW_ToInnoString(innoString, pointer);
    end;

    { Now we have the value stored in a proper string variable! }
    Log('String value = ' + innoString);

    Result := innoString;
end;

这里通过 GetCommandLineW() 方法来测试

[code]
{ Example of a function that returns a PWideChar }
function GetCommandLineW(): PWideChar;
external 'GetCommandLineW@kernel32.dll stdcall';

function InitializeSetup(): Boolean;
var
  returnedPointer: PWideChar; { This is what we get from the external function }
	innoString : String;
begin
  returnedPointer := GetCommandLineW();
  innoString = GetStringFromPWideChar(returnedPointer);
  Log('innoString is: ' + innoString);
end;

参考:

How can I dereference a pointer in Inno Setup Pascal Script?

可能有关:

Delphi – How to get substring from PAnsiChar?

How to return a string from a DLL to Inno Setup?