Link to home
Start Free TrialLog in
Avatar of cerebrumconsulting
cerebrumconsulting

asked on

Use Inno Setup to detect and install Windows Installer 4.5

I'm installing SQL Server Express 2008 as part of my installation using Inno Setup.  On my Windows XP, SP 3 virtual test machine, the installation fails because Windows Installer 4.5 is not installed.  How do I detect that this version of Windows Installer is missing?  Once the script detects it is missing, how to I get it to install the correct version?
ASKER CERTIFIED SOLUTION
Avatar of Ferruccio Accalai
Ferruccio Accalai
Flag of Italy image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I think the easiest is if you launch it anyways. If it's already there, it will do nothing. Command line switch /quiet will make it quiet, /norestart will prohibit restart. From all times I was running it, it always wanted restart and never actually needed it, installer 4.5 always worked ok right after the installation.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of cerebrumconsulting
cerebrumconsulting

ASKER

These suggestions were well intentioned and helpful to a degree, but none really gave me what I was looking for.  However, I was able to work it out for myself and I post it here in case this may be helpful to someone else in my situation.
function InitializeSetup(): Boolean;
var
  ErrorMsg :String;
  ErrorCode :Integer;
  MS, LS :Cardinal;
  MajorVerNo, MinorVerNo :Word; 
  NetSPVer :DWord;
  InstallMSI :Boolean;
  WindowsVersion: TWindowsVersion;

begin
  Result := True;
  If not IsWin64 then
  begin
    MsgBox('This computer is running a 64-bit version of Windows.  This installation is intended for a 32-bit Windows operating system only.  ' +
           'Please use the 32-bit version for this computer available from www.dgcontrol.com', mbConfirmation, MB_OK);
    Result := False;
  end;

  if Result then
  begin
    GetVersionNumbers(ExpandConstant('{sys}\msi.dll'), MS, LS);
    DecodeVersion(MS, MajorVerNo, MinorVerNo);
    InstallMSI := (MajorVerNo < 4) or ((MajorVerNo = 4) and (MinorVerNo < 5));
    if InstallMSI then
    begin
      Result := False;
      if MsgBox('DGControl requires that Windows Installer version 4.5 or higher be installed.  ' +
                'This installation can be downloaded now from the internet and installed on this computer, ' +
                'or you can do it yourself manually at a later time from a certified Microsoft download site. ' + 
                'Would you like to update Windows Installer now?' + #13#10#13#10 +
                '(After completing this step, you will have to rerun the DGControl setup program.)', mbConfirmation, MB_YESNO) = IDYES then
      begin 
        MsgBox('Once Windows Installer 4.5 has been installed, you will have to restart this computer, then rerun the DGControl Setup program.', mbConfirmation, MB_OK);
        ErrorMsg := 'Unable to install the Microsoft Installer 4.5 for the following reason: ' + #13#10#13#10;
        GetWindowsVersionEx(WindowsVersion);
        // Windows XP 
        if WindowsVersion.NTPlatform and 
          (WindowsVersion.Major = 5) and
          (WindowsVersion.Minor = 1) then
        begin
          if WindowsVersion.ServicePackMajor < 2 then
            MsgBox('Windows XP Service Pack 2 must be installed before the Windows Installer 4.5 can be installed.  ' +
                   'Please install the latest service pack for this computer, then rerun DGControl to again attempt to install Windows Installer 4.5.', mbConfirmation, MB_OK)
          else 
            if not ShellExec('open',	'http://www.dgcsoftware.com/userftp/WindowsXP-KB942288-v3-x86.exe',	'','',SW_SHOWNORMAL,ewNoWait,ErrorCode) then
              MsgBox(ErrorMsg + SysErrorMessage(ErrorCode), mbConfirmation, MB_OK);
        end else // Windows Server 2003
        if WindowsVersion.NTPlatform and 
          (WindowsVersion.Major = 5) and
          (WindowsVersion.Minor = 2) then
        begin
          if not ShellExec('open',	'http://www.dgcsoftware.com/userftp/WindowsServer2003-KB942288-v4-x86.exe',	'','',SW_SHOWNORMAL,ewNoWait,ErrorCode) then
            MsgBox(ErrorMsg + SysErrorMessage(ErrorCode), mbConfirmation, MB_OK);
        end else // Windows Vista 
        if WindowsVersion.NTPlatform and 
          (WindowsVersion.Major = 6) then
        begin
          if not ShellExec('open',	'http://www.dgcsoftware.com/userftp/Windows6.0-KB942288-v2-x86.exe',	'','',SW_SHOWNORMAL,ewNoWait,ErrorCode) then
            MsgBox(ErrorMsg + SysErrorMessage(ErrorCode), mbConfirmation, MB_OK);
        end; 
      end;
    end;
  end;

  if Result then
  begin
    Result := RegKeyExists(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v2.0.50727');
    if Result then
    begin
      Result := False;
      if RegValueExists(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v2.0.50727', 'SP') then
      begin
        RegQueryDWordValue(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v2.0.50727', 'SP', NetSPVer);
        Result := (NetSPVer = 2);
      end;
    end;

    if not Result then
    begin
      if (MsgBox('This installation requires the Windows .NET Framework 2.0 SP 2 to be installed.  ' + 
                 'DGControl can download and install this framework for you, or you can do so yourself at a later time from a Microsoft download site. ' + #13#10#13#10 +
                 'Would like to install the .NET Framework now.' + #13#10#13#10 +
                 '(After the .NET Framework in installed, you will have to rerun the DGControl setup program.)', mbConfirmation, MB_YESNO) = idYes) then
      begin
        if not ShellExec('open',	'http://www.dgcsoftware.com/userftp/NetFx20SP2_x86.exe',	'','',SW_SHOWNORMAL,ewNoWait,ErrorCode) then
        begin
          ErrorMsg := 'Unable to install the Microsoft .NET Framework for the following reason: ' + #13#10#13#10 + SysErrorMessage(ErrorCode);
          MsgBox(ErrorMsg, mbConfirmation, MB_OK);
        end;
      end;
    end;
  end;
end;

Open in new window

I've requested that this question be closed as follows:

Accepted answer: 500 points for CSI-Windows's comment http:/Q_27311365.html#36548450
Assisted answer: 0 points for cerebrumconsulting's comment http:/Q_27311365.html#36553051

for the following reason:

My own comment was the solution
If I correctly understand this code, its part related to Installer 4.5 is in fact implementation of the comment http:#36547782. If this is what worked, then that comment should be accepted.
(forgot to click "object" in the previous comment)
...sorry for multiple comments and maybe unnecessary Objection - I somehow missed author's last comment and looked only at the Reason.

If "my own comment was the solution", and "none really gave me what I was looking for",  then why another comment is accepted? and as I said, the code that appears to have been the solution in fact implements the very first comment from Ferruccio68 (contrary to the above quote).
I appreciate Ferruccio68 efforts, but my question Indicates I already knew what to do.  I wanted to know how to do it.  I knew I had to check the current version of windows installer and then upgrade if necessary to 4.5.  What I was asking for was "how" to do that.  That is why I posted the code sample, so some future individual in my boat, could see how it could be done.

However, I felt that it would be unfair to all that had participated to not aware any points.  You'd all made an effort to help and I wanted to show my appreciation.  I'm still fairly new to this.  In the future, should this situation reoccur, I'll take into consideration the "Accept Mutliple Solutions" feature and distributte the points around more fairly.


You asked exactly "How do I detect that this version of Windows Installer is missing?..."

So you really didn't know how to check the version (by reading the MSI.dll version, I mean)

Anyway I've suggested to take a look at the Inno Setup demo script CodeAutomation.iss that explains better than a long post here how to implement some code into Inno Setup.

Finally, for these reasons, I agree with the vadimrapp1 objection
That is correct.  I really didn't know how to check the version of msi.dll programmatically?  That was why I posted ths question on experts-exchange.com.  I was hoping for some specific code samples to show me how to do it.  I shall try to be even more specific in the future.  

The CodeAutomation.iss didn't prove as helpful to me as you think it should have.  My last post was intended to specifically answer the question of how to detect the current version of Windows Installer and upgrade it if needed to version 4.5.  I posted it in a hurry, and realize that it is missing some code, so this exchange has been advantageous in drawing that to my attention. I'm posting the corrected code here.

Again, it was not my intention to cause offense.  
; If you are using Inno Setup to install SQL Server Express 2008, you will
; need to ensure that its prerequisites are also installed.
; This code example serves to illustrate one way that can be accomplished.

#define MyAppName "My Program"
#define MyAppVersion "1.5"
#define MyAppPublisher "My Company, Inc."
#define MyAppURL "http://www.example.com/"
#define MyAppExeName "MyProg.exe"

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{0B417C92-8359-4905-8CA6-AEB7D5E7FBEC}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DisableDirPage=yes
DefaultGroupName={#MyAppName}
DisableProgramGroupPage=yes
OutputDir=C:\Tmp
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Files]
Source: "C:\Program Files (x86)\Inno Setup 5\Examples\MyProg.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Inno Setup 5\Examples\MyProgDatabase_Data.MDF"; DestDir: "{app}\{#CommonFiles}"; Flags: ignoreversion; Permissions: everyone-full users-full
Source: "C:\Program Files (x86)\Inno Setup 5\Examples\MyProgDatabase_Log.LDF"; DestDir: "{app}\{#CommonFiles}"; Flags: ignoreversion; Permissions: everyone-full users-full
Source: "C:\Program Files (x86)\Inno Setup 5\Examples\SQLEXPR32_X86_ENU.exe"; DestDir: "{app}\Temp"; Flags: ignoreversion deleteafterinstall; Permissions: everyone-full users-full
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"

[Run]
; Install SQL Server in unattended mode with progress indicators for user to view to know that the process is running
Filename: "{app}\Temp\SQLEXPR32_X86_ENU.exe"; Parameters: "/qs /ACTION=Install /FEATURES=SQLEngine /INSTANCENAME=MY_SQL_INSTANCE /ERRORREPORTING=1 /INDICATEPROGRESS /IAcceptSQLServerLicenseTerms /SECURITYMODE=SQL /SAPWD=MySQLPassword "; WorkingDir: "{app}\Temp"; StatusMsg: SQL Server 2008 Express Setup
; Attach MyProgDatabase to the new named instance of SQL Server Express
Filename: "sqlcmd"; Parameters: "-S {computername}\MY_SQL_INSTANCE -d master -U sa -P MySQLPassword -Q ""exec sp_attach_db @dbname = N'MyProgDatabase', @filename1 = N'{app}\{#CommonFiles}\MyProgDatabase_Data.mdf', @filename2 = N'{app}\{#CommonFiles}\MyProgDatabase_Log.ldf'"" "

[Code]
procedure DecodeVersion(const Version: cardinal; var MajorVerNo, MinorVerNo :word);
begin
  MajorVerNo := word(Version shr 16);
  MinorVerNo := word(Version and not $ffff0000);
end;

// Check for SQL Server Express prerequisites and stop installation if they are not present, while prompting user to install them. 
function InitializeSetup(): Boolean;
var
  ErrorMsg :String;
  ErrorCode :Integer;
  MS, LS :Cardinal;
  MajorVerNo, MinorVerNo :Word; 
  NetSPVer :DWord;
  InstallMSI :Boolean;
  WindowsVersion: TWindowsVersion;

begin
  Result := True;
  If IsWin64 then
  begin
    MsgBox('This computer is running a 64-bit version of Windows.  This installation is intended for a 32-bit Windows operating system only.  ' +
           'Please use the 32-bit version for this computer available from www.dgcontrol.com', mbConfirmation, MB_OK);
    Result := False;
  end;

  if Result then
  begin
    // SQLExpress 2008 requires Windows Installer 4.5.  Check the current version.
    GetVersionNumbers(ExpandConstant('{sys}\msi.dll'), MS, LS);
    DecodeVersion(MS, MajorVerNo, MinorVerNo);
    InstallMSI := (MajorVerNo < 4) or ((MajorVerNo = 4) and (MinorVerNo < 5));
    if InstallMSI then
    begin
      Result := False;
      if MsgBox('This setup program requires that Windows Installer version 4.5 or higher be installed.  ' + #13#10#13#10 +
                'Would you like to update Windows Installer now?', mbConfirmation, MB_YESNO) = IDYES then
      begin 
        MsgBox('Once Windows Installer 4.5 has been installed, you will have to restart this computer, then rerun the DGControl Setup program.', mbConfirmation, MB_OK);
        ErrorMsg := 'Unable to install the Microsoft Installer 4.5 for the following reason: ' + #13#10#13#10;
        GetWindowsVersionEx(WindowsVersion);
        // Windows XP 
        if WindowsVersion.NTPlatform and 
          (WindowsVersion.Major = 5) and
          (WindowsVersion.Minor = 1) then
        begin
          if WindowsVersion.ServicePackMajor < 2 then
            MsgBox('Windows XP Service Pack 2 must be installed before the Windows Installer 4.5 can be installed.  ' +
                   'Please install the latest service pack for this computer, then rerun this setup program to again attempt to install Windows Installer 4.5.', mbConfirmation, MB_OK)
          else 
            if not ShellExec('open',	'http://www.example.com/WindowsXP-KB942288-v3-x86.exe',	'','',SW_SHOWNORMAL,ewNoWait,ErrorCode) then
              MsgBox(ErrorMsg + SysErrorMessage(ErrorCode), mbConfirmation, MB_OK);
        end else // Windows Server 2003
        if WindowsVersion.NTPlatform and 
          (WindowsVersion.Major = 5) and
          (WindowsVersion.Minor = 2) then
        begin
          if not ShellExec('open',	'http://www.example.com/WindowsServer2003-KB942288-v4-x86.exe',	'','',SW_SHOWNORMAL,ewNoWait,ErrorCode) then
            MsgBox(ErrorMsg + SysErrorMessage(ErrorCode), mbConfirmation, MB_OK);
        end else // Windows Vista 
        if WindowsVersion.NTPlatform and 
          (WindowsVersion.Major = 6) then
        begin
          if not ShellExec('open',	'http://www.example.com/Windows6.0-KB942288-v2-x86.exe',	'','',SW_SHOWNORMAL,ewNoWait,ErrorCode) then
            MsgBox(ErrorMsg + SysErrorMessage(ErrorCode), mbConfirmation, MB_OK);
        end; 
      end;
    end;
  end;

  if Result then
  begin
    Result := RegKeyExists(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v2.0.50727');
    if Result then
    begin
      Result := False;
      if RegValueExists(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v2.0.50727', 'SP') then
      begin
        RegQueryDWordValue(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v2.0.50727', 'SP', NetSPVer);
        Result := (NetSPVer = 2);
      end;
    end;

    if not Result then
    begin
      if (MsgBox('This setup program requires the Windows .NET Framework 2.0 SP 2 to be installed.  ' + 
                 'Would like to install the .NET Framework now.' + #13#10#13#10 +
                 '(After the .NET Framework in installed, you will have to rerun the DGControl setup program.)', mbConfirmation, MB_YESNO) = idYes) then
      begin
        if not ShellExec('open',	'http://www.example.com/NetFx20SP2_x86.exe',	'','',SW_SHOWNORMAL,ewNoWait,ErrorCode) then
        begin
          ErrorMsg := 'Unable to install the Microsoft .NET Framework for the following reason: ' + #13#10#13#10 + SysErrorMessage(ErrorCode);
          MsgBox(ErrorMsg, mbConfirmation, MB_OK);
        end;
      end;
    end;
  end;
end;

Open in new window

I thought I had already closed it.
The reason for the Average grade--no offence intended--is simply that I was looking for a solution that showed me how to do what I asked about.  I did learn from the answers what to do, which gave me the starting point to figure out how to do it.
> I did learn from the answers what to do, which gave me the starting point to figure out how to do it.

Which is exactly what you should expect from this website, and qualifies for A. The very name of this website implies that you have the expertise sufficient to implement the how-to advise given by the experts; if something still appears unclear, all you have to do is to ask. Still, http:#36548450 gives a sample of the code how to detect the version of the dll.
I'll leave it up to you.