Introduction
Compiling our programs using external RTLs is generally always a good option to have smaller & efficient programs.
In the case of Visual Studio ones, the best option is to use its own setup kit, because:
- it frees us from caring about RTL requirements (needed files, components registrations, …)
- from Visual Studio 2015 to 2022, it is a single standard package.
- once installed, it is usually maintained by Windows Update.
On the other side, one of the few drawbacks is that it is that the whole package is about 24 Mb for the 64-bits and 14 Mb for 32-bits versions. It can be a bit excessive for small programs, and a problem to keep updated in our setup package.
The optimal solution might be to download (from MS site) and install it, if not already present.
The Solution
After some research, I downloaded a sample, and after some work, I wrote this Object Pascal code to be added in the [Code] section in our Inno Setup script.
{ ---- VCRedist processing code ----- }
// minimal RTL version required (default: 14.23.27820.0)
// minimal VC2019 RTL version: 14.29.30133.0
// minimal VC2022 RTL version: 14.32.31326.0
const VCRTL_MIN_V1 = 14;
const VCRTL_MIN_V2 = 23;
const VCRTL_MIN_V3 = 27820;
const VCRTL_MIN_V4 = 0;
// check if the needed RTL 32/64 bits is installed (by looking the registry)
function RTL_IsNeeded (bUse64BitsRTL: Boolean): Boolean;
var
sRegKey: string;
v1: Cardinal;
v2: Cardinal;
v3: Cardinal;
v4: Cardinal;
begin
// is it running on 64 bits OS?
if IsWin64 then
begin
sRegKey := 'SOFTWARE\WOW6432Node\Microsoft\VisualStudio\14.0\VC\Runtimes\';
// need 64 bits RTL?
if bUse64BitsRTL then
sRegKey := sRegKey + 'x64'
else
sRegKey := sRegKey + 'x86'
end
// else we have only 32 bits RTL on 32 bits OS...
else if not bUse64BitsRTL then
sRegKey := 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\X86';
// if we have a key, let's check it
if ((sRegKey <> '') and
RegQueryDWordValue (HKEY_LOCAL_MACHINE, sRegKey, 'Major', v1) and
RegQueryDWordValue (HKEY_LOCAL_MACHINE, sRegKey, 'Minor', v2) and
RegQueryDWordValue (HKEY_LOCAL_MACHINE, sRegKey, 'Bld', v3) and
RegQueryDWordValue (HKEY_LOCAL_MACHINE, sRegKey, 'RBld', v4)) then
begin
Log ('VC 2015-2022 Redist version: ' + IntToStr (v1) +
'.' + IntToStr (v2) + '.' + IntToStr (v3) +
'.' + IntToStr (v4));
{ Version info was found. Return true if later or equal to our
minimal required version RTL_MIN_Vx }
Result := not (
(v1 > VCRTL_MIN_V1) or ((v1 = VCRTL_MIN_V1) and
((v2 > VCRTL_MIN_V2) or ((v2 = VCRTL_MIN_V2) and
((v3 > VCRTL_MIN_V3) or ((v3 = VCRTL_MIN_V3) and
(v4 >= VCRTL_MIN_V4)))))));
end
else
Result := TRUE;
end;
// onDownload event handler
function OnDownloadProgress (const Url, FileName: String;
const Progress, ProgressMax: Int64): Boolean;
begin
if Progress = ProgressMax then
Log(Format('Successfully downloaded file to {tmp}: %s', [FileName]));
Result := TRUE;
end;
// download and install the requested RTL 32/64 bits
function RTL_DownloadAndInstall (bUse64BitsRTL: Boolean): Boolean;
var
ret_code: Integer;
sFile: String;
sSetupFile: String;
DownloadPage: TDownloadWizardPage;
begin
DownloadPage := CreateDownloadPage (SetupMessage (msgWizardPreparing),
'Needed Visual Studio C++ Runtime files...', @OnDownloadProgress);
DownloadPage.Clear;
if bUse64BitsRTL then
sSetupFile := 'VC_redist.x64.exe'
else
sSetupfile := 'VC_redist.x86.exe';
DownloadPage.Add ('https://aka.ms/vs/17/release/' + sSetupFile,
sSetupFile, '');
DownloadPage.Show;
try
try
DownloadPage.Download;
{ run the downloaded setup files }
sFile := ExpandConstant ('{tmp}\' + sSetupFile);
Log (Format ('- starting: %s', [sFile]));
DownloadPage.SetText ('installing package...', sSetupFile);
Exec (sFile, '/install /passive /norestart', '',
SW_SHOW, ewWaitUntilTerminated, ret_code);
Log (Format ('- done : %u', [ret_code]));
{ let's go on!! }
Result := TRUE;
except
SuppressibleMsgBox (AddPeriod (GetExceptionMessage), mbCriticalError,
MB_OK, IDOK);
Result := FALSE;
end;
finally
DownloadPage.Hide;
end;
end;
To link it to the setup flow, you can add something like the following Object Pascal function to the [Code] section:
function NextButtonClick (CurPageID: Integer): Boolean;
var
bUse64BitsRTL: Boolean;
begin
Result := TRUE;
if (CurPageID = wpReady) then
begin
{ do we need to download RTM? }
bUse64BitsRTL := TRUE;
if RTL_IsNeeded (bUse64BitsRTL) then
Result := RTL_DownloadAndInstall (bUse64BitsRTL);
end
end;
At this point, you have only the set bUse64BitsRTL to properly select the needed RTL type (32/64-bits) and the scripts should take care of all the dirty work.
If you need, you can also set a specific minimal RTL version by updating VCRTL_MIN_Vx constants. You can get your current one by looking in the folder below in your Visual Studio root folder:
<Visual Studio root folder>\VC\Redist\MSVC
One of the remarkable things is that this script is using only Inno Setup included features (ie no external plugins, …).
Finally, the only serious drawback of this solution is when the MS site is down (yes, it happened). If this file is needed but it cannot be downloaded, this means that your program cannot even start.
My current solution is to offer an emergency page to download a local and signed copy of the needed RTL setup file.