Hello i am trying to make an installer using INNO SETUP, when i started to use ISSkin Code Inno setup send me an error mesage DUPLICATE IDENTIFIER 'INITIALIZESETUP' I would like to know what i have to change to my code to make it work.
I was reading at internet and i found a program called IS Script Joiner, i used it but it doesnt work.
Here is my Inno Code:
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "Myprogram"
#define MyAppVersion "2.8"
#define MyAppPublisher "Myprogram"
#define MyAppURL "http://www.example.com/"
#define MyAppExeName "program.exe"
#define ISSI_WizardSmallBitmapImage "wpBanner.bmp"
#define ISSI_WizardSmallBitmapImage_x 495
#define ISSI_WizardSmallBitmapImage_Align
#define ISSI_IncludePath "C:\ISSI"
#include ISSI_IncludePath+"\_issi.isi"
[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={{2A8CE1DB-2FDB-4CAA-8A2C-0FE3DB8A500D}
AppName=Myprogram
AppVersion=2.8
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher=Myprogram
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\Myprogram
DefaultGroupName={#MyAppName}
LicenseFile=C:\Libraries\EULA.rtf
OutputDir=C:\Users\Hans Lopez\INNO SETUPS
OutputBaseFilename=programoutput
SetupIconFile=C:\Libraries\Icon.ico
Compression=lzma/Max
SolidCompression=true
WizardImageFile=C:\InstallMlockPackage\Setupbanner.bmp
AppVerName=2.8
DirExistsWarning=yes
VersionInfoProductName=Myprogram
VersionInfoProductVersion=2.8
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl"
[Dirs]
Name: "{app}" ; Permissions: everyone-full
Name: {sd}\myprogramfolder; Permissions: everyone-full;
[Code]
//===================================================================Verify if Installed===============================================================================
function GetUninstallString: string;
var
sUnInstPath: string;
sUnInstallString: String;
begin
Result := '';
sUnInstallString := '';
if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
Result := sUnInstallString;
end;
function IsUpgrade: Boolean;
begin
Result := (GetUninstallString() <> '');
end;
function InitializeSetup: Boolean;
var
V: Integer;
iResultCode: Integer;
sUnInstallString: string;
begin
Result := True; // in case when no previous version is found
if RegValueExists(HKEY_LOCAL_MACHINE,'Software\Microsoft\Windows\CurrentVersion\Uninstall\ {2A8CE1DB-2FDB-4CAA-8A2C-0FE2DB8A500D}_is1', 'UninstallString') then //Your App GUID/ID
begin
V := MsgBox(ExpandConstant('Myprogram is Already installed, Do you want to continue?'), mbInformation, MB_YESNO); //Custom Message if App installed
if V = IDYES then
begin
sUnInstallString := GetUninstallString();
sUnInstallString := RemoveQuotes(sUnInstallString);
Exec(ExpandConstant(sUnInstallString), '', '', SW_SHOW, ewWaitUntilTerminated, iResultCode);
Result := True; //if you want to proceed after uninstall
//Exit; //if you want to quit after uninstall
end
else
Result := False; //when older version present and not uninstalled
end;
end;
//====================================================================Unistall and Delete Everything==================================================================
procedure DeleteBitmaps(ADirName: string);
var
FindRec: TFindRec;
begin
if FindFirst(ADirName + '\*.*', FindRec) then begin
try
repeat
if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then begin
if (FindRec.Name <> '.') and (FindRec.Name <> '..') then begin
DeleteBitmaps(ADirName + '\' + FindRec.Name);
RemoveDir(ADirName + '\' + FindRec.Name);
end;
end else if Pos('.bmp', AnsiLowerCase(FindRec.Name)) > 0 then
DeleteFile(ADirName + '\' + FindRec.Name);
until not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end;
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usUninstall then begin
if MsgBox('Do you want to delete all data files?', mbConfirmation,
MB_YESNO) = IDYES
then begin
DeleteBitmaps(ExpandConstant('{app}'));
end;
end;
end;
//===========================================================ISSKinCODE=============================================================================
// Importing LoadSkin API from ISSkin.DLL
procedure LoadSkin(lpszPath: String; lpszIniFileName: String);
external 'LoadSkin#files:isskin.dll stdcall';
// Importing UnloadSkin API from ISSkin.DLL
procedure UnloadSkin();
external 'UnloadSkin#files:isskin.dll stdcall';
// Importing ShowWindow Windows API from User32.DLL
function ShowWindow(hWnd: Integer; uType: Integer): Integer;
external 'ShowWindow#user32.dll stdcall';
function InitializeSetup(): Boolean;
begin
ExtractTemporaryFile('iTunesB.msstyles');
LoadSkin(ExpandConstant('{tmp}\iTunesB.msstyles'), '');
Result := True;
end;
procedure DeinitializeSetup();
begin
// Hide Window before unloading skin so user does not get
// a glimpse of an unskinned window before it is closed.
ShowWindow(StrToInt(ExpandConstant('{wizardhwnd}')), 0);
UnloadSkin();
end;
/////////////////////////////////////////////////////////////ENDCODE/////////////////////////////////////////////////////////////////////////////////////////////////
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: " {cm:AdditionalIcons}"; Flags: unchecked
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: " {cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
[Files]
Source: "C:\My program\program.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files\C:\My program\*"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\programfolder\*"; DestDir: "{sd}\Myprogramfolder"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: ISSkin.dll; DestDir: {app}; Flags: dontcopy
Source: "C:\InstallMlockPackage\ISSkin\iTunesB\iTunesB\iTunesB.msstyles"; DestDir: " {tmp}"; Flags: dontcopy
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: " {app}\icon.ico" ;
Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}"; IconFilename: "{app}\icon.ico" ;
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"; IconFilename: "{app}\icon.ico" ;
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon; IconFilename: "{app}\icon.ico" ;
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon; IconFilename: "{app}\icon.ico" ;
Name: {group}\Uninstall =ISSkin; Filename: {app}\unins000.exe
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram, {#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
Thank You very Much for Your Help
Relocate the two calls to the ISSkin DLL from where they are now (above the second InitializeSetup) to just above the first InitializeSetup declaration.
// Importing LoadSkin API from ISSkin.DLL
procedure LoadSkin(lpszPath: String; lpszIniFileName: String);
external 'LoadSkin#files:isskin.dll stdcall';
// Importing UnloadSkin API from ISSkin.DLL
procedure UnloadSkin();
external 'UnloadSkin#files:isskin.dll stdcall';
Change the first InitializeSetup code to include the calls to extract and load the skin (from the second InitializeSetup).
function InitializeSetup: Boolean;
var
V: Integer;
iResultCode: Integer;
sUnInstallString: string;
begin
// These two lines moved from second InitializeSetup declaration before it
// was removed.
ExtractTemporaryFile('iTunesB.msstyles');
LoadSkin(ExpandConstant('{tmp}\iTunesB.msstyles'), '');
Result := True; // in case when no previous version is found
if RegValueExists(HKEY_LOCAL_MACHINE,'Software\Microsoft\Windows\CurrentVersion\Uninstall\ {2A8CE1DB-2FDB-4CAA-8A2C-0FE2DB8A500D}_is1', 'UninstallString') then //Your App GUID/ID
begin
V := MsgBox(ExpandConstant('Myprogram is Already installed, Do you want to continue?'), mbInformation, MB_YESNO); //Custom Message if App installed
if V = IDYES then
begin
sUnInstallString := GetUninstallString();
sUnInstallString := RemoveQuotes(sUnInstallString);
Exec(ExpandConstant(sUnInstallString), '', '', SW_SHOW, ewWaitUntilTerminated, iResultCode);
Result := True; //if you want to proceed after uninstall
//Exit; //if you want to quit after uninstall
end
else
Result := False; //when older version present and not uninstalled
end;
end;
Remove the second InitializeSetup code entirely.
Related
I have a license.exe file that I call in my setup code at the end,
The code needs the environment variable to be set before working correctly,
The code is as follows:
[Registry]
; set PATH
Root: HKLM; \
Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: string; ValueName: "PATH"; ValueData: "{app}"
[Setup]
; Tell Windows Explorer to reload the environment
ChangesEnvironment=yes
[Run]
Filename: "{app}\temp\installation_files\license.exe";
Here the code executes, but does not find the correct path.
When I check the system environment variable, it is set correctly,
When I run the license.exe code afterwards manually, it works correctly and sees the environment variable.
Can someone tell me how to fix this?
Or how to delay the [Run] section until the system recognizes the environment variable?
The processes created for executing entries from the [Run] section inherits the environment block of its parent process, which is the installer itself. So you have to set the environment variable to the installer and let it inherit to your executed application. How to do that is shown in the below script:
[Run]
Filename: "{app}\temp\installation_files\license.exe"; BeforeInstall: SetEnvPath
[Code]
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
function SetEnvironmentVariable(lpName: string; lpValue: string): BOOL;
external 'SetEnvironmentVariable{#AW}#kernel32.dll stdcall';
procedure SetEnvPath;
begin
if not SetEnvironmentVariable('PATH', ExpandConstant('{app}')) then
MsgBox(SysErrorMessage(DLLGetLastError), mbError, MB_OK);
end;
Previous answer for notifying rest of the system about variable change:
As #Jerry pointed out in his comment, a notification about the environment changes is performed after the [Run] section is processed. Actually, it is one of the last things executed by the installer.
So, to notify the system about environment changes before processing the [Run] section, you'll need to have a workaround. I rewrote the RefreshEnvironment procedure from Inno Setup code to script. It's the same function as it's executed if you have ChangesEnvironment directive set to yes.
In the following script I have removed the ChangesEnvironment directive and added execution of the RefreshEnvironment procedure from the AfterInstall parameter function of your registry entry:
[Registry]
Root: HKLM; \
Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: string; ValueName: "PATH"; ValueData: "{app}"; \
AfterInstall: RefreshEnvironment;
[Run]
Filename: "{app}\temp\installation_files\license.exe";
[Code]
const
SMTO_ABORTIFHUNG = 2;
WM_WININICHANGE = $001A;
WM_SETTINGCHANGE = WM_WININICHANGE;
type
WPARAM = UINT_PTR;
LPARAM = INT_PTR;
LRESULT = INT_PTR;
function SendTextMessageTimeout(hWnd: HWND; Msg: UINT;
wParam: WPARAM; lParam: PAnsiChar; fuFlags: UINT;
uTimeout: UINT; out lpdwResult: DWORD): LRESULT;
external 'SendMessageTimeoutA#user32.dll stdcall';
procedure RefreshEnvironment;
var
S: AnsiString;
MsgResult: DWORD;
begin
S := 'Environment';
SendTextMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
PAnsiChar(S), SMTO_ABORTIFHUNG, 5000, MsgResult);
end;
The solution with SetEnvironmentVariable in TLama's answer is correct for many situations.
But it won't work for [Run] tasks with runasoriginaluser flag (what is implied by postinstall flag). I.e. the variable won't be propagated to an application run with common "Run My Program" check box on the "Finished" page.
The reason is that the tasks with runasoriginaluser are executed by a un-elevated hidden parent process of the Inno Setup installer. The SetEnvironmentVariable will change environment for the installer, but not for its parent process. Unfortunately, the parent process of the installer cannot be controlled (imo).
As a workaround, to set the variable for the runasoriginaluser tasks, you have to inject an intermediate process between the installer parent process and the task, and have the intermediate process set the variable.
Such an intermediate process can easily be the cmd.exe with its set command:
[Run]
Filename: "{cmd}"; Parameters: "/C set PATH=%PATH%;{app} & ""{app}\MyProg.exe"""; \
Description: "Run My Program"; Flags: postinstall runhidden
The runhidden flag hides the cmd.exe console window, not the application (assuming it's a GUI application). If it's a console application and you want the output to be visible, remove the runhidden flag. Alternatively, you can use start command to start the application in its own console window.
after some modifications below, worked perfectly:
[Run]
Filename: "{app}\{#MyAppExeName}"; BeforeInstall: AppendToPathAndRefresh;Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}";Flags: nowait postinstall shellexec skipifsilent
[Code]
////////////////////////////////////////////////////////////
const
SMTO_ABORTIFHUNG = 2;
WM_WININICHANGE = $001A;
type
WPARAM = UINT_PTR;
LPARAM = INT_PTR;
LRESULT = INT_PTR;
function SendTextMessageTimeout(hWnd: HWND; Msg: UINT;
wParam: WPARAM; lParam: PAnsiChar; fuFlags: UINT;
uTimeout: UINT; out lpdwResult: DWORD): LRESULT;
external 'SendMessageTimeoutA#user32.dll stdcall';
procedure RefreshEnvironment;
var
S: AnsiString;
MsgResult: DWORD;
begin
S := 'Environment';
SendTextMessageTimeout(HWND_BROADCAST, WM_WININICHANGE, 0,
PAnsiChar(S), SMTO_ABORTIFHUNG, 5000, MsgResult);
end;
///PATH ENVINRONMENT//////////////////////////////////////////
function Replace(Dest, SubStr, Str: string): string;
var
Position: Integer;
Ok: Integer;
begin
Ok := 1;
while Ok > 0 do
begin
Position:=Pos(SubStr, Dest);
if Position > 0 then
begin
Delete(Dest, Position, Length(SubStr));
Insert(Str, Dest, Position);
end else
Ok := 0;
end;
Result:=Dest;
end;
procedure AppendToPath();
var
V: string;
Str: string;
begin
RegQueryStringValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', V)
Str := ExpandConstant('{app}\libav');
V := Replace(V, Str, '');
V := V + ';' + Str;
V := Replace(V,';;',';');
RegWriteStringValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', V)
// MsgBox(V, mbInformation, MB_OK);
end;
procedure RemoveFromPath();
var
V: string;
Str: string;
begin
RegQueryStringValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', V)
Str := ExpandConstant('{app}\dlls');
V := Replace(V, Str, '');
V := Replace(V,';;',';');
RegWriteStringValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', V)
//MsgBox(V, mbInformation, MB_OK);
end;
procedure AppendToPathAndRefresh;
begin
AppendToPath;
RefreshEnvironment;
end;
procedure DeinitializeUninstall();
begin
RemoveFromPath();
end;
///END OF PATH ENVIRONMENT ///////////////////////////////////
I have a license.exe file that I call in my setup code at the end,
The code needs the environment variable to be set before working correctly,
The code is as follows:
[Registry]
; set PATH
Root: HKLM; \
Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: string; ValueName: "PATH"; ValueData: "{app}"
[Setup]
; Tell Windows Explorer to reload the environment
ChangesEnvironment=yes
[Run]
Filename: "{app}\temp\installation_files\license.exe";
Here the code executes, but does not find the correct path.
When I check the system environment variable, it is set correctly,
When I run the license.exe code afterwards manually, it works correctly and sees the environment variable.
Can someone tell me how to fix this?
Or how to delay the [Run] section until the system recognizes the environment variable?
The processes created for executing entries from the [Run] section inherits the environment block of its parent process, which is the installer itself. So you have to set the environment variable to the installer and let it inherit to your executed application. How to do that is shown in the below script:
[Run]
Filename: "{app}\temp\installation_files\license.exe"; BeforeInstall: SetEnvPath
[Code]
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
function SetEnvironmentVariable(lpName: string; lpValue: string): BOOL;
external 'SetEnvironmentVariable{#AW}#kernel32.dll stdcall';
procedure SetEnvPath;
begin
if not SetEnvironmentVariable('PATH', ExpandConstant('{app}')) then
MsgBox(SysErrorMessage(DLLGetLastError), mbError, MB_OK);
end;
Previous answer for notifying rest of the system about variable change:
As #Jerry pointed out in his comment, a notification about the environment changes is performed after the [Run] section is processed. Actually, it is one of the last things executed by the installer.
So, to notify the system about environment changes before processing the [Run] section, you'll need to have a workaround. I rewrote the RefreshEnvironment procedure from Inno Setup code to script. It's the same function as it's executed if you have ChangesEnvironment directive set to yes.
In the following script I have removed the ChangesEnvironment directive and added execution of the RefreshEnvironment procedure from the AfterInstall parameter function of your registry entry:
[Registry]
Root: HKLM; \
Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: string; ValueName: "PATH"; ValueData: "{app}"; \
AfterInstall: RefreshEnvironment;
[Run]
Filename: "{app}\temp\installation_files\license.exe";
[Code]
const
SMTO_ABORTIFHUNG = 2;
WM_WININICHANGE = $001A;
WM_SETTINGCHANGE = WM_WININICHANGE;
type
WPARAM = UINT_PTR;
LPARAM = INT_PTR;
LRESULT = INT_PTR;
function SendTextMessageTimeout(hWnd: HWND; Msg: UINT;
wParam: WPARAM; lParam: PAnsiChar; fuFlags: UINT;
uTimeout: UINT; out lpdwResult: DWORD): LRESULT;
external 'SendMessageTimeoutA#user32.dll stdcall';
procedure RefreshEnvironment;
var
S: AnsiString;
MsgResult: DWORD;
begin
S := 'Environment';
SendTextMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
PAnsiChar(S), SMTO_ABORTIFHUNG, 5000, MsgResult);
end;
The solution with SetEnvironmentVariable in TLama's answer is correct for many situations.
But it won't work for [Run] tasks with runasoriginaluser flag (what is implied by postinstall flag). I.e. the variable won't be propagated to an application run with common "Run My Program" check box on the "Finished" page.
The reason is that the tasks with runasoriginaluser are executed by a un-elevated hidden parent process of the Inno Setup installer. The SetEnvironmentVariable will change environment for the installer, but not for its parent process. Unfortunately, the parent process of the installer cannot be controlled (imo).
As a workaround, to set the variable for the runasoriginaluser tasks, you have to inject an intermediate process between the installer parent process and the task, and have the intermediate process set the variable.
Such an intermediate process can easily be the cmd.exe with its set command:
[Run]
Filename: "{cmd}"; Parameters: "/C set PATH=%PATH%;{app} & ""{app}\MyProg.exe"""; \
Description: "Run My Program"; Flags: postinstall runhidden
The runhidden flag hides the cmd.exe console window, not the application (assuming it's a GUI application). If it's a console application and you want the output to be visible, remove the runhidden flag. Alternatively, you can use start command to start the application in its own console window.
after some modifications below, worked perfectly:
[Run]
Filename: "{app}\{#MyAppExeName}"; BeforeInstall: AppendToPathAndRefresh;Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}";Flags: nowait postinstall shellexec skipifsilent
[Code]
////////////////////////////////////////////////////////////
const
SMTO_ABORTIFHUNG = 2;
WM_WININICHANGE = $001A;
type
WPARAM = UINT_PTR;
LPARAM = INT_PTR;
LRESULT = INT_PTR;
function SendTextMessageTimeout(hWnd: HWND; Msg: UINT;
wParam: WPARAM; lParam: PAnsiChar; fuFlags: UINT;
uTimeout: UINT; out lpdwResult: DWORD): LRESULT;
external 'SendMessageTimeoutA#user32.dll stdcall';
procedure RefreshEnvironment;
var
S: AnsiString;
MsgResult: DWORD;
begin
S := 'Environment';
SendTextMessageTimeout(HWND_BROADCAST, WM_WININICHANGE, 0,
PAnsiChar(S), SMTO_ABORTIFHUNG, 5000, MsgResult);
end;
///PATH ENVINRONMENT//////////////////////////////////////////
function Replace(Dest, SubStr, Str: string): string;
var
Position: Integer;
Ok: Integer;
begin
Ok := 1;
while Ok > 0 do
begin
Position:=Pos(SubStr, Dest);
if Position > 0 then
begin
Delete(Dest, Position, Length(SubStr));
Insert(Str, Dest, Position);
end else
Ok := 0;
end;
Result:=Dest;
end;
procedure AppendToPath();
var
V: string;
Str: string;
begin
RegQueryStringValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', V)
Str := ExpandConstant('{app}\libav');
V := Replace(V, Str, '');
V := V + ';' + Str;
V := Replace(V,';;',';');
RegWriteStringValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', V)
// MsgBox(V, mbInformation, MB_OK);
end;
procedure RemoveFromPath();
var
V: string;
Str: string;
begin
RegQueryStringValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', V)
Str := ExpandConstant('{app}\dlls');
V := Replace(V, Str, '');
V := Replace(V,';;',';');
RegWriteStringValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', V)
//MsgBox(V, mbInformation, MB_OK);
end;
procedure AppendToPathAndRefresh;
begin
AppendToPath;
RefreshEnvironment;
end;
procedure DeinitializeUninstall();
begin
RemoveFromPath();
end;
///END OF PATH ENVIRONMENT ///////////////////////////////////
I am continuing with my work in Inno Setup, So now I have a new questions about it.
I am trying of to execute some programs before install my final application, for this purpose I am using Exec function.
When I try with the following code:
[Files]
Source: "AccessDatabaseEngine_x64.exe"; DestDir: "{tmp}"; Flags: dontcopy noencryption
Source: "Database.accdb"; DestDir: "{app}"; Flags: ignoreversion
[Code]
function PrepareToInstall(var NeedsRestart: Boolean): String;
Var
ResultCode: Integer;
begin
ExtractTemporaryFile('AccessDatabaseEngine_x64.exe');
if Exec(ExpandConstant('{tmp}\AccessDatabaseEngine_x64.exe'), 'quit', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
begin
msgbox('True: {tmp}\AccessDatabaseEngine_x64.exe : ' + IntToStr(ResultCode), mbInformation, MB_OK);
end
else begin
msgbox('False: {tmp}\AccessDatabaseEngine_x64.exe : ' + SysErrorMessage(ResultCode), mbInformation, MB_OK);
end;
end;
I get this error:
On the other hand, if I use the follow code:
[Files]
Source: "AccessDatabaseEngine_x64.exe"; DestDir: "{tmp}"; Flags: dontcopy noencryption
Source: "Database.accdb"; DestDir: "{app}"; Flags: ignoreversion
[Code]
function PrepareToInstall(var NeedsRestart: Boolean): String;
Var
ResultCode: Integer;
begin
ExtractTemporaryFile('AccessDatabaseEngine_x64.exe');
if Exec(ExpandConstant('{tmp}\AccessDatabaseEngine_x64.exe'), '', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
begin
msgbox('True: {tmp}\AccessDatabaseEngine_x64.exe : ' + IntToStr(ResultCode), mbInformation, MB_OK);
end
else begin
msgbox('False: {tmp}\AccessDatabaseEngine_x64.exe : ' + SysErrorMessage(ResultCode), mbInformation, MB_OK);
end;
end;
I get the installation wizard of the another file. Some like this:
I want to install my other programs automatically, without user intervention.
Is it possible? Can you help me?
Thank for advance!
The usage screen says /quiet, and you use quit.
So use /quiet, not quit:
if Exec(ExpandConstant('{tmp}\AccessDatabaseEngine_x64.exe'), '/quiet', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
I was inattentive, the correct answer is in the first picture. The word that should be used is: /quiet; not /quite, not /quit.
As support (if this happens again to someone other) I leave the next link:
Description of the command-line switches that are supported by a software installation package, an update package, or a hotfix package that was created by using Microsoft Self-Extractor
.
Likewise many thaks for you attention.
The option needed is :
/passive Runs the update without any interaction from the user.
if Exec(ExpandConstant('{tmp}\AccessDatabaseEngine_x64.exe'), '/passive', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
My Inno Setup script is used to install a driver. It runs my InstallDriver.exe after this file was copied during step ssInstall.
I need to ask the user to restart in some cases according to the value returned by InstallDriver.exe.
This means that I cannot put InstallDriver.exe in section [Run] because there's no way to monitor it's return value.
So I put it in function CurStepChanged() as follows:
procedure CurStepChanged(CurStep: TSetupStep);
var
TmpFileName, ExecStdout, msg: string;
ResultCode: Integer;
begin
if (CurStep=ssPostInstall) then
begin
Log('CurStepChanged(ssPostInstall)');
TmpFileName := ExpandConstant('{app}') + '\InstallDriver.exe';
if Exec(TmpFileName, 'I', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then .......
However, I can't find a way to make my script restart at this stage.
I thought of using function NeedRestart() to monitor the output of the driver installer, but it is called earlier in the process.
Does it make sense to call the driver installer from within NeedRestart()?
NeedRestart does not look like the right place to install anything. But it would work, as it's fortunately called only once. You will probably want to present a progress somehow though, as the wizard form is almost empty during a call to NeedRestart.
An alternative is to use AfterInstall parameter of the InstallDriver.exe or the driver binary itself (whichever is installed later).
#define InstallDriverName "InstallDriver.exe"
[Files]
Source: "driver.sys"; DestDir: ".."
Source: "{#InstallDriverName}"; DestDir: "{app}"; AfterInstall: InstallDriver
[Code]
var
NeedRestartFlag: Boolean;
const
NeedRestartResultCode = 1;
procedure InstallDriver();
var
InstallDriverPath: string;
ResultCode: Integer;
begin
Log('Installing driver');
InstallDriverPath := ExpandConstant('{app}') + '\{#InstallDriverName}';
if not Exec(InstallDriverPath, 'I', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
begin
Log('Failed to execute driver installation');
end
else
begin
Log(Format('Driver installation finished with code %d', [ResultCode]))
if ResultCode = NeedRestartResultCode then
begin
Log('Need to restart to finish driver installation');
NeedRestartFlag := True;
end;
end;
end;
function NeedRestart(): Boolean;
begin
if NeedRestartFlag then
begin
Log('Need restart');
Result := True;
end
else
begin
Log('Do not need restart');
Result := False;
end;
end;
My idea is to offer the user the choice of installing the application either in {localappdata} or {commonappdata}, and that part works fine. However, I'm using custom Inno Setup skinning support, which requires a couple functions to get loaded during installation/uninstallation.
I have a DefaultAppDataFolder(): String function which returns the folder that the user chose (either common or local appdata one), and it works fine during installation. However, when I try to uninstall the app, it throws following error right upon execution:
Script error: Could not call proc
You can see that in the DefaultAppDataFolder() function I'm getting the uninstall directory in a bit shady way, extracting the file directory twice from the {UninstallExe} constant, maybe there is a better way to retrieve this?
Here is my script:
#define ApplicationName "MyApp"
#define ApplicationExe "app.exe"
#define ApplicationInstanceMutex "APPMUTEX"
#define InstallerFilename "install_app"
#define SkinName "Carbon.vsf"
[Setup]
AppName={#ApplicationName}
AppVerName={#ApplicationName}
DefaultDirName={code:DefaultAppDataFolder}
DefaultGroupName={#ApplicationName}
UninstallFilesDir={code:DefaultAppDataFolder}\uninstall
UninstallDisplayName={#ApplicationName}
Compression=lzma2
SolidCompression=yes
OutputDir=.\
DisableDirPage=yes
OutputBaseFilename={#InstallerFilename}
UninstallDisplayIcon={code:DefaultAppDataFolder}\{#ApplicationExe}
DisableProgramGroupPage=yes
AppMutex={#ApplicationInstanceMutex}
WizardImageFile=installer_images\installer-1.bmp
WizardSmallImageFile=installer_images\installer-2.bmp
[Files]
Source: "skins\VclStylesInno.dll"; DestDir: "{code:DefaultAppDataFolder}"; Flags: uninsneveruninstall ignoreversion
Source: "skins\{#SkinName}"; DestDir: "{code:DefaultAppDataFolder}"; Flags: ignoreversion
Source: "root_files\*.*"; DestDir: "{code:DefaultAppDataFolder}"; Flags: ignoreversion
Source: "client_files\*.*"; DestDir: "{code:DefaultAppDataFolder}"; Flags: ignoreversion
Source: "ssl_libs\*.*"; DestDir: "{code:DefaultAppDataFolder}"; Flags: ignoreversion
[Icons]
Name: "{group}\{#ApplicationName}"; Filename: "{code:DefaultAppDataFolder}\{#ApplicationExe}"; WorkingDir: "{code:DefaultAppDataFolder}"
Name: "{group}\Uninstall"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#ApplicationName}"; Filename: "{code:DefaultAppDataFolder}\{#ApplicationExe}"; Tasks: desktopicon
[Run]
Filename: "{code:DefaultAppDataFolder}\{#ApplicationExe}"; Description: "Launch {#ApplicationName}"; Flags: postinstall nowait runascurrentuser
[Tasks]
Name: commondir; Description: "&All users"; GroupDescription: "Install For:"; Flags: exclusive
Name: localdir; Description: "&Current user"; GroupDescription: "Install For:"; Flags: exclusive unchecked
Name: desktopicon; Description: "Create a &desktop icon"
[Code]
procedure LoadVCLStyleS(VClStyleFile: String); external 'LoadVCLStyleW#files:VclStylesInno.dll stdcall setuponly';
procedure UnLoadVCLStylesS; external 'UnLoadVCLStyles#files:VclStylesInno.dll stdcall setuponly';
procedure LoadVCLStyleU(VClStyleFile: String); external 'LoadVCLStyleW#{code:DefaultAppDataFolder}\VclStylesInno.dll stdcall uninstallonly';
procedure UnLoadVCLStylesU; external 'UnLoadVCLStyles#{code:DefaultAppDataFolder}\VclStylesInno.dll stdcall uninstallonly';
var
ApplicationUninstalled: Boolean;
WizardInitialized: Boolean;
function InitializeSetup(): Boolean;
var
C1: Integer;
begin
ExtractTemporaryFile('{#SkinName}');
LoadVCLStyleS(ExpandConstant('{tmp}\{#SkinName}'));
result := TRUE;
end;
procedure InitializeWizard();
begin
WizardInitialized := TRUE;
end;
procedure DeinitializeSetup();
begin
UnLoadVCLStylesS;
end;
function InitializeUninstall(): Boolean;
begin
LoadVCLStyleU(ExpandConstant('{code:DefaultAppDataFolder}\{#SkinName}'));
result := TRUE;
end;
procedure InitializeUninstallProgressForm();
begin
ApplicationUninstalled := TRUE;
end;
procedure DeinitializeUninstall();
begin
UnLoadVCLStylesU;
UnloadDLL(ExpandConstant('{code:DefaultAppDataFolder}\VclStylesInno.dll'));
if ApplicationUninstalled then
begin
DeleteFile(ExpandConstant('{code:DefaultAppDataFolder}\VclStylesInno.dll'));
RemoveDir(ExpandConstant('{code:DefaultAppDataFolder}'));
end;
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
mres: integer;
begin
case CurUninstallStep of
usPostUninstall: begin
mres := MsgBox('Do you want to delete user data?', mbConfirmation, MB_YESNO or MB_DEFBUTTON2)
if mres = IDYES then
begin
DelTree(ExpandConstant('{localappdata}\{#ApplicationName}'), TRUE, TRUE, TRUE);
DelTree(ExpandConstant('{userappdata}\{#ApplicationName}'), TRUE, TRUE, TRUE);
end;
end;
end;
end;
function DefaultAppDataFolder(Param: String): String;
begin
if IsUninstaller then
result := ExtractFileDir(ExtractFileDir(ExpandConstant('{uninstallexe}')))
else
if (WizardInitialized) and
(IsTaskSelected('localdir')) then
result := ExpandConstant('{localappdata}') + '\Programs\{#ApplicationName}'
else
result := ExpandConstant('{commonappdata}') + '\Programs\{#ApplicationName}';
end;
The error you got is not related to the uninstaller; you can narrow the problem down to this:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName=My Program
[Code]
procedure DoSomething;
external 'DoSomething#{code:GetLibPath}\MyLib.dll stdcall setuponly';
function GetLibPath(Value: string): string;
begin
Result := 'C:\ValidPathToLib';
end;
From the above script it seems that you cannot use scripted constants for imported DLL file names. And even delayed loading didn't workaround this limit. But for your case you can use just {app} path since your library is actually there (if I get your intention right):
...
procedure LoadVCLStyleU(VClStyleFile: string);
external 'LoadVCLStyleW#{app}\VclStylesInno.dll stdcall uninstallonly';
procedure UnLoadVCLStylesU;
external 'UnLoadVCLStyles#{app}\VclStylesInno.dll stdcall uninstallonly';
...