1
\$\begingroup\$

I don't have a virtual computer so I am not able to beta test this installation. Therefore I am kindly asking if I have gone about this correctly. It compiles OK.

Step 1

I declared these variables:

var
  vcRedist64BitPath: string;
  vcRedist32BitPath: string;
  bVcRedist64BitNeeded : boolean;
  bVcRedist32BitNeeded : boolean;

const
  // See: https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads
  vcRedist64BitURL = 'https://aka.ms/vs/16/release/vc_redist.x64.exe';
  vcRedist32BitURL = 'https://aka.ms/vs/16/release/vc_redist.x86.exe';

Step 2

I implemented these functions to test if the x86 and x64 redistributables are already installed:

// See: https://stackoverflow.com/a/51614652/2287576
function IsVCRedist64BitNeeded(): boolean;
var
  strVersion: string;
begin
  if (RegQueryStringValue(HKEY_LOCAL_MACHINE,
    'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64', 'Version', strVersion)) then
  begin
    // Is the installed version at least 14.14 ? 
    Log('VC Redist x64 Version : found ' + strVersion);
    Result := (CompareStr(strVersion, 'v14.14.26429.03') < 0);
  end
  else
  begin
    // Not even an old version installed
    Log('VC Redist x64 is not already installed');
    Result := True;
  end;
end;

function IsVCRedist32BitNeeded(): boolean;
var
  strVersion: string;
begin
  if (RegQueryStringValue(HKEY_LOCAL_MACHINE,
    'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x86', 'Version', strVersion)) then
  begin
    // Is the installed version at least 14.14 ? 
    Log('VC Redist x86 Version : found ' + strVersion);
    Result := (CompareStr(strVersion, 'v14.14.26429.03') < 0);
  end
  else
  begin
    if (RegQueryStringValue(HKEY_LOCAL_MACHINE,
      'SOFTWARE\WOW6432Node\Microsoft\VisualStudio\14.0\VC\Runtimes\x86', 'Version', strVersion)) then
    begin
      // Is the installed version at least 14.14 ? 
      Log('VC Redist x86 Version : found ' + strVersion);
      Result := (CompareStr(strVersion, 'v14.14.26429.03') < 0);
    end
    else
    begin
      // Not even an old version installed
      Log('VC Redist x86 is not already installed');
      Result := True;
    end;
  end;
end;

As I understand it, from the SO answer in the comment, 14.14 is the 2015 redistributable package and 2015 through 2019 use the same binaries. So I assume it is acceptable to look for this version in the registry.

Step 3

I updated PrepareToInstall:

function PrepareToInstall(var NeedsRestart: Boolean): String;
begin
  result := '';

  bVcRedist64BitNeeded := false;
  if(IsWin64()) then
  begin
    bVcRedist64BitNeeded := IsVCRedist64BitNeeded();
  end;
  bVcRedist32BitNeeded := IsVCRedist32BitNeeded();
end;

Step 4

Since I am using DWinsHs for downloading remote files I added the following two entries to the BeforeDownload callback:

function BeforeDownload(): boolean;
begin
  if(bVcRedist64BitNeeded) then
  begin
    // We need to download the 64 Bit VC Redistributable from the Microsoft Website
    vcRedist64BitPath := ExpandConstant('{tmp}\vc_redist.x64.exe');
    DwinsHs_AppendRemoteFile( vcRedist64BitPath, 
                  vcRedist64BitURL, 'My_Setup', rmGet, FILESIZE_QUERY_SERVER );
  end;

  if(bVcRedist32BitNeeded) then
  begin
    // We need to download the 32 Bit VC Redistributable from the Microsoft Website
    vcRedist32BitPath := ExpandConstant('{tmp}\vc_redist.x86.exe');
    DwinsHs_AppendRemoteFile( vcRedist32BitPath, 
                  vcRedist32BitURL, 'My_Setup', rmGet, FILESIZE_QUERY_SERVER );
  end;

  result := true;
end;

Step 5

Since I am using DWinsHs for downloading remote files I added the following two entries to the AfterDownload callback:

procedure AfterDownload(State: integer);
var
  ResultCode: integer;
begin
  if (State = READ_OK) then
  begin
    if(bVcRedist64BitNeeded) then
    begin
      if Exec(ExpandConstant(vcRedist64BitPath), '/install /passive /norestart', '',
          SW_SHOW, ewWaitUntilTerminated, ResultCode) then begin
        // handle success if necessary; ResultCode contains the exit code
        if not (ResultCode = 0) then begin
          MsgBox(ExpandConstant('The installation of Visual Studio x64 Redistributable failed. The Meeting Schedule Assistant installation will be aborted.'), mbInformation, MB_OK);
          Abort();
        end;
      end
      else begin
        // The execution failed for some reason
        MsgBox(SysErrorMessage(ResultCode), mbInformation, MB_OK);
        Abort();
      end;
    end;

    if(bVcRedist32BitNeeded) then
    begin
      if Exec(ExpandConstant(vcRedist32BitPath), '/install /passive /norestart', '',
          SW_SHOW, ewWaitUntilTerminated, ResultCode) then begin
        // handle success if necessary; ResultCode contains the exit code
        if not (ResultCode = 0) then begin
          MsgBox(ExpandConstant('The installation of Visual Studio x86 Redistributable failed. The Meeting Schedule Assistant installation will be aborted.'), mbInformation, MB_OK);
          Abort();
        end;
      end
      else begin
        // The execution failed for some reason
        MsgBox(SysErrorMessage(ResultCode), mbInformation, MB_OK);
        Abort();
      end;
    end;
  end;
end;

The installer parameters and registry keys I have obtained are from resources I have found on the internet.

My installer caters for both x86 and x64 file .exe files which is why I am detecting if both redistributables are installed.

Have I in principle done this correctly? Again, I do not have a virtual environment to test with.

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

I tested your code,

  1. Please move lines in PrepareToInstall method to BeforeDownload method:
  bVcRedist64BitNeeded := false;
  if(IsWin64()) then
  begin
    bVcRedist64BitNeeded := IsVCRedist64BitNeeded();
  end;
  bVcRedist32BitNeeded := IsVCRedist32BitNeeded();

Because the BeforeDownload is called earlier than PrepareToInstall method.

  1. Then add method:
    procedure CurPageChanged(CurPageID: Integer);
    begin
      DwinsHs_CurPageChanged(CurPageID, @BeforeDownload, @AfterDownload);
    end;

Also you can use the DwinsHs_Check to add the download files:

[files]
Source: "{tmp}\a.exe"; DestDir: "{tmp}\vc_redist.x32.exe"; Flags: external; Check: IsVCRedist32BitNeeded() and DwinsHs_Check(ExpandConstant('{tmp}\a.exe'), 'https://aka.ms/vs/16/release/vc_redist.x86.exe', 'My_Setup', 'Get', 0, 0 );
Source: "{tmp}\b.exe"; DestDir: "{tmp}\vc_redist.x64.exe"; Flags: external; Check: IsWin64() and IsVCRedist64BitNeeded() and DwinsHs_Check(ExpandConstant('{tmp}\b.exe'), 'https://aka.ms/vs/16/release/vc_redist.x64.exe', 'My_Setup', 'Get', 0, 0 );

then remove the BeforeDownload method.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks. Would it be better to cache the Is...Needed values first and then use the cached values? Otherwise we would have to run the same checks again in AfterDownload. \$\endgroup\$ Commented Jun 27, 2019 at 4:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.