Skip to content

Commit 7b00660

Browse files
download and install c++ runtime if not already installed for windows
1 parent e26afad commit 7b00660

File tree

1 file changed

+289
-1
lines changed

1 file changed

+289
-1
lines changed

tools/installer/installer.iss

Lines changed: 289 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
; -- CEdev installation script --
22

33
[Setup]
4-
AppName=TI-84+CE C SDK
4+
AppName=CE C Toolchain
55
AppVersion={#APP_VERSION}
66
DefaultDirName={sd}\CEdev
77
DefaultGroupName=CEdev
@@ -23,6 +23,24 @@ const SystemEnvironmentKey = 'SYSTEM\CurrentControlSet\Control\Session Manager\E
2323
const UserEnvironmentKey = 'Environment';
2424
const CEDEVKey = 'CEDEV';
2525
26+
type
27+
TDependency = record
28+
Filename: String;
29+
Parameters: String;
30+
Title: String;
31+
URL: String;
32+
Checksum: String;
33+
ForceSuccess: Boolean;
34+
InstallClean: Boolean;
35+
RebootAfter: Boolean;
36+
end;
37+
InstallResult = (InstallSuccessful, InstallRebootRequired, InstallError);
38+
var
39+
MemoInstallInfo: String;
40+
Dependencies: array of TDependency;
41+
DelayedReboot, ForceX86: Boolean;
42+
DownloadPage: TDownloadWizardPage;
43+
2644
procedure EnvAddPath(Path: string);
2745
var
2846
Paths: string;
@@ -71,5 +89,275 @@ begin
7189
end;
7290
7391
92+
// https://github.com/DomGries/InnoDependencyInstaller
93+
// code to download and install Microsoft Visual C++ Runtime as needed.
94+
procedure AddDependency(const Filename, Parameters, Title, URL, Checksum: String; const ForceSuccess, InstallClean, RebootAfter: Boolean);
95+
var
96+
Dependency: TDependency;
97+
I: Integer;
98+
begin
99+
MemoInstallInfo := MemoInstallInfo + #13#10 + '%1' + Title;
100+
Dependency.Filename := Filename;
101+
Dependency.Parameters := Parameters;
102+
Dependency.Title := Title;
103+
if FileExists(ExpandConstant('{tmp}{\}') + Filename) then begin
104+
Dependency.URL := '';
105+
end else begin
106+
Dependency.URL := URL;
107+
end;
108+
Dependency.Checksum := Checksum;
109+
Dependency.ForceSuccess := ForceSuccess;
110+
Dependency.InstallClean := InstallClean;
111+
Dependency.RebootAfter := RebootAfter;
112+
I := GetArrayLength(Dependencies);
113+
SetArrayLength(Dependencies, I + 1);
114+
Dependencies[I] := Dependency;
115+
end;
116+
function IsPendingReboot: Boolean;
117+
var
118+
Value: String;
119+
begin
120+
Result := RegQueryMultiStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager', 'PendingFileRenameOperations', Value) or
121+
(RegQueryMultiStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager', 'SetupExecute', Value) and (Value <> ''));
122+
end;
123+
function InstallProducts: InstallResult;
124+
var
125+
ResultCode, I, ProductCount: Integer;
126+
begin
127+
Result := InstallSuccessful;
128+
ProductCount := GetArrayLength(Dependencies);
129+
MemoInstallInfo := SetupMessage(msgReadyMemoTasks);
130+
if ProductCount > 0 then begin
131+
DownloadPage.Show;
132+
for I := 0 to ProductCount - 1 do begin
133+
if Dependencies[I].InstallClean and (DelayedReboot or IsPendingReboot) then begin
134+
Result := InstallRebootRequired;
135+
break;
136+
end;
137+
DownloadPage.SetText(Dependencies[I].Title, '');
138+
DownloadPage.SetProgress(I + 1, ProductCount);
139+
while True do begin
140+
ResultCode := 0;
141+
if ShellExec('', ExpandConstant('{tmp}{\}') + Dependencies[I].Filename, Dependencies[I].Parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode) then begin
142+
if Dependencies[I].RebootAfter then begin
143+
// delay reboot after install if we installed the last dependency anyways
144+
if I = ProductCount - 1 then begin
145+
DelayedReboot := True;
146+
end else begin
147+
Result := InstallRebootRequired;
148+
MemoInstallInfo := Dependencies[I].Title;
149+
end;
150+
break;
151+
end else if (ResultCode = 0) or Dependencies[I].ForceSuccess then begin
152+
break;
153+
end else if ResultCode = 3010 then begin
154+
// Windows Installer ResultCode 3010: ERROR_SUCCESS_REBOOT_REQUIRED
155+
DelayedReboot := True;
156+
break;
157+
end;
158+
end;
159+
case SuppressibleMsgBox(FmtMessage(SetupMessage(msgErrorFunctionFailed), [Dependencies[I].Title, IntToStr(ResultCode)]), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of
160+
IDABORT: begin
161+
Result := InstallError;
162+
MemoInstallInfo := MemoInstallInfo + #13#10 + ' ' + Dependencies[I].Title;
163+
break;
164+
end;
165+
IDIGNORE: begin
166+
MemoInstallInfo := MemoInstallInfo + #13#10 + ' ' + Dependencies[I].Title;
167+
break;
168+
end;
169+
end;
170+
end;
171+
if Result <> InstallSuccessful then begin
172+
break;
173+
end;
174+
end;
175+
DownloadPage.Hide;
176+
end;
177+
end;
178+
// Inno Setup event functions
179+
procedure InitializeWizard;
180+
begin
181+
DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), nil);
182+
end;
183+
function PrepareToInstall(var NeedsRestart: Boolean): String;
184+
var
185+
I: Integer;
186+
begin
187+
DelayedReboot := False;
188+
case InstallProducts of
189+
InstallError: begin
190+
Result := MemoInstallInfo;
191+
end;
192+
InstallRebootRequired: begin
193+
Result := MemoInstallInfo;
194+
NeedsRestart := True;
195+
// write into the registry that the installer needs to be executed again after restart
196+
RegWriteStringValue(HKEY_CURRENT_USER, 'SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce', 'InstallBootstrap', ExpandConstant('{srcexe}'));
197+
end;
198+
end;
199+
end;
200+
function NeedRestart: Boolean;
201+
begin
202+
Result := DelayedReboot;
203+
end;
204+
function UpdateReadyMemo(const Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
205+
begin
206+
Result := '';
207+
if MemoUserInfoInfo <> '' then begin
208+
Result := Result + MemoUserInfoInfo + Newline + NewLine;
209+
end;
210+
if MemoDirInfo <> '' then begin
211+
Result := Result + MemoDirInfo + Newline + NewLine;
212+
end;
213+
if MemoTypeInfo <> '' then begin
214+
Result := Result + MemoTypeInfo + Newline + NewLine;
215+
end;
216+
if MemoComponentsInfo <> '' then begin
217+
Result := Result + MemoComponentsInfo + Newline + NewLine;
218+
end;
219+
if MemoGroupInfo <> '' then begin
220+
Result := Result + MemoGroupInfo + Newline + NewLine;
221+
end;
222+
if MemoTasksInfo <> '' then begin
223+
Result := Result + MemoTasksInfo;
224+
end;
225+
if MemoInstallInfo <> '' then begin
226+
if MemoTasksInfo = '' then begin
227+
Result := Result + SetupMessage(msgReadyMemoTasks);
228+
end;
229+
Result := Result + FmtMessage(MemoInstallInfo, [Space]);
230+
end;
231+
end;
232+
function NextButtonClick(const CurPageID: Integer): Boolean;
233+
var
234+
I, ProductCount: Integer;
235+
Retry: Boolean;
236+
begin
237+
Result := True;
238+
if (CurPageID = wpReady) and (MemoInstallInfo <> '') then begin
239+
DownloadPage.Show;
240+
ProductCount := GetArrayLength(Dependencies);
241+
for I := 0 to ProductCount - 1 do begin
242+
if Dependencies[I].URL <> '' then begin
243+
DownloadPage.Clear;
244+
DownloadPage.Add(Dependencies[I].URL, Dependencies[I].Filename, Dependencies[I].Checksum);
245+
Retry := True;
246+
while Retry do begin
247+
Retry := False;
248+
try
249+
DownloadPage.Download;
250+
except
251+
if GetExceptionMessage = SetupMessage(msgErrorDownloadAborted) then begin
252+
Result := False;
253+
I := ProductCount;
254+
end else begin
255+
case SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of
256+
IDABORT: begin
257+
Result := False;
258+
I := ProductCount;
259+
end;
260+
IDRETRY: begin
261+
Retry := True;
262+
end;
263+
end;
264+
end;
265+
end;
266+
end;
267+
end;
268+
end;
269+
DownloadPage.Hide;
270+
end;
271+
end;
272+
// architecture helper functions
273+
function IsX64: Boolean;
274+
begin
275+
Result := not ForceX86 and Is64BitInstallMode;
276+
end;
277+
function GetString(const x86, x64: String): String;
278+
begin
279+
if IsX64 then begin
280+
Result := x64;
281+
end else begin
282+
Result := x86;
283+
end;
284+
end;
285+
function GetArchitectureSuffix: String;
286+
begin
287+
Result := GetString('', '_x64');
288+
end;
289+
function GetArchitectureTitle: String;
290+
begin
291+
Result := GetString(' (x86)', ' (x64)');
292+
end;
293+
function CompareVersion(const Version1, Version2: String): Integer;
294+
var
295+
Position, Number1, Number2: Integer;
296+
begin
297+
Result := 0;
298+
while (Version1 <> '') or (Version2 <> '') do begin
299+
Position := Pos('.', Version1);
300+
if Position > 0 then begin
301+
Number1 := StrToIntDef(Copy(Version1, 1, Position - 1), 0);
302+
Delete(Version1, 1, Position);
303+
end else if Version1 <> '' then begin
304+
Number1 := StrToIntDef(Version1, 0);
305+
Version1 := '';
306+
end else begin
307+
Number1 := 0;
308+
end;
309+
Position := Pos('.', Version2);
310+
if Position > 0 then begin
311+
Number2 := StrToIntDef(Copy(Version2, 1, Position - 1), 0);
312+
Delete(Version2, 1, Position);
313+
end else if Version2 <> '' then begin
314+
Number2 := StrToIntDef(Version2, 0);
315+
Version2 := '';
316+
end else begin
317+
Number2 := 0;
318+
end;
319+
if Number1 < Number2 then begin
320+
Result := -1;
321+
break;
322+
end else if Number1 > Number2 then begin
323+
Result := 1;
324+
break;
325+
end;
326+
end;
327+
end;
328+
329+
function MsiEnumRelatedProducts(UpgradeCode: String; Reserved, Index: DWORD; ProductCode: String): Integer;
330+
external 'MsiEnumRelatedProductsW@msi.dll stdcall';
331+
function MsiGetProductInfo(ProductCode, PropertyName, Value: String; var ValueSize: DWORD): Integer;
332+
external 'MsiGetProductInfoW@msi.dll stdcall';
333+
function IsMsiProductInstalled(const UpgradeCode, MinVersion: String): Boolean;
334+
var
335+
ProductCode, Version: String;
336+
ValueSize: DWORD;
337+
begin
338+
SetLength(ProductCode, 39);
339+
Result := False;
340+
if MsiEnumRelatedProducts(UpgradeCode, 0, 0, ProductCode) = 0 then begin
341+
SetLength(Version, 39);
342+
ValueSize := Length(Version);
343+
if MsiGetProductInfo(ProductCode, 'VersionString', Version, ValueSize) = 0 then begin
344+
Result := CompareVersion(Version, MinVersion) >= 0;
345+
end;
346+
end;
347+
end;
348+
349+
function InitializeSetup: Boolean;
350+
var
351+
Version: String;
352+
begin
74353
354+
if not IsMsiProductInstalled(GetString('{65E5BD06-6392-3027-8C26-853107D3CF1A}', '{36F68A90-239C-34DF-B58C-64B30153CE35}'), '14.28.29325') then begin
355+
AddDependency('vcredist2019' + GetArchitectureSuffix + '.exe',
356+
'/install /quiet /norestart',
357+
'Visual C++ 2015-2019 Redistributable' + GetArchitectureTitle,
358+
GetString('https://aka.ms/vs/16/release/vc_redist.x86.exe', 'https://aka.ms/vs/16/release/vc_redist.x64.exe'),
359+
'', False, False, False);
360+
end;
75361
362+
Result := True;
363+
end;

0 commit comments

Comments
 (0)