Selectively unregistereing and deleting a DLL dependant on another app being installed or not - inno-setup

In application B I have this code in the [Run] section:
Filename: "{dotnet40}\regasm.exe"; \
Parameters: "/u PTSTools_x86.dll"; \
WorkingDir: "{app}"; \
Flags: runhidden; \
Check: FileExists(ExpandConstant('{app}\PTSTools_x86.dll')); \
AfterInstall: DoDeleteFile(ExpandConstant('{app}\PTSTools_x86.dll'))
Filename: "{dotnet4064}\regasm.exe"; \
Parameters: "/u PTSTools_x64.dll"; \
WorkingDir: "{app}"; \
Flags: runhidden; \
Check: IsWin64 and FileExists(ExpandConstant('{app}\PTSTools_x64.dll')); \
AfterInstall: DoDeleteFile(ExpandConstant('{app}\PTSTools_x64.dll'))
I used to use those DLL files in application B but no longer need to. So I performed the above to "unregistered and get rid of them". That is OK in itself. BUT ...
I have application A which DOES use them! So, in its [Run] section it does have:
Filename: "{dotnet40}\regasm.exe"; \
Parameters: "PTSTools_x86.dll /codebase"; \
WorkingDir: "{app}"; \
Flags: runhidden
Filename: "{dotnet4064}\regasm.exe"; \
Parameters: "PTSTools_x64.dll /codebase"; \
WorkingDir: "{app}"; \
Flags: runhidden; \
Check: IsWin64
Now, the two applications are independent of each other. A user may have one, the other or both.
If they only have application B then it can unregister and delete the obsolete DLL files.
If they also have application A installed, then, the obsolete DLL files only need to be deleted because application A would have registered them in its folder.
Can do I perform this selection uninstallation behaviour?

Call the regasm /u from CurStepChanged(ssInstall) using Exec function, after checking if Application A is not installed.
To check if Application A is installed, use the same code as here:
Can Inno Setup respond differently to a new install and an update?
Excludes part of Code section in ssPostInstall step if installation is update in Inno Setup
Just use AppId of the Application A.
procedure Unregister(Filename: string);
var
Path, FilePath: string;
ResultCode: Integer;
begin
Path := ExpandConstant('{app}');
FilePath := AddBackslash(Path) + Filename;
if not FileExists(FilePath) then
begin
Log(Format('%s does not exist', [FilePath]));
end
else
begin
if IsAppAInstalled then
begin
Log(Format('Application A is installed, not unregistering %s', [FilePath]));
end
else
begin
if Exec(ExpandConstant('{dotnet40}\regasm.exe'), '/u ' + Filename,
Path, SW_HIDE, ewWaitUntilTerminated,
ResultCode) and
// Not sure about this
(ResultCode = 0) then
begin
Log(Format('Unregistered %s', [FilePath]));
end
else
begin
Log(Format('Failed to unregister %s', [FilePath]));
end;
end;
if DeleteFile(FilePath) then
begin
Log(Format('Deleted %s', [FilePath]));
end
else
begin
Log(Format('Failed to delete %s', [FilePath]));
end;
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then
begin
Unregister('PTSTools_x86.dll');
if IsWin64 then Unregister('PTSTools_x64.dll');
end;
end;

This is based on the accepted answer with minor tweaks:
Tweak 1
In CurStepChanged I changed it to be conditional for unregistering the 64 bit DLL:
else if (CurStep = ssInstall) then
begin
Unregister('PTSTools_x86.dll', ExpandConstant('{dotnet40}'));
if (IsWin64) then
begin
Unregister('PTSTools_x64.dll', ExpandConstant('{dotnet4064}'));
end;
end
Tweak 2
I modified Unregister to take a second parameter (the value of the expanded {dotnet40} constants). This is then used to build the path to regasm:
RegAsmPath := AddBackSlash(sDotNetRoot) + 'regasm.exe';
Then I simply used that value as the first parameter to Exec.

Related

How to unzip multiple files with InnoTools post install?

The script sample I have came from http://www.saidsimple.com/daniel/blog/117966/ and it’s only set for one zip. I want to be able to unzip any zips in a particular location. I guess one approach might be a wildcard *.zip when the zip name might vary depending on earlier installer selections.
No unzipping occurs. I’ve missed defining something or procedure is not setup properly. In my use the zips are text files the intended program reads for functions.
[Setup] …
SolidCompression=true
Compression=lzma
CreateAppDir=false
DirExistsWarning=false
ShowLanguageDialog=false
CreateUninstallRegKey=no
#include <idp.iss>
[Files]
Source: "{tmp}\text.net"; DestDir: "{userappdata}\ccc"; Flags: external; Components: abc
Source: "{tmp}\HLNJ.zip"; DestDir: "{userappdata}\ccc"; Flags: external deleteafterinstall; Components: hlnj
Source: "{tmp}\HNJ.zip"; DestDir: "{userappdata}\ccc"; Flags: external deleteafterinstall; Components: hnj
[Code]
const
SHCONTCH_NOPROGRESSBOX = 4;
SHCONTCH_RESPONDYESTOALL = 16;
procedure InitializeWizard; ...
begin ...
end;
procedure CurStepChanged(CurStep: TSetupStep); ...
begin
if CurStep = ssPostInstall then
begin ...
end;
end;
procedure unzip(ZipFile, TargetFldr: PAnsiChar);
var
shellobj: variant;
ZipFileV, TargetFldrV: variant;
SrcFldr, DestFldr: variant;
shellfldritems: variant;
begin
if FileExists('{userappdata}\ccc\HLNJ.zip') then begin
ForceDirectories('{userappdata}\ccc’);
shellobj := CreateOleObject('Shell.Application');
ZipFileV := string(ZipFile);
TargetFldrV := string(TargetFldr);
SrcFldr := shellobj.NameSpace(ZipFileV);
DestFldr := shellobj.NameSpace(TargetFldrV);
shellfldritems := SrcFldr.Items;
DestFldr.CopyHere(shellfldritems, SHCONTCH_NOPROGRESSBOX or SHCONTCH_RESPONDYESTOALL);
end;
end;
procedure ExtractSomething(src, target : AnsiString);
begin
unzip(ExpandConstant(src), ExpandConstant(target));
end;
I would expect one of the zips to be unzipped. But nothing, even in inno log; nothing happens in this section of code. At least deletion of zip works.
EDIT: I’m revisiting an issue I did not solve last year. The problem is getting the Unzip to work. Zip downloads to location but is deleted without unzipping first.
EDIT 2: Might not be the best but appears to work. I’ve changed my recent code to a working version for Inno 5 (edited the filenames, removed setup.)
; #pragma include __INCLUDE__ + ";" + ReadReg(HKLM, "Software\Mitrich Software\Inno Download Plugin", "InstallDir")
#pragma include __INCLUDE__ + ";" + "c:\lib\InnoDownloadPlugin"
[Setup]
#include <idp.iss>
[Types]
Name: custom; Description: "Custom installation"; Flags: iscustom
[Components]
Name: conn; Description: “CC File”; Types: custom; Flags: exclusive
Name: hlnj; Description: “H L (Recommended)”; Types: custom; Flags: exclusive
[Files]
Source: "{tmp}\text.net"; DestDir: "{userappdata}\ccc”; Flags: external; Components: conn
Source: "{tmp}\HLNJ.zip”; DestDir: "{userappdata}\ccc”; Flags: external deleteafterinstall; Components: hlnj conn
[Code]
const
SHCONTCH_NOPROGRESSBOX = 4;
SHCONTCH_RESPONDYESTOALL = 16;
procedure InitializeWizard;
begin
idpAddFileComp('http://ccc.sourceforge.net/text.net', ExpandConstant('{tmp}\text.net'), 'conn');
idpAddFileComp('http://ccc.sourceforge.net/SecurityUpdates/HLNJ.zip', ExpandConstant('{tmp}\HLNJ.zip'), 'hlnj');
idpDownloadAfter(wpReady);
end;
procedure CurStepChanged1(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
FileCopy(ExpandConstant('{tmp}\text.net'), ExpandConstant('{userappdata}\ccc\text.net'), false);
FileCopy(ExpandConstant('{tmp}\HLNJ.zip'), ExpandConstant('{userappdata}\ccc\HLNJ.zip'), false);
end;
end;
procedure unzip(ZipFile, TargetFldr: variant);
var
shellobj: variant;
SrcFldr, DestFldr: variant;
shellfldritems: variant;
begin
if FileExists(ZipFile) then begin
if not DirExists(TargetFldr) then
if not ForceDirectories(TargetFldr) then begin
MsgBox('Can not create folder '+TargetFldr+' !!', mbError, MB_OK);
Exit;
end;
shellobj := CreateOleObject('Shell.Application');
SrcFldr := shellobj.NameSpace(ZipFile);
DestFldr := shellobj.NameSpace(TargetFldr);
shellfldritems := SrcFldr.Items;
DestFldr.CopyHere(shellfldritems, SHCONTCH_NOPROGRESSBOX or SHCONTCH_RESPONDYESTOALL);
if FileExists(TargetFldr+'\HLNJ.zip') then MsgBox('HLNJ.zip'+ZipFile+
' extracted to '+TargetFldr, mbInformation, MB_OK);
end else MsgBox('HLNJ.zip does not exist', mbError, MB_OK);
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
unzip(ExpandConstant('{userappdata}\ccc\HLNJ.zip'),ExpandConstant('{userappdata}\ccc'));
end;
end;
You can not even extract one .zip file.
So step by step first one and then ...
The code is not complete.
So one can only guess what is missing or wrong.
To test the proper functioning of the unzip procedure you should use a simple standard inno-setup program.
If this works you can add extra features and then find the error easier.
Also the used constants "src" and "target" are not visible.
How are they constructed?
unzip(ExpandConstant(src), ExpandConstant(target));
The use of different types of data should be avoided.
AnsiString vs PAnsiChar
procedure unzip(ZipFile, TargetFldr: PAnsiChar);
....
end;
procedure ExtractSomething(src, target : AnsiString);
begin
unzip(ExpandConstant(src), ExpandConstant(target));
end;
The use of {tmp} will, I suspect, made by the #include idp.iss download.
This code also not exists.
We will simulate this and use a known zip file from a known directory. So we do not need the download of the files.
Information also does not harm but makes it easier to find fault.
I used some MsgBox() for that.
A simple procedure is for the beginning following.
Copy the HLNJ.zip file to C:\HLNJ.zip
and look for a file or folder name part of the HLNJ.zip
so we can test the extraction.
I use here a file named atext.txt wich is part of my HLNJ.zip
CreateOleObject needs variants so use them instead.
[Files]
; Simulate the download of HLNJ.zip is ok
; On the development PC .. on the client PC.
Source: "C:\HLNJ.zip"; DestDir: "{tmp}";
; Now "HLNJ.zip" is in the {tmp} folder so we can use it.
Source: "{tmp}\HLNJ.zip"; DestDir: "{userappdata}\ccc"; Flags: external deleteafterinstall
[Code]
const
SHCONTCH_NOPROGRESSBOX = 4;
SHCONTCH_RESPONDYESTOALL = 16;
....
procedure unzip(ZipFile, TargetFldr: variant);// <--- variant instead of PAnsiChar
var
shellobj: variant;
SrcFldr, DestFldr: variant;
shellfldritems: variant;
begin
if FileExists(ZipFile) then begin
if not DirExists(TargetFldr) then
if not ForceDirectories(TargetFldr) then begin
MsgBox('Can not create folder '+TargetFldr+' !!', mbError, MB_OK);
Exit;
end;
shellobj := CreateOleObject('Shell.Application');
SrcFldr := shellobj.NameSpace(ZipFile);
DestFldr := shellobj.NameSpace(TargetFldr);
shellfldritems := SrcFldr.Items;
DestFldr.CopyHere(shellfldritems, SHCONTCH_NOPROGRESSBOX or SHCONTCH_RESPONDYESTOALL);
if FileExists(TargetFldr+'\atext.txt') then MsgBox('ZipFile '+ZipFile+
' extracted to '+TargetFldr, mbInformation, MB_OK);
end else MsgBox('ZipFile '+ZipFile+' does not exist', mbError, MB_OK);
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
unzip(ExpandConstant('{userappdata}\ccc\HLNJ.zip'),ExpandConstant('{userappdata}\ccc\extracted'));
end;
end;

Inno Setup - Delete old/obsolete files on update

So, I realize that this question has been asked before. In fact I read through a good 10 of them before writing this, but none of them have a applicable solution and I'm hoping that nowadays someone has found something.
The problem:
My program is build with a script, creating all final files in a single folder.
Those files are included in inno like this:
[Files]
Source: "build\exe.win-amd64-3.6\*"; Excludes: "*.key, *.log"; DestDir: "{app}"; \
Flags: ignoreversion recursesubdirs createallsubdirs
The application has been out there for a few months with different updates. There is no record anymore of old files, though it could be painstakingly re-assembled as we do have version control and I could build the old installers again.
From what I understand, you're meant to use the InstallDelete section to get rid of old files - however you are not meant to use wildcards and there is also no Excludes section to safeguard the single folder we have that may contain user data they may want to keep.
So, how do I get rid of old files? The application is 100 MB and a current user may have 300+ MB of old files that are no longer necessary, I'd love to clean that up.
TL;DR: I want the installer to either overwrite or delete all files in the application directory, except for one folder which contains user data.
The easiest solution is to delete all files in the installation folder before the installation.
As you know, you can use [InstallDelete] section for that. But that does not allow you to exclude the "data" folder.
You can code that Pascal Scripting instead. See Inno Setup - Delete whole application folder except for data subdirectory. You can call the DelTreeExceptSavesDir function from my answer to the that question from CurStepChanged(ssInstall) event function:
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then
begin
DelTreeExceptSavesDir(WizardDirValue);
end;
end;
If you really want to delete only obsolete files, to avoid deleting and re-creating existing files (what's not your case, as you are using ignoreversion flag anyway), you can use preprocessor to generate a list of files to be installed for the Pascal Scripting and use that to delete only really obsolete files.
#pragma parseroption -p-
#define FileEntry(DestDir) \
" FilesNotToBeDeleted.Add('" + LowerCase(DestDir) + "');\n"
#define ProcessFile(Source, Dest, FindResult, FindHandle) \
FindResult \
? \
Local[0] = FindGetFileName(FindHandle), \
Local[1] = Source + "\\" + Local[0], \
Local[2] = Dest + "\\" + Local[0], \
(Local[0] != "." && Local[0] != ".." \
? FileEntry(Local[2]) + \
(DirExists(Local[1]) ? ProcessFolder(Local[1], Local[2]) : "") \
: "") + \
ProcessFile(Source, Dest, FindNext(FindHandle), FindHandle) \
: \
""
#define ProcessFolder(Source, Dest) \
Local[0] = FindFirst(Source + "\\*", faAnyFile), \
ProcessFile(Source, Dest, Local[0], Local[0])
#pragma parseroption -p+
[Code]
var
FilesNotToBeDeleted: TStringList;
function InitializeSetup(): Boolean;
begin
FilesNotToBeDeleted := TStringList.Create;
FilesNotToBeDeleted.Add('\data');
{#Trim(ProcessFolder('build\exe.win-amd64-3.6', ''))}
FilesNotToBeDeleted.Sorted := True;
Result := True;
end;
procedure DeleteObsoleteFiles(Path: string; RelativePath: string);
var
FindRec: TFindRec;
FilePath: string;
FileRelativePath: string;
begin
if FindFirst(Path + '\*', FindRec) then
begin
try
repeat
if (FindRec.Name <> '.') and (FindRec.Name <> '..') then
begin
FilePath := Path + '\' + FindRec.Name;
FileRelativePath := RelativePath + '\' + FindRec.Name;
if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then
begin
DeleteObsoleteFiles(FilePath, FileRelativePath);
end;
if FilesNotToBeDeleted.IndexOf(Lowercase(FileRelativePath)) < 0 then
begin
if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then
begin
if RemoveDir(FilePath) then
begin
Log(Format('Deleted obsolete directory %s', [FilePath]));
end
else
begin
Log(Format('Failed to delete obsolete directory %s', [FilePath]));
end;
end
else
begin
if DeleteFile(FilePath) then
begin
Log(Format('Deleted obsolete file %s', [FilePath]));
end
else
begin
Log(Format('Failed to delete obsolete file %s', [FilePath]));
end;
end;
end;
end;
until not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end
else
begin
Log(Format('Failed to list %s', [Path]));
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then
begin
Log('Looking for obsolete files...');
DeleteObsoleteFiles(WizardDirValue, '');
end;
end;
For other options, see Inno Setup: Removing files installed by previous version.

Install file in Inno Setup Pascal code using FileCopy function (not to show the installation on wizard form)

How to copy a file using FileCopy function to the application folder, so that it's name does not display on the installing page? (FilenameLabel).
I.e. I want to use the first option of Inno Setup - How to hide certain filenames while installing? (FilenameLabel)
Use the FileCopy function in the CurStepChanged event function:
[Files]
Source: "MyProg.exe"; Flags: dontcopy
[Code]
procedure CurStepChanged(CurStep: TSetupStep);
begin
{ Install after installation, as then the application folder exists already }
if CurStep = ssPostInstall then
begin
Log('Installing file');
ExtractTemporaryFile('MyProg.exe');
if FileCopy(
ExpandConstant('{tmp}\MyProg.exe'), ExpandConstant('{app}\MyProg.exe'),
False) then
begin
Log('File installed.');
end
else
begin
Log('Failed to install file.');
end;
end;
end;

Opening a document in wizard before install

My problem is that i would like to make an "hyperlink"(i know there is now such thing in inno) when you click label a document(rtf) with instructions will open.
The problem: i DON'T want to copy this program along with the setup,
it should be inside the setup and after the installation it is no more
needed, thus it should be deleted or thrown out.
cant use {tmp} folder since it is accesed only in [run] phase(that is installation if i am not mistaken) and i need it earlier.
Any suggestions?
The temporary folder is not explicitly reserved for [Run] section. It can be used whenever needed (it is widely used e.g. for DLL libraries). And there is no such thing as a hyperlink label in Inno Setup as far as I know. I've made an example of a link lable and extended it for opening files that are extracted from the setup archive into a temporary folder (a folder that is deleted when the installer terminates):
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Files]
; the dontcopy flag tells the installer that this file is not going to be copied to
; the target system
Source: "File.txt"; Flags: dontcopy
[Code]
var
LinkLabel: TLabel;
procedure LinkLabelClick(Sender: TObject);
var
FileName: string;
ErrorCode: Integer;
begin
FileName := ExpandConstant('{tmp}\File.txt');
// if the file was not yet extracted into the temporary folder, do it now
if not FileExists(FileName) then
ExtractTemporaryFile('File.txt');
// open the file from the temporary folder; if that fails, show the error message
if not ShellExec('', FileName, '', '', SW_SHOW, ewNoWait, ErrorCode) then
MsgBox(Format('File could not be opened. Code: %d', [ErrorCode]), mbError, MB_OK);
end;
procedure InitializeWizard;
begin
LinkLabel := TLabel.Create(WizardForm);
LinkLabel.Parent := WizardForm;
LinkLabel.Left := 8;
LinkLabel.Top := WizardForm.ClientHeight - LinkLabel.ClientHeight - 8;
LinkLabel.Cursor := crHand;
LinkLabel.Font.Color := clBlue;
LinkLabel.Font.Style := [fsUnderline];
LinkLabel.Caption := 'Click me to read something important!';
LinkLabel.OnClick := #LinkLabelClick;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
LinkLabel.Visible := CurPageID <> wpLicense;
end;

Inno Setup: How do I create a 'check:' function for currently installed version of DirectX and whether MS VC++ 2005 is installed

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.
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;

Resources