【问题标题】:Save INI file in UTF-8 rather than ANSI in Inno Setup在 Inno Setup 中将 INI 文件保存为 UTF-8 而不是 ANSI
【发布时间】:2016-05-09 03:02:34
【问题描述】:

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

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

[INI]
Filename: "{app}\www\conf\config.ini"; Section: "Settings"; Key: "ca.plafondAnnuel"; String: "{code:GetUser|Plafond}"
Filename: "{app}\www\conf\config.ini"; Section: "Settings"; Key: "app.siren"; String: "{code:GetUser|Siren}"
Filename: "{app}\www\conf\config.ini"; Section: "Settings"; Key: "app.adresse"; String: "{code:GetUser|Adresse}"


[Code]
var
  UserPage: TInputQueryWizardPage;
  ExamplePage : TInputOptionWizardPage;
  ImmatriculationPage : TInputOptionWizardPage;
  FakeElemIndex: Integer;
  FakeElem: TCustomEdit;
  AdresseTextarea: TNewMemo;

procedure InitializeWizard;
begin
  UserPage := CreateInputQueryPage(wpWelcome,
    'Configuration de l''application', '',
    'Configurez ici votre application. Une fois installée, vous pourrez modifier ces valeurs.');

  UserPage.Add('Siren :', False);
  UserPage.Add('Plafond annuel (utilisé par les auto-entreprises, mettre 0 si vous ne souhaitez pas plafonner votre chiffre d''affaire.):', False);

  FakeElemIndex := UserPage.Add('Votre adresse complète (telle qu''elle s''affichera sur les devis et factures, avec nom complet):', False);
  FakeElem  := UserPage.Edits[FakeElemIndex];

  AdresseTextarea := TNewMemo.Create(WizardForm);
  AdresseTextarea.Parent := FakeElem.Parent;
  AdresseTextarea.SetBounds(FakeElem.Left, FakeElem.Top, FakeElem.Width, ScaleY(50));

  // Hide the original single-line edit
  FakeElem.Visible := False;
end; 

function GetUser(Param: String): String;
begin
  if Param = 'Adresse' then
    Result := AdresseTextarea.Text
  else if Param = 'Siren' then
    Result := UserPage.Values[0]
  else if Param = 'Plafond' then
    Result := UserPage.Values[1];
end;

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

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

非常感谢!

【问题讨论】:

  • 请注意,您不应在代码中使用 UTF-8。引用Unicode Inno Setup 文章:... 支持 Unicode,但不支持其输入源。这意味着它确实使用 Unicode 字符串类型,但脚本中的任何文字 Unicode 字符都将转换为 ANSI。这并不意味着您不能显示 Unicode 字符串:例如,您可以使用编码的 Unicode 字符来构建 Unicode 字符串(如S := #$0100 + #$0101 + 'Aa';),或者使用LoadStringsFromFile 从文件中加载字符串,或者使用@987654328 @常量。
  • 感谢您回复马丁。我必须使用 UTF8,因为我在 utf8 中制作了一个 Web 应用程序,而没有想到以后可以将它安装为桌面应用程序。因此,ini conf 文件也必须采用 utf8 格式,以便我的 Web 应用程序可以正确读取。所以,我必须能够用 UTF8 而不是 ANSI 写入这个 ini 文件。

标签: encoding utf-8 inno-setup ini codepages


【解决方案1】:

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

这个函数根本不支持 UTF-8。它只支持 ANSI 编码和 UTF-16。
How to read/write Chinese/Japanese characters from/to INI files?

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


无论如何,如果你需要UTF-8,你必须自己将条目格式化为INI格式并使用SaveStringsToUTF8File function来编写它。


最后一个选项是通过使用系统调用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;

【讨论】:

  • 非常感谢马丁,它有效!我第一次尝试时它不起作用,因为我的 conf 文件已经存在(即使 conf 键不存在),但如果我还没有 conf 文件,它可以工作!
猜你喜欢
  • 2011-01-16
  • 1970-01-01
  • 2011-05-02
  • 1970-01-01
  • 1970-01-01
  • 2020-10-24
  • 2015-12-07
  • 1970-01-01
  • 2020-05-07
相关资源
最近更新 更多