11

I've got a bit of a pickle with Inno Setup: on a user machine, my installer was running slowly (something I've yet to diagnose, might be a problem specific with that computer, I still don't know). This lead to said user to run the installer again, while the first instance was still executing - and to my surprise, they both seemed to be running for a time, before crashing and burning...

I searched around but have not found any way to disable this behavior - most of my queries wound up on Inno Setup mutex feature, which is not really what I'm looking for. Anyone got tips on how to make sure there is only one instance / process of the installer executing? Thank you!

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Takeshi
  • 150
  • 1
  • 10
  • 3
    I'm not aware of any directive that would allow only one setup instance (I assume per `AppId`). Pity that the `CreateMutex` does not return anything useful; here's [`a workaround`](http://pastebin.com/sGcrC3pY) for it. But it would be a good built-in feature. – TLama Feb 20 '15 at 12:44

2 Answers2

19

Since Inno Setup 5.5.6 you can use the SetupMutex directive:

[Setup]
AppId=MyProgram
SetupMutex=SetupMutex{#SetupSetting("AppId")}

If you want to change a text of the message, that displays when another installer is running already, use:

[Messages]
SetupAppRunningError=Setup has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit.

Before this version, there was no built-in mechanism available. But you could write your own pretty simply. Principle is that you create a unique mutex when the setup starts. But, as first you check if there is no such mutex already created. If so, you exit the setup, if not, you create the mutex:

[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Code]
const
  // this needs to be system-wide unique name of the mutex (up to MAX_PATH long),
  // there is a discussion on this topic http://stackoverflow.com/q/464253/960757
  // you can expand here e.g. the AppId directive and add it some 'salt'
  MySetupMutex = 'My Program Setup 2336BF63-DF20-445F-AAE6-70FD7E2CE1CF';

function InitializeSetup: Boolean;
begin
  // allow the setup to run only if there is no thread owning our mutex (in other
  // words it means, there's no other instance of this process running), so allow
  // the setup if there is no such mutex (there is no other instance)
  Result := not CheckForMutexes(MySetupMutex);
  // if this is the only instance of the setup, create our mutex
  if Result then
    CreateMutex(MySetupMutex)
  // otherwise tell the user the setup will exit
  else
    MsgBox('Another instance is running. Setup will exit.', mbError, MB_OK);
end;
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
TLama
  • 75,147
  • 17
  • 214
  • 392
  • Thanks for your time and help TLama, it's appreciated. I've read that the mutex approch isn't 100% unfailable regarding racing conditions - though it does seem like the best option. I'll keep track of the proposal you linked in the other answer; I think something like this should've been implemented years ago, right? Thanks again! – Takeshi Feb 24 '15 at 16:04
  • Race conditions are usually related to threads inside a process. This is race between processes. But yes, the risk is there, but very, very small. The user would have to run the second instance exactly before the first instance creates the mutex but after it checked the mutex existence (so it would have to be in between the `CheckForMutexes` and `CreateMutex` calls, which is at most time in milliseconds). Besides, people use mutexes for checking if their applications already runs; it's a common practice (I don't know about any atomic function that could avoid this race condition). – TLama Feb 24 '15 at 16:17
  • I've just been made aware of [this](http://www.codeproject.com/Articles/538/Avoiding-Multiple-Instances-of-an-Application). Now I know it's a long shot, but I've heard cases where the support area has gotten calls from clients with multiple instances of our software running (it uses the mutex technique), so I know it happens. – Takeshi Feb 24 '15 at 16:28
0

If your installer was called setup.exe for example, then you could use the following code to check if setup.exe is running and terminate the install.

[Code]
function IsAppRunning(const FileName : string): Boolean;
var
    FSWbemLocator: Variant;
    FWMIService   : Variant;
    FWbemObjectSet: Variant;
begin
    Result := false;
    FSWbemLocator := CreateOleObject('WBEMScripting.SWBEMLocator');
    FWMIService := FSWbemLocator.ConnectServer('', 'root\CIMV2', '', '');
    FWbemObjectSet := FWMIService.ExecQuery(Format('SELECT Name FROM Win32_Process Where Name="%s"',[FileName]));
    Result := (FWbemObjectSet.Count > 0);
    FWbemObjectSet := Unassigned;
    FWMIService := Unassigned;
    FSWbemLocator := Unassigned;
end;

function InitializeSetup: boolean;
begin
  result := not IsAppRunning('setup.exe');
  if not result then
    MsgBox('setup.exe is already running', mbError, MB_OK);
end;
TLama
  • 75,147
  • 17
  • 214
  • 392
Andrew Seaford
  • 645
  • 6
  • 13
  • 2
    This is not reliable at all. There might be running totally different `setup.exe` process and that's not the reason to terminate your setup. – TLama Feb 24 '15 at 07:21
  • 1
    But this would be quite unlikely. In order to avoid this name your setup like `MyApplication_Setup_Ver_1.2.3.4.exe`. In my opinion this is more user-friendly anyway and does not entrap the user to rename the `setup.exe` to something of his choice. – Wernfried Domscheit Feb 24 '15 at 07:31
  • 1
    I only used the name setup.exe to simplify the example code. I agree with Wernfried. In product code the setup file name should contain the product name and version number. I normally set the installer name using OutputBaseFilename=Setup{#MyAppName}{#MyAppVersion} – Andrew Seaford Feb 24 '15 at 08:48
  • 2
    @Wernfried, Andrew, true, but then you are limiting yourself. And it is still unsafe. Some, not so smart people will rename the setup file and then call you they cannot run your setup. And I bet that after a few such support calls you'd change your mind :) Easier, and much more reliable is the use of mutex objects (see the other answer here). Btw. I've made [`this proposal`](http://news.jrsoftware.org/read/article.php?id=101727&group=jrsoftware.innosetup#101727) if you'd like to discuss, feel free to join. – TLama Feb 24 '15 at 08:54