0
votes

I'm in the process of creating a custom installer and for the most part I have it set up the way I want it, except that it's missing two features I want to add to the Setup. I've done some extensive searching and while I've found plenty of similar questions, I haven't been able to take the responses to those and modify them for my specific needs with any success.

Basically what I need to do is create a custom function for 'Check:' that checks the version of DirectX that's currently installed. I know there is the 'RegQueryStringValue' function, and I know where the key is in the registry that contains the version (HKLM\SOFTWARE\Microsoft\DirectX, Version). I just don't know how to implement the code to check the version contained in the registry, and if it reports back a value less than 4.09.00.0904 to go ahead with the DXSETUP I have entered under [Files].

I also want to perform this same routine for a 'Check:' to use with Visual C++ 2005 (x86). This one I believe will be simpler as it only needs to check if an actual key exists (RegQueryKey?) and not a value. I believe the key for VC++ 2005 is HKLM\SOFTWARE\Microsoft\VisualStudio\8.0

If anyone can help me out I'd greatly appreciate it, as I've been messing with this for several hours trying to get something functional together without much success. If you require any further information from me I'd be more than happy to provide it.

1

1 Answers

3
votes

There's an example for checking for prerequisites included in the Inno Setup Examples of doing this sort of thing in CodePrepareToInstall.iss. InitializeSetup shows how to check for the existence of a registry entry, and you can do so in DetectAndInstallPrerequisites. I added a CheckDXVersion function that you can pass the Version string from the DirectX registry entry that checks for 4.9 or higher (untested!) you can use as well.

; -- CodePrepareToInstall.iss --
;
; This script shows how the PrepareToInstall event function can be used to
; install prerequisites and handle any reboots in between, while remembering
; user selections across reboots.

[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
DefaultGroupName=My Program
UninstallDisplayIcon={app}\MyProg.exe
OutputDir=userdocs:Inno Setup Examples Output

[Files]
Source: "MyProg.exe"; DestDir: "{app}";
Source: "MyProg.chm"; DestDir: "{app}";
Source: "Readme.txt"; DestDir: "{app}"; Flags: isreadme;

[Icons]
Name: "{group}\My Program"; Filename: "{app}\MyProg.exe"

[Code]
const
  (*** Customize the following to your own name. ***)
  RunOnceName = 'My Program Setup restart';

  QuitMessageReboot = 'The installation of a prerequisite program was not completed. You will need to restart your computer to complete that installation.'#13#13'After restarting your computer, Setup will continue next time an administrator logs in.';
  QuitMessageError = 'Error. Cannot continue.';

var
  Restarted: Boolean;

function InitializeSetup(): Boolean;
begin
  Restarted := ExpandConstant('{param:restart|0}') = '1';

  if not Restarted then begin
    Result := not RegValueExists(HKLM, 'Software\Microsoft\Windows\CurrentVersion\RunOnce', RunOnceName);
    if not Result then
      MsgBox(QuitMessageReboot, mbError, mb_Ok);
  end else
    Result := True;
end;

function CheckDXVersion(const VerString: String): Boolean;
var
  MajorVer, MinorVer: Integer;
  StartPos: Integer;
  TempStr: string;
begin
  (* Extract major version *)
  StartPos := Pos('.', VerString);
  MajorVer := StrToInt(Copy(VerString, 1, StartPos - 1);
  (* Remove major version and decimal point that follows *)
  TempStr := Copy(VerString, StartPos + 1, MaxInt);
  (* Find next decimal point *)
  StartPos := Pos('.', TempStr); 
  (* Extract minor version *)
  MinorVer := Copy(TempStr, 1, StartPos - 1);
  Result := (MajorVer > 4) or ((MajorVer = 4) and MinorVer >= 9));
end;

function DetectAndInstallPrerequisites: Boolean;
begin
  (*** Place your prerequisite detection and installation code below. ***)
  (*** Return False if missing prerequisites were detected but their installation failed, else return True. ***)

  //<your code here>

  Result := True;

  (*** Remove the following block! Used by this demo to simulate a prerequisite install requiring a reboot. ***)
  if not Restarted then
    RestartReplace(ParamStr(0), '');
end;

function Quote(const S: String): String;
begin
  Result := '"' + S + '"';
end;

function AddParam(const S, P, V: String): String;
begin
  if V <> '""' then
    Result := S + ' /' + P + '=' + V;
end;

function AddSimpleParam(const S, P: String): String;
begin
 Result := S + ' /' + P;
end;

procedure CreateRunOnceEntry;
var
  RunOnceData: String;
begin
  RunOnceData := Quote(ExpandConstant('{srcexe}')) + ' /restart=1';
  RunOnceData := AddParam(RunOnceData, 'LANG', ExpandConstant('{language}'));
  RunOnceData := AddParam(RunOnceData, 'DIR', Quote(WizardDirValue));
  RunOnceData := AddParam(RunOnceData, 'GROUP', Quote(WizardGroupValue));
  if WizardNoIcons then
    RunOnceData := AddSimpleParam(RunOnceData, 'NOICONS');
  RunOnceData := AddParam(RunOnceData, 'TYPE', Quote(WizardSetupType(False)));
  RunOnceData := AddParam(RunOnceData, 'COMPONENTS', Quote(WizardSelectedComponents(False)));
  RunOnceData := AddParam(RunOnceData, 'TASKS', Quote(WizardSelectedTasks(False)));

  (*** Place any custom user selection you want to remember below. ***)

  //<your code here>

  RegWriteStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\RunOnce', RunOnceName, RunOnceData);
end;

function PrepareToInstall(var NeedsRestart: Boolean): String;
var
  ChecksumBefore, ChecksumAfter: String;
begin
  ChecksumBefore := MakePendingFileRenameOperationsChecksum;
  if DetectAndInstallPrerequisites then begin
    ChecksumAfter := MakePendingFileRenameOperationsChecksum;
    if ChecksumBefore <> ChecksumAfter then begin
      CreateRunOnceEntry;
      NeedsRestart := True;
      Result := QuitMessageReboot;
    end;
  end else
    Result := QuitMessageError;
end;

function ShouldSkipPage(PageID: Integer): Boolean;
begin
  Result := Restarted;
end;