在 Inno Setup 中以 UTF-8 而不是 ANSI 保存 INI 文件

wyl*_*jon 4 ini encoding inno-setup utf-8 codepages

我开始使用 Inno Setup,但 INI 文件编码存在一些问题。
\n我想将用户输入保存在 INI 文件中,并且该输入可以包含重音符号。

\n\n

我使用 Inno Setup Unicode,我的 setupScript.iss 是 UTF-8 编码的,这是我的代码(一部分):

\n\n
[INI]\nFilename: "{app}\\www\\conf\\config.ini"; Section: "Settings"; Key: "ca.plafondAnnuel"; String: "{code:GetUser|Plafond}"\nFilename: "{app}\\www\\conf\\config.ini"; Section: "Settings"; Key: "app.siren"; String: "{code:GetUser|Siren}"\nFilename: "{app}\\www\\conf\\config.ini"; Section: "Settings"; Key: "app.adresse"; String: "{code:GetUser|Adresse}"\n\n\n[Code]\nvar\n  UserPage: TInputQueryWizardPage;\n  ExamplePage : TInputOptionWizardPage;\n  ImmatriculationPage : TInputOptionWizardPage;\n  FakeElemIndex: Integer;\n  FakeElem: TCustomEdit;\n  AdresseTextarea: TNewMemo;\n\nprocedure InitializeWizard;\nbegin\n  UserPage := CreateInputQueryPage(wpWelcome,\n    \'Configuration de l\'\'application\', \'\',\n    \'Configurez ici votre application. Une fois install\xc3\xa9e, vous pourrez modifier ces valeurs.\');\n\n  UserPage.Add(\'Siren :\', False);\n  UserPage.Add(\'Plafond annuel (utilis\xc3\xa9 par les auto-entreprises, mettre 0 si vous ne souhaitez pas plafonner votre chiffre d\'\'affaire.):\', False);\n\n  FakeElemIndex := UserPage.Add(\'Votre adresse compl\xc3\xa8te (telle qu\'\'elle s\'\'affichera sur les devis et factures, avec nom complet):\', False);\n  FakeElem  := UserPage.Edits[FakeElemIndex];\n\n  AdresseTextarea := TNewMemo.Create(WizardForm);\n  AdresseTextarea.Parent := FakeElem.Parent;\n  AdresseTextarea.SetBounds(FakeElem.Left, FakeElem.Top, FakeElem.Width, ScaleY(50));\n\n  // Hide the original single-line edit\n  FakeElem.Visible := False;\nend; \n\nfunction GetUser(Param: String): String;\nbegin\n  if Param = \'Adresse\' then\n    Result := AdresseTextarea.Text\n  else if Param = \'Siren\' then\n    Result := UserPage.Values[0]\n  else if Param = \'Plafond\' then\n    Result := UserPage.Values[1];\nend;\n
Run Code Online (Sandbox Code Playgroud)\n\n

getUser|Adresse该部分返回的值[INI]不是 UTF-8 编码的:我用 Notepad++ 打开 INI 文件,我看到该文件是 UTF-8 编码的。但该值adresse是ANSI编码的(如果我将文件的编码更改为ANSI,则该值是可读的)

\n\n

有人可以帮助我了解如何以 UTF-8 保存此用户输入?

\n\n

多谢 !

\n

Mar*_*ryl 5

Inno Setup 的 INI 函数([INI]节和SetIni*函数)在内部使用 Windows API 函数WritePrivateProfileString

该函数根本不支持UTF-8。它仅支持 ANSI 编码和 UTF-16。
请参阅如何从 INI 文件中读取/写入中文/日文字符?

因此,如果目标应用程序依赖 Windows API 函数来读取 UTF-8 编码的 INI 文件,那么它是否能够读取它甚至是值得怀疑的。


不管怎样,如果你需要UTF-8,你必须自己将条目格式化为INI格式并使用SaveStringsToUTF8File函数来编写它。


最后一个选项是通过使用系统调用WritePrivateProfileString来编写看似 ANSI 编码的字符串(实际上是 UTF-8 编码)来破解它。

为此,您需要在代码中将字符串转换为 UTF-8。你可以用WideCharToMultiByte它。

function WideCharToMultiByte(CodePage: UINT; dwFlags: DWORD;
  lpWideCharStr: string; cchWideChar: Integer; lpMultiByteStr: AnsiString;
  cchMultiByte: Integer; lpDefaultCharFake: Integer;
  lpUsedDefaultCharFake: Integer): Integer;
  external 'WideCharToMultiByte@kernel32.dll stdcall';

const
  CP_UTF8 = 65001;

function GetStringAsUtf8(S: string): AnsiString;
var
  Len: Integer;
begin
  Len := WideCharToMultiByte(CP_UTF8, 0, S, Length(S), Result, 0, 0, 0);
  SetLength(Result, Len);
  WideCharToMultiByte(CP_UTF8, 0, S, Length(S), Result, Len, 0, 0);
end;

function WritePrivateProfileString(
  lpAppName, lpKeyName, lpString, lpFileName: AnsiString): Integer;
  external 'WritePrivateProfileStringA@kernel32.dll stdcall';

procedure CurStepChanged(CurStep: TSetupStep);
var
  IniFileName: string;
begin
  if CurStep = ssInstall then
  begin
    Log('Writting INI file');
    if not ForceDirectories(ExpandConstant('{app}\www\conf')) then
    begin
      MsgBox('Error creating directory for INI file', mbError, MB_OK);
    end
      else
    begin
      IniFileName := ExpandConstant('{app}\www\conf\config.ini');
      if (WritePrivateProfileString(
            'Settings', 'ca.plafondAnnuel', GetStringAsUtf8(GetUser('Plafond')),
            IniFileName) = 0) or
         (WritePrivateProfileString(
            'Settings', 'app.siren', GetStringAsUtf8(GetUser('Siren')),
            IniFileName) = 0) or
         (WritePrivateProfileString(
            'Settings', 'app.adresse', GetStringAsUtf8(GetUser('Adresse')),
            IniFileName) = 0) then
      begin
        MsgBox('Error writting the INI file', mbError, MB_OK);
      end;
    end;
  end;
end;
Run Code Online (Sandbox Code Playgroud)