315 lines
11 KiB
Plaintext
315 lines
11 KiB
Plaintext
; Modified from https://github.com/DomGries/InnoDependencyInstaller
|
|
|
|
|
|
|
|
[Code]
|
|
// types and variables
|
|
type
|
|
TDependency_Entry = record
|
|
Filename: String;
|
|
Parameters: String;
|
|
Title: String;
|
|
URL: String;
|
|
Checksum: String;
|
|
ForceSuccess: Boolean;
|
|
RestartAfter: Boolean;
|
|
end;
|
|
|
|
var
|
|
Dependency_Memo: String;
|
|
Dependency_List: array of TDependency_Entry;
|
|
Dependency_NeedRestart, Dependency_ForceX86: Boolean;
|
|
Dependency_DownloadPage: TDownloadWizardPage;
|
|
|
|
procedure Dependency_Add(const Filename, Parameters, Title, URL, Checksum: String; const ForceSuccess, RestartAfter: Boolean);
|
|
var
|
|
Dependency: TDependency_Entry;
|
|
DependencyCount: Integer;
|
|
begin
|
|
Dependency_Memo := Dependency_Memo + #13#10 + '%1' + Title;
|
|
|
|
Dependency.Filename := Filename;
|
|
Dependency.Parameters := Parameters;
|
|
Dependency.Title := Title;
|
|
|
|
if FileExists(ExpandConstant('{tmp}{\}') + Filename) then begin
|
|
Dependency.URL := '';
|
|
end else begin
|
|
Dependency.URL := URL;
|
|
end;
|
|
|
|
Dependency.Checksum := Checksum;
|
|
Dependency.ForceSuccess := ForceSuccess;
|
|
Dependency.RestartAfter := RestartAfter;
|
|
|
|
DependencyCount := GetArrayLength(Dependency_List);
|
|
SetArrayLength(Dependency_List, DependencyCount + 1);
|
|
Dependency_List[DependencyCount] := Dependency;
|
|
end;
|
|
|
|
<event('InitializeWizard')>
|
|
procedure Dependency_Internal1;
|
|
begin
|
|
Dependency_DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), nil);
|
|
end;
|
|
|
|
<event('PrepareToInstall')>
|
|
function Dependency_Internal2(var NeedsRestart: Boolean): String;
|
|
var
|
|
DependencyCount, DependencyIndex, ResultCode: Integer;
|
|
Retry: Boolean;
|
|
TempValue: String;
|
|
begin
|
|
DependencyCount := GetArrayLength(Dependency_List);
|
|
|
|
if DependencyCount > 0 then begin
|
|
Dependency_DownloadPage.Show;
|
|
|
|
for DependencyIndex := 0 to DependencyCount - 1 do begin
|
|
if Dependency_List[DependencyIndex].URL <> '' then begin
|
|
Dependency_DownloadPage.Clear;
|
|
Dependency_DownloadPage.Add(Dependency_List[DependencyIndex].URL, Dependency_List[DependencyIndex].Filename, Dependency_List[DependencyIndex].Checksum);
|
|
|
|
Retry := True;
|
|
while Retry do begin
|
|
Retry := False;
|
|
|
|
try
|
|
Dependency_DownloadPage.Download;
|
|
except
|
|
if Dependency_DownloadPage.AbortedByUser then begin
|
|
Result := Dependency_List[DependencyIndex].Title;
|
|
DependencyIndex := DependencyCount;
|
|
end else begin
|
|
case SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of
|
|
IDABORT: begin
|
|
Result := Dependency_List[DependencyIndex].Title;
|
|
DependencyIndex := DependencyCount;
|
|
end;
|
|
IDRETRY: begin
|
|
Retry := True;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if Result = '' then begin
|
|
for DependencyIndex := 0 to DependencyCount - 1 do begin
|
|
Dependency_DownloadPage.SetText(Dependency_List[DependencyIndex].Title, '');
|
|
Dependency_DownloadPage.SetProgress(DependencyIndex + 1, DependencyCount + 1);
|
|
|
|
while True do begin
|
|
ResultCode := 0;
|
|
if ShellExec('', ExpandConstant('{tmp}{\}') + Dependency_List[DependencyIndex].Filename, Dependency_List[DependencyIndex].Parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode) then begin
|
|
if Dependency_List[DependencyIndex].RestartAfter then begin
|
|
if DependencyIndex = DependencyCount - 1 then begin
|
|
Dependency_NeedRestart := True;
|
|
end else begin
|
|
NeedsRestart := True;
|
|
Result := Dependency_List[DependencyIndex].Title;
|
|
end;
|
|
break;
|
|
end else if (ResultCode = 0) or Dependency_List[DependencyIndex].ForceSuccess then begin // ERROR_SUCCESS (0)
|
|
break;
|
|
end else if ResultCode = 1641 then begin // ERROR_SUCCESS_REBOOT_INITIATED (1641)
|
|
NeedsRestart := True;
|
|
Result := Dependency_List[DependencyIndex].Title;
|
|
break;
|
|
end else if ResultCode = 3010 then begin // ERROR_SUCCESS_REBOOT_REQUIRED (3010)
|
|
Dependency_NeedRestart := True;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
case SuppressibleMsgBox(FmtMessage(SetupMessage(msgErrorFunctionFailed), [Dependency_List[DependencyIndex].Title, IntToStr(ResultCode)]), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of
|
|
IDABORT: begin
|
|
Result := Dependency_List[DependencyIndex].Title;
|
|
break;
|
|
end;
|
|
IDIGNORE: begin
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if Result <> '' then begin
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
if NeedsRestart then begin
|
|
TempValue := '"' + ExpandConstant('{srcexe}') + '" /restart=1 /LANG="' + ExpandConstant('{language}') + '" /DIR="' + WizardDirValue + '" /GROUP="' + WizardGroupValue + '" /TYPE="' + WizardSetupType(False) + '" /COMPONENTS="' + WizardSelectedComponents(False) + '" /TASKS="' + WizardSelectedTasks(False) + '"';
|
|
if WizardNoIcons then begin
|
|
TempValue := TempValue + ' /NOICONS';
|
|
end;
|
|
RegWriteStringValue(HKA, 'SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce', '{#SetupSetting("AppName")}', TempValue);
|
|
end;
|
|
end;
|
|
|
|
Dependency_DownloadPage.Hide;
|
|
end;
|
|
end;
|
|
|
|
<event('UpdateReadyMemo')>
|
|
function Dependency_Internal3(const Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
|
|
begin
|
|
Result := '';
|
|
if MemoUserInfoInfo <> '' then begin
|
|
Result := Result + MemoUserInfoInfo + Newline + NewLine;
|
|
end;
|
|
if MemoDirInfo <> '' then begin
|
|
Result := Result + MemoDirInfo + Newline + NewLine;
|
|
end;
|
|
if MemoTypeInfo <> '' then begin
|
|
Result := Result + MemoTypeInfo + Newline + NewLine;
|
|
end;
|
|
if MemoComponentsInfo <> '' then begin
|
|
Result := Result + MemoComponentsInfo + Newline + NewLine;
|
|
end;
|
|
if MemoGroupInfo <> '' then begin
|
|
Result := Result + MemoGroupInfo + Newline + NewLine;
|
|
end;
|
|
if MemoTasksInfo <> '' then begin
|
|
Result := Result + MemoTasksInfo;
|
|
end;
|
|
|
|
if Dependency_Memo <> '' then begin
|
|
if MemoTasksInfo = '' then begin
|
|
Result := Result + SetupMessage(msgReadyMemoTasks);
|
|
end;
|
|
Result := Result + FmtMessage(Dependency_Memo, [Space]);
|
|
end;
|
|
end;
|
|
|
|
<event('NeedRestart')>
|
|
function Dependency_Internal4: Boolean;
|
|
begin
|
|
Result := Dependency_NeedRestart;
|
|
end;
|
|
|
|
function Dependency_IsX64: Boolean;
|
|
begin
|
|
Result := not Dependency_ForceX86 and Is64BitInstallMode;
|
|
end;
|
|
|
|
function Dependency_String(const x86, x64: String): String;
|
|
begin
|
|
if Dependency_IsX64 then begin
|
|
Result := x64;
|
|
end else begin
|
|
Result := x86;
|
|
end;
|
|
end;
|
|
|
|
function Dependency_ArchSuffix: String;
|
|
begin
|
|
Result := Dependency_String('_x64', '_x64');
|
|
end;
|
|
|
|
function Dependency_ArchTitle: String;
|
|
begin
|
|
Result := Dependency_String(' (x86)', ' (x64)');
|
|
end;
|
|
|
|
function Dependency_IsNetCoreInstalled(const Version: String): Boolean;
|
|
var
|
|
ResultCode: Integer;
|
|
begin
|
|
// source code: https://github.com/dotnet/deployment-tools/tree/main/src/clickonce/native/projects/NetCoreCheck
|
|
if not FileExists(ExpandConstant('{tmp}{\}') + 'netcorecheck' + Dependency_ArchSuffix + '.exe') then begin
|
|
ExtractTemporaryFile('netcorecheck' + Dependency_ArchSuffix + '.exe');
|
|
end;
|
|
Result := ShellExec('', ExpandConstant('{tmp}{\}') + 'netcorecheck' + Dependency_ArchSuffix + '.exe', Version, '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and (ResultCode = 0);
|
|
end;
|
|
|
|
function Dependency_IsVCRuntimeInstalled(const Arch: String; const Major, Minor, Bld: Cardinal): Boolean;
|
|
var
|
|
InstalledFlag, InstMajor, InstMinor, InstBld: Cardinal;
|
|
Key: String;
|
|
begin
|
|
// Canonical VC++ runtime detection per Microsoft docs:
|
|
// https://learn.microsoft.com/en-us/cpp/windows/redistributing-visual-cpp-files
|
|
// The redistributable installer writes these values to both registry views,
|
|
// so a plain HKLM read is correct from Inno Setup's 32-bit process.
|
|
Key := 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\' + Arch;
|
|
Result :=
|
|
RegQueryDWordValue(HKLM, Key, 'Installed', InstalledFlag) and (InstalledFlag = 1) and
|
|
RegQueryDWordValue(HKLM, Key, 'Major', InstMajor) and
|
|
RegQueryDWordValue(HKLM, Key, 'Minor', InstMinor) and
|
|
RegQueryDWordValue(HKLM, Key, 'Bld', InstBld) and
|
|
((InstMajor > Major) or
|
|
((InstMajor = Major) and (InstMinor > Minor)) or
|
|
((InstMajor = Major) and (InstMinor = Minor) and (InstBld >= Bld)));
|
|
end;
|
|
|
|
procedure Dependency_AddVC2015To2022;
|
|
var
|
|
Arch, Url: String;
|
|
MinMajor, MinMinor, MinBld: Cardinal;
|
|
begin
|
|
// https://docs.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist
|
|
MinMajor := 14;
|
|
MinMinor := 30;
|
|
MinBld := 30704;
|
|
|
|
if IsARM64 then begin
|
|
Arch := 'arm64';
|
|
Url := 'https://aka.ms/vc14/vc_redist.arm64.exe';
|
|
end else begin
|
|
Arch := 'x64';
|
|
Url := 'https://aka.ms/vc14/vc_redist.x64.exe';
|
|
end;
|
|
|
|
// Primary: registry-based detection (Microsoft's documented method, stable
|
|
// across installer builds). Fallback: MSI UpgradeCode lookup for x64 only
|
|
// (the x64 UpgradeCode {36F68A90-...} is verified; keeping a fallback helps
|
|
// on unusual install states). See issue #4596 for the regression this
|
|
// replaces, where a ProductCode was mistakenly used with IsMsiProductInstalled.
|
|
if Dependency_IsVCRuntimeInstalled(Arch, MinMajor, MinMinor, MinBld) then Exit;
|
|
if (Arch = 'x64') and IsMsiProductInstalled('{36F68A90-239C-34DF-B58C-64B30153CE35}',
|
|
PackVersionComponents(MinMajor, MinMinor, MinBld, 0)) then Exit;
|
|
|
|
Dependency_Add('vcredist2022_' + Arch + '.exe',
|
|
'/passive /norestart',
|
|
'Visual C++ 2015-2022 Redistributable (' + Arch + ')',
|
|
Url,
|
|
'', False, False);
|
|
end;
|
|
|
|
|
|
procedure Dependency_AddWebView2;
|
|
var
|
|
WebView2URL, WebView2Title: String;
|
|
begin
|
|
// https://developer.microsoft.com/en-us/microsoft-edge/webview2
|
|
if not RegValueExists(HKLM, Dependency_String('SOFTWARE', 'SOFTWARE\WOW6432Node') + '\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}', 'pv') then begin
|
|
if IsARM64 then begin
|
|
WebView2URL := 'https://go.microsoft.com/fwlink/?linkid=2099616';
|
|
WebView2Title := 'WebView2 Runtime (ARM64)';
|
|
end else begin
|
|
WebView2URL := 'https://go.microsoft.com/fwlink/?linkid=2124701';
|
|
WebView2Title := 'WebView2 Runtime (x64)';
|
|
end;
|
|
Dependency_Add('MicrosoftEdgeWebview2Setup.exe',
|
|
'/silent /install',
|
|
WebView2Title,
|
|
WebView2URL,
|
|
'', False, False);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
[Files]
|
|
#ifdef Dependency_Path_NetCoreCheck
|
|
; download netcorecheck_x64.exe: https://www.nuget.org/packages/Microsoft.NET.Tools.NETCoreCheck.x64
|
|
Source: "{#Dependency_Path_NetCoreCheck}netcorecheck_x64.exe"; Flags: dontcopy noencryption
|
|
#endif
|
|
|
|
#ifdef Dependency_Path_DirectX
|
|
Source: "{#Dependency_Path_DirectX}dxwebsetup.exe"; Flags: dontcopy noencryption
|
|
#endif
|