Inno Setup - prevent executing the installer multi

2019-03-19 16:14发布

问题:

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!

回答1:

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;


回答2:

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;


标签: inno-setup