Reputation: 23
I have a working script, where the installer finds the specific file inside specific path but I need to slightly change it. I noticed that when I reinstall the application, the name of the file which I want to get the info from is different every time, so it's not that important as I thought.
There are some things which are not changing although - the path to that variable filename, which I have defined already using the constant and can be used again and also the file extension. So if the path doesn't change, the search process could be a lot more quicker just for that. The file format is JSON and code for it is already applied in the script.
Here is the JSON structure sample:
"ChunkDbs": [],
"CompatibleApps": [],
"DisplayName": "Application Name",
"InstallLocation": "D:\\Program Files (x86)\\ApplicationName",
"InstallTags": [],
"InstallComponents": [],
The only solution for this is searching all the files in specific path with specific extension. There are some variables I need to use here, the first is already mentioned in the code as InstallLocation
which is the proper install path, the next variable which I need to define is DisplayName
, which contains the application name and probably another one that define the file extension.
So I need to find the right file, containing the specific string inside DisplayName
parameter, compare if it's the same as in the defined one and then read the installation path from InstallLocation
parameter.
Here is the code I have so far:
[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 '[email protected] 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;
Thank you for help
I've written my code prototype to show how I see the code to make what I want (the most intuitive / clearest way):
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;
Upvotes: 1
Views: 571
Reputation: 202118
To find a files with a specific extension, use FindFirst
and FindNext
functions.
For each matching file you find, inspect its contents using the code you already have.
You will need to adapt the code further, as it's not clear to me what you want to do in case of various kinds of errors.
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;
Upvotes: 1