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.