InnoSetup restart application after setup is done

I configured InnoSetup to install my application. There is a parameter “RestartApplications” which allows innoSetup to restart the application after the setup is done. InnoSetup states “the app must call a windows API method called RegisterApplicationRestart”. Here is the microsoft doc of this method:

Microsoft Docs

As I actually did not create any declare before, what have I to do? Could this be a valid declare?

Var lpwzCommandLine As String = "c:\program files\myProg\myProg.exe"
Var ldwFlags as UInt32 = 0

Declare Sub RegisterApplicationRestart Lib "winbase" (byRef lpwzCommandLine As CString, ldwFlags As UInt32)

it’s close, you need to actually call it after you declare it.

Var lpwzCommandLine As String = "c:\program files\myProg\myProg.exe"
Var ldwFlags as UInt32 = 0

Declare Sub RegisterApplicationRestart Lib "winbase" (byRef lpwzCommandLine As CString, ldwFlags As UInt32)

RegisterApplicationRestart(lpwzCommandLine, ldwFlags)

you should probably also consider the values of the flags though…

Value Meaning
1 RESTART_NO_CRASH Do not restart the process if it terminates due to an unhandled exception.
2 RESTART_NO_HANG Do not restart the process if it terminates due to the application not responding.
4 RESTART_NO_PATCH Do not restart the process if it terminates due to the installation of an update.
8 RESTART_NO_REBOOT Do not restart the process if the computer is restarted as the result of an update.

You probably don’t want your app to restart for crashes, hangs or reboots, so you should set those flags to 11 instead of 0.

actually I get a “too many arguments” compile error… got 2 expected only 0… :thinking:

ok, found another thing… the lib should be kernel32…

@Greg_O : Thanks for the hint with the flags… yes I should deactivate all those…

Well if you don’t call it, it’s not going to be activated.

I’m not sure that the first parameter needs to be ByRef either.

You should probably be calling UnregisterApplicationRestart when the user quits the app too.

I’ve never had this work. Instead, pass my own parameter.

First, you don’t need a declare. Use a Shell object to launch the update. Execute something like Path/To/Installer.exe /PARAMETER to begin. You can have as many parameters as you like, including the supported built-in ones. So if RestartApplications worked, you’d include /RESTARTAPPLICATIONS.

What I’ve done is use my own /NOLAUNCH parameter. In my Inno script, my “launch app” checkbox is defined as

Filename: "{app}\{#MyAppExeName}"; Parameters: "/NOSETUPCHECK"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Check: not CmdLineParamExists('/NOLAUNCH'); Flags: nowait postinstall

It’s the Check: not CmdLineParamExists('/NOLAUNCH'); that is important. When launched from Windows Explorer, the parameter will not be there, so the checkbox will appear. When launched from the command line without the parameter, since I use the /SILENT and /VERYSILENT parameters, the app is launched automatically. When launched from the command line with the /NOLAUNCH parameter, the install just ends.

I’ve used /NOSETUPCHECK here as well, so that when my app launches my installer, it does NOT perform mutex checking. Without this, the installer would immediately terminate because my app were still running for another moment. This is another custom parameter and not needed if you’re not using mutex checking.

My full Inno script can be seen at Beacon/Setup.iss at master · thommcgrath/Beacon · GitHub

Also, if you don’t need the ability to control wether or not it starts your app when finished, then this is much simpler. The Run command in the script will launch your app automatically if run silently. I wanted the ability to not do this, as my normal updates happen silently as the user quits my app.

Well, I thought I call this method right before I start the downloaded executable with the setup and only then. So it will be restarted and everything is fine. So I changed it

Var lpwzCommandLine As String = App.ExecutableFile.NativePath
Var ldwFlags as UInt32 = 11

Declare Sub RegisterApplicationRestart Lib "kernel32.dll" (byRef lpwzCommandLine As CString, ldwFlags As UInt32) 

RegisterApplicationRestart(lpwzCommandLine, ldwFlags)

but I get the compile error "too many arguments, got 2 expected only 0…

That is an interesting approach… seams to be a lot easier…

I will try that…

When removing the byRef the compile error is gone and the method can be called…

So to document the declare so far…

Var lpwzCommandLine As String = App.ExecutableFile.NativePath
Var ldwFlags as UInt32 = 11

Declare Sub RegisterApplicationRestart Lib "kernel32.dll" (lpwzCommandLine As CString, ldwFlags As UInt32) 

RegisterApplicationRestart(lpwzCommandLine, ldwFlags)

I will update this thread after the tests and see which way works…

Honestly, as long as you call the Unregister method in App.Closing, you could probably always call this in App.Opening and if a user were to download the updater separately, it should still work.

As always… Greg your thoughts are great. That is absolutely possible so I will integrate that declare as well…

Thank you so much…

start with tests now…

First things first… thank all of you for your advice and ideas to get this working…

The process steps are:

  1. Register App
  2. Download UpdateFile
  3. Execute Setup
  4. InnoSetup closes the running app
  5. Setup is executed
  6. InnoSetup starts the app again

The innosetup file must contain several settings to get the update process working:

RestartApplications=yes
CloseApplications=yes
CloseApplicationsFilter=*.*

SetupMutex=AppNameSetup
AppMutex=AppName

As you can see you must define a mutex for the app. That is the identifier that innosetup nows that the app is running. You should create the mutex in app.opening event:

Event Opening
  // update settings for innosetup
  // first get the starting ticks to check if the app is already running at least 60 seconds
  // otherwise the windows restart manager did not execute the restart of the app   
  StartTicks = System.Ticks
  // create the mutex for innosetup. The mutex only must exist, locking is not required
  mMutex = New Mutex(App.ExecutableFile.NameWithoutExtension)
  //register the app for restarts
  RegisterApplicationRestart
End Event

The method RegisterApplicationRestart calls the declare.

Function RegisterApplicationRestart
  #if TargetWindows
    // The commandline contains parameters for the app to use at restart. 
    // I do not need any parameters but it must not be empty
    Var lpwzCommandLine As String = "dummy"
    // The flags control when the windows restart manager starts the app again
    // possible values: (to combine settings add them)
    // 1    RESTART_NO_CRASH    Do not restart the process if it terminates due to an unhandled exception.
    // 2    RESTART_NO_HANG     Do not restart the process if it terminates due to the application not responding.
    // 4    RESTART_NO_PATCH    Do not restart the process if it terminates due to the installation of an update.
    // 8    RESTART_NO_REBOOT   Do not restart the process if the computer is restarted as the result of an update.
    // So restart on update only is 8 + 2 + 1 = 11
    Var ldwFlags as UInt32 = 11
  
    Declare Function RegisterApplicationRestart Lib "kernel32" (lpwzCommandLine As CString, ldwFlags As UInt32) As UInt32
  
    Var lResult As UInt32 = RegisterApplicationRestart(lpwzCommandLine, ldwFlags)
  
  #endif
End Function

The method UnregisterApplicationRestart is called in App.Closing event:

Function UnregisterApplicationRestart
  #if TargetWindows
    
    Declare Sub UnRegisterApplicationRestart Lib "kernel32" 
    
    UnRegisterApplicationRestart()
    
  #endif
End Function

The update process is started in a method after

  • checking if there is an update and
  • if the update may be downloaded and
  • if the minimum os version is ok
  • the setup file is downloaded

Then I check if the app is running at least 60 seconds and wait until the time is reached.

#If TargetWindows
  // Check if we have to wait a little bit, because the windows restart manager only restarts apps when they were running at least 60 seconds
  // I have to do this because my update process runs when the app starts.
  Var lTicksElapsed As Integer
  Do
    lTicksElapsed = system.Ticks - StartTicks
    Thread.YieldToNext
  Loop Until lTicksElapsed / 60 / 60 > 1
  // run the setup 
  pfile.Open
  
#endif

So that is all to do and now it works…
Thanks again to @Greg_O and @Thom_McGrath for their advice and support…

2 Likes