在 Inno Setup 中找到具有特定名称模式和内容的 JSON 文件
Find JSON file with specific name pattern and contents in Inno Setup
我有一个工作脚本,安装程序在其中找到特定路径中的特定文件,但我需要稍微更改它。我注意到当我重新安装应用程序时,我想从中获取信息的文件的名称每次都不同,所以它并没有我想的那么重要。
虽然有些东西没有改变 - 变量文件名的路径,我已经使用常量定义并且可以再次使用,还有文件扩展名。因此,如果路径没有改变,那么搜索过程可能会快得多。文件格式为 JSON,脚本中已应用其代码。
这是 JSON 结构示例:
"ChunkDbs": [],
"CompatibleApps": [],
"DisplayName": "Application Name",
"InstallLocation": "D:\Program Files (x86)\ApplicationName",
"InstallTags": [],
"InstallComponents": [],
唯一的解决办法是搜索特定路径中具有特定扩展名的所有文件。我需要在这里使用一些变量,第一个已经在代码中提到 InstallLocation
这是正确的安装路径,我需要定义的下一个变量是 DisplayName
,它包含应用程序名称,可能还有另一个定义文件扩展名的名称。
所以我需要找到正确的文件,包含DisplayName
参数中的特定字符串,比较是否与定义的相同,然后从InstallLocation
参数中读取安装路径。
这是我目前的代码:
[Setup]
DefaultDirName={code:GetInstallLocation}
[Code]
#include "JsonParser.pas"
function ParseJsonAndLogErrors(
var JsonParser: TJsonParser; const Source: WideString): Boolean;
var
I: Integer;
begin
ParseJson(JsonParser, Source);
Result := (Length(JsonParser.Output.Errors) = 0);
if not Result then
begin
Log('Error parsing JSON');
for I := 0 to Length(JsonParser.Output.Errors) - 1 do
begin
Log(JsonParser.Output.Errors[I]);
end;
end;
end;
function GetJsonRoot(Output: TJsonParserOutput): TJsonObject;
begin
Result := Output.Objects[0];
end;
function FindJsonValue(
Output: TJsonParserOutput; Parent: TJsonObject; Key: TJsonString;
var Value: TJsonValue): Boolean;
var
I: Integer;
begin
for I := 0 to Length(Parent) - 1 do
begin
if Parent[I].Key = Key then
begin
Value := Parent[I].Value;
Result := True;
Exit;
end;
end;
Result := False;
end;
function FindJsonString(
Output: TJsonParserOutput; Parent: TJsonObject; Key: TJsonString;
var Str: TJsonString): Boolean;
var
JsonValue: TJsonValue;
begin
Result :=
FindJsonValue(Output, Parent, Key, JsonValue) and
(JsonValue.Kind = JVKString);
if Result then
begin
Str := Output.Strings[JsonValue.Index];
end;
end;
function MultiByteToWideChar(
CodePage: UINT; dwFlags: DWORD; const lpMultiByteStr: AnsiString;
cchMultiByte: Integer; lpWideCharStr: string; cchWideChar: Integer): Integer;
external 'MultiByteToWideChar@kernel32.dll stdcall';
function LoadStringFromFileInCP(
FileName: string; var S: string; CP: Integer): Boolean;
var
Ansi: AnsiString;
Len: Integer;
begin
Result := LoadStringFromFile(FileName, Ansi);
if Result then
begin
Len := MultiByteToWideChar(CP, 0, Ansi, Length(Ansi), S, 0);
SetLength(S, Len);
MultiByteToWideChar(CP, 0, Ansi, Length(Ansi), S, Len);
end;
end;
const
CP_UTF8 = 65001;
var
InstallLocation: string;
<event('InitializeSetup')>
function InitializeSetupParseConfig(): Boolean;
var
Json: string;
ConfigPath: string;
JsonParser: TJsonParser;
JsonRoot: TJsonObject;
S: TJsonString;
begin
Result := True;
ConfigPath := ExpandConstant('{commonappdata}\Data\FEE8D728379C5E.dat');
Log(Format('Reading "%s"', [ConfigPath]));
if not LoadStringFromFileInCP(ConfigPath, Json, CP_UTF8) then
begin
MsgBox(Format('Error reading "%s"', [ConfigPath]), mbError, MB_OK);
Result := True;
end
else
if not ParseJsonAndLogErrors(JsonParser, Json) then
begin
MsgBox(Format('Error parsing "%s"', [ConfigPath]), mbError, MB_OK);
Result := True;
end
else
begin
JsonRoot := GetJsonRoot(JsonParser.Output);
if not FindJsonString(JsonParser.Output, JsonRoot, 'InstallLocation', S) then
begin
MsgBox(Format('Cannot find InstallLocation in "%s"', [ConfigPath]),
mbError, MB_OK);
Result := False;
end
else
begin
InstallLocation := S;
Log(Format('Found InstallLocation = "%s"', [InstallLocation]));
end;
ClearJsonParser(JsonParser);
end;
end;
function GetInstallLocation(Param: string): string;
begin
Result := InstallLocation;
end;
感谢您的帮助
我已经编写了我的代码原型来展示我如何看待代码来实现我想要的(最直观/最清晰的方式):
const
MyDisplayName = 'MyReqAppName';
MyPath = 'C:\some\path\*.dat';
var
RealDisplayName: string;
InstallLocation: string;
function FindParameters();
begin
RealDisplayName := 'DisplayName';
InstallLocation := 'InstallLocation';
Find(RealDisplayName in MyPath);
if (RealDisplayName = MyDisplayName) then
Find(InstallLocation);
else
repeat
Find(RealDisplayName in MyPath);
until(RealDisplayName = MyDisplayName);
end;
要查找具有特定扩展名的文件,请使用 FindFirst
and FindNext
函数。
对于您找到的每个匹配文件,使用您已有的代码检查其内容。
您需要进一步调整代码,因为我不清楚在出现各种错误时您要做什么。
var
Path: string;
FindRec: TFindRec;
Json: string;
ConfigPath: string;
JsonParser: TJsonParser;
JsonRoot: TJsonObject;
S: TJsonString;
DisplayName: string;
begin
Path := 'C:\some\path';
if FindFirst(Path + '\*.dat', FindRec) then
begin
repeat
Log('Found: ' + FindRec.Name);
ConfigPath := Path + '\' + FindRec.Name;
Log(Format('Reading "%s"', [ConfigPath]));
if not LoadStringFromFileInCP(ConfigPath, Json, CP_UTF8) then
begin
Log(Format('Error reading "%s"', [ConfigPath]));
end
else
if not ParseJsonAndLogErrors(JsonParser, Json) then
begin
Log(Format('Error parsing "%s"', [ConfigPath]));
end
else
begin
JsonRoot := GetJsonRoot(JsonParser.Output);
if not FindJsonString(JsonParser.Output, JsonRoot, 'DisplayName', S) then
begin
Log(Format('Cannot find DisplayName in "%s"', [ConfigPath]));
end
else
if DisplayName <> MyDisplayName then
begin
Log(Format('DisplayName is "%s", not what we want', [DisplayName]));
end
else
begin
Log(Format('DisplayName is "%s", what we want', [DisplayName]));
if not FindJsonString(
JsonParser.Output, JsonRoot, 'InstallLocation', S) then
begin
Log(Format('Cannot find InstallLocation in "%s"', [ConfigPath]));
end
else
begin
InstallLocation := S;
Log(Format('Found InstallLocation = "%s"', [InstallLocation]));
end;
end;
ClearJsonParser(JsonParser);
end;
until not FindNext(FindRec);
FindClose(FindRec);
end;
end;
我有一个工作脚本,安装程序在其中找到特定路径中的特定文件,但我需要稍微更改它。我注意到当我重新安装应用程序时,我想从中获取信息的文件的名称每次都不同,所以它并没有我想的那么重要。
虽然有些东西没有改变 - 变量文件名的路径,我已经使用常量定义并且可以再次使用,还有文件扩展名。因此,如果路径没有改变,那么搜索过程可能会快得多。文件格式为 JSON,脚本中已应用其代码。
这是 JSON 结构示例:
"ChunkDbs": [],
"CompatibleApps": [],
"DisplayName": "Application Name",
"InstallLocation": "D:\Program Files (x86)\ApplicationName",
"InstallTags": [],
"InstallComponents": [],
唯一的解决办法是搜索特定路径中具有特定扩展名的所有文件。我需要在这里使用一些变量,第一个已经在代码中提到 InstallLocation
这是正确的安装路径,我需要定义的下一个变量是 DisplayName
,它包含应用程序名称,可能还有另一个定义文件扩展名的名称。
所以我需要找到正确的文件,包含DisplayName
参数中的特定字符串,比较是否与定义的相同,然后从InstallLocation
参数中读取安装路径。
这是我目前的代码:
[Setup]
DefaultDirName={code:GetInstallLocation}
[Code]
#include "JsonParser.pas"
function ParseJsonAndLogErrors(
var JsonParser: TJsonParser; const Source: WideString): Boolean;
var
I: Integer;
begin
ParseJson(JsonParser, Source);
Result := (Length(JsonParser.Output.Errors) = 0);
if not Result then
begin
Log('Error parsing JSON');
for I := 0 to Length(JsonParser.Output.Errors) - 1 do
begin
Log(JsonParser.Output.Errors[I]);
end;
end;
end;
function GetJsonRoot(Output: TJsonParserOutput): TJsonObject;
begin
Result := Output.Objects[0];
end;
function FindJsonValue(
Output: TJsonParserOutput; Parent: TJsonObject; Key: TJsonString;
var Value: TJsonValue): Boolean;
var
I: Integer;
begin
for I := 0 to Length(Parent) - 1 do
begin
if Parent[I].Key = Key then
begin
Value := Parent[I].Value;
Result := True;
Exit;
end;
end;
Result := False;
end;
function FindJsonString(
Output: TJsonParserOutput; Parent: TJsonObject; Key: TJsonString;
var Str: TJsonString): Boolean;
var
JsonValue: TJsonValue;
begin
Result :=
FindJsonValue(Output, Parent, Key, JsonValue) and
(JsonValue.Kind = JVKString);
if Result then
begin
Str := Output.Strings[JsonValue.Index];
end;
end;
function MultiByteToWideChar(
CodePage: UINT; dwFlags: DWORD; const lpMultiByteStr: AnsiString;
cchMultiByte: Integer; lpWideCharStr: string; cchWideChar: Integer): Integer;
external 'MultiByteToWideChar@kernel32.dll stdcall';
function LoadStringFromFileInCP(
FileName: string; var S: string; CP: Integer): Boolean;
var
Ansi: AnsiString;
Len: Integer;
begin
Result := LoadStringFromFile(FileName, Ansi);
if Result then
begin
Len := MultiByteToWideChar(CP, 0, Ansi, Length(Ansi), S, 0);
SetLength(S, Len);
MultiByteToWideChar(CP, 0, Ansi, Length(Ansi), S, Len);
end;
end;
const
CP_UTF8 = 65001;
var
InstallLocation: string;
<event('InitializeSetup')>
function InitializeSetupParseConfig(): Boolean;
var
Json: string;
ConfigPath: string;
JsonParser: TJsonParser;
JsonRoot: TJsonObject;
S: TJsonString;
begin
Result := True;
ConfigPath := ExpandConstant('{commonappdata}\Data\FEE8D728379C5E.dat');
Log(Format('Reading "%s"', [ConfigPath]));
if not LoadStringFromFileInCP(ConfigPath, Json, CP_UTF8) then
begin
MsgBox(Format('Error reading "%s"', [ConfigPath]), mbError, MB_OK);
Result := True;
end
else
if not ParseJsonAndLogErrors(JsonParser, Json) then
begin
MsgBox(Format('Error parsing "%s"', [ConfigPath]), mbError, MB_OK);
Result := True;
end
else
begin
JsonRoot := GetJsonRoot(JsonParser.Output);
if not FindJsonString(JsonParser.Output, JsonRoot, 'InstallLocation', S) then
begin
MsgBox(Format('Cannot find InstallLocation in "%s"', [ConfigPath]),
mbError, MB_OK);
Result := False;
end
else
begin
InstallLocation := S;
Log(Format('Found InstallLocation = "%s"', [InstallLocation]));
end;
ClearJsonParser(JsonParser);
end;
end;
function GetInstallLocation(Param: string): string;
begin
Result := InstallLocation;
end;
感谢您的帮助
我已经编写了我的代码原型来展示我如何看待代码来实现我想要的(最直观/最清晰的方式):
const
MyDisplayName = 'MyReqAppName';
MyPath = 'C:\some\path\*.dat';
var
RealDisplayName: string;
InstallLocation: string;
function FindParameters();
begin
RealDisplayName := 'DisplayName';
InstallLocation := 'InstallLocation';
Find(RealDisplayName in MyPath);
if (RealDisplayName = MyDisplayName) then
Find(InstallLocation);
else
repeat
Find(RealDisplayName in MyPath);
until(RealDisplayName = MyDisplayName);
end;
要查找具有特定扩展名的文件,请使用 FindFirst
and FindNext
函数。
对于您找到的每个匹配文件,使用您已有的代码检查其内容。
您需要进一步调整代码,因为我不清楚在出现各种错误时您要做什么。
var
Path: string;
FindRec: TFindRec;
Json: string;
ConfigPath: string;
JsonParser: TJsonParser;
JsonRoot: TJsonObject;
S: TJsonString;
DisplayName: string;
begin
Path := 'C:\some\path';
if FindFirst(Path + '\*.dat', FindRec) then
begin
repeat
Log('Found: ' + FindRec.Name);
ConfigPath := Path + '\' + FindRec.Name;
Log(Format('Reading "%s"', [ConfigPath]));
if not LoadStringFromFileInCP(ConfigPath, Json, CP_UTF8) then
begin
Log(Format('Error reading "%s"', [ConfigPath]));
end
else
if not ParseJsonAndLogErrors(JsonParser, Json) then
begin
Log(Format('Error parsing "%s"', [ConfigPath]));
end
else
begin
JsonRoot := GetJsonRoot(JsonParser.Output);
if not FindJsonString(JsonParser.Output, JsonRoot, 'DisplayName', S) then
begin
Log(Format('Cannot find DisplayName in "%s"', [ConfigPath]));
end
else
if DisplayName <> MyDisplayName then
begin
Log(Format('DisplayName is "%s", not what we want', [DisplayName]));
end
else
begin
Log(Format('DisplayName is "%s", what we want', [DisplayName]));
if not FindJsonString(
JsonParser.Output, JsonRoot, 'InstallLocation', S) then
begin
Log(Format('Cannot find InstallLocation in "%s"', [ConfigPath]));
end
else
begin
InstallLocation := S;
Log(Format('Found InstallLocation = "%s"', [InstallLocation]));
end;
end;
ClearJsonParser(JsonParser);
end;
until not FindNext(FindRec);
FindClose(FindRec);
end;
end;