使用 Inno Setup 中的缓冲区调用 DLL 函数 (GetPrivateProfileSection)

Calling a DLL function (GetPrivateProfileSection) using a buffer from Inno Setup

我想使用 Inno Setup 脚本中的 GetPrivateProfileSection(来自 Windows Kernel32.dll),这是一种 Delphi (Pascal) 程序。

但我不知道如何创建缓冲区,它是函数中的一个 Out 参数,以及它将我想要检索的有用信息放在哪里。

输入缓冲区是一个指向字符串的指针,您可以在函数导入原型中将其简单地声明为 string,只要您导入函数的适当变体,ANSI 或 Unicode 相对于它您使用的 Inno Setup 变体。

关于返回的缓冲区,它是由空字符分隔的键值对组成的字符串,您需要在代码中对其进行处理。以下函数可以将 INI 部分读取到字符串列表中,例如:

[Code]
#ifdef UNICODE
  #define AW "W"
#else
  #define AW "A"
#endif

function GetPrivateProfileSection(lpAppName: string;
  lpReturnedString: string; nSize: DWORD; lpFileName: string): DWORD;
  external 'GetPrivateProfileSection{#AW}@kernel32.dll stdcall';

function GetIniSection(const FileName, Section: string; Strings: TStrings): Integer;
var
  BufLen: DWORD;
  Buffer: string;
begin
  { initialize the result }
  Result := 0;
  { first attempt with 1024 chars; use here at least 3 chars so the function can }
  { return 1 as a signal of insufficient buffer failure }
  SetLength(Buffer, 1024);
  { first attempt to call the function }
  BufLen := GetPrivateProfileSection(Section, Buffer, Length(Buffer), FileName);
  { check the first call function result }
  case BufLen of
    { the function failed for some reason, that the WinAPI does not provide }
    0: Exit;
    { the function returned value of the passed buffer length - 2 to indicate that }
    { it has insufficient buffer }
    Length(Buffer) - 2: 
    begin
      { second attempt with the maximum possible buffer length }
      SetLength(Buffer, 32767);
      { this time it should succeed }
      BufLen := GetPrivateProfileSection(Section, Buffer, Length(Buffer), FileName);
      { if the returned value is 0, or equals to the passed buffer length - 2, then }
      { even this call failed, so let's give it up }
      if (BufLen = 0) or (BufLen = Length(Buffer) - 2) then
        Exit;
    end;
  end;
  { the function call succeeded, so let's trim the result (note, that it will trim }
  { also the two terminating null characters from the end of the string buffer) }
  Buffer := Trim(Buffer);
  { now replace all the null characters with line breaks so we can easily fill the }
  { output string list }
  StringChangeEx(Buffer, #0, #13#10, True);
  { fill the output string list }
  Strings.Text := Buffer;
  { and return the number of items in the output string list }
  Result := Strings.Count;
end;

可能的用法:

var
  Strings: TStringList;
begin
  Strings := TStringList.Create;
  try
    { if the function returns value greater than 0, it found a non-empty }
    { section called SectionName in the C:\MyFile.ini file }
    if GetIniSection('C:\MyFile.ini', 'SectionName', Strings) > 0 then
      { process the Strings somehow }
  finally
    Strings.Free;
  end;
end;