-->

How to determine with certainty if an appliction i

2019-06-01 01:12发布

问题:

I have an install script with Pascal code to determine if the app to be installed is currently running:

; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

[Setup]
AppName=MyApp
AppVerName=MyApp v1.0
DiskSpanning=no
AppPublisher=me
AppPublisherURL=http://www.example.com
AppSupportURL=http://www.example.com
AppUpdatesURL=http://www.example.com
DefaultDirName={pf}\MyApp
UsePreviousAppDir=yes
DefaultGroupName=MyApp
OutputBaseFilename=Setup
OutputDir=.\MyAppSetup
MinVersion=5.0

[Tasks]
Name: desktopicon; Description: Create a &desktop icon; GroupDescription: Additional icons:; MinVersion: 4,4

[Files]
Source: .\Release\MyApp.exe; DestDir: {app}; Flags: ignoreversion

[Icons]
Name: {group}\EasyCash&Tax; Filename: {app}\MyApp.exe
Name: {userdesktop}\EasyCash&Tax; Filename: {app}\MyApp.exe; MinVersion: 4,4; Tasks: desktopicon

[Run]
Filename: {app}\MyApp.exe; Description: Launch MyApp; Flags: nowait postinstall skipifsilent

[Code]

function CheckProcessRunning( aProcName,
                              aProcDesc: string ): boolean;
var
  ShellResult: boolean;
  ResultCode: integer;
  cmd: string;
  sl: TStringList;
  f: string;
  d: string;
begin
  cmd := 'for /f "delims=," %%i ' + 
         'in (''tasklist /FI "IMAGENAME eq ' + aProcName + '" /FO CSV'') ' + 
         'do if "%%~i"=="' + aProcName + '" exit 1'; 
  f := 'CheckProc.cmd';
  d := AddBackSlash( ExpandConstant( '{tmp}' ));
  sl := TStringList.Create;
  sl.Add( cmd );
  sl.Add( 'exit /0' );
  sl.SaveToFile( d + f );
  sl.Free;
  Result := true;
  while ( Result ) do
  begin
    ResultCode := 1;
    ShellResult := Exec( f,
                         '',
                         d, 
                         SW_HIDE, 
                         ewWaitUntilTerminated, 
                         ResultCode );
    Result := ResultCode > 0;
    if Result and 
       ( MsgBox( aProcDesc + ' is active and must be closed to proceed', 
                 mbConfirmation, 
                 MB_OKCANCEL ) <> IDOK ) then
      Break;
  end;
  DeleteFile( d + f );
end;

// Perform some initializations.  Return False to abort setup
function InitializeSetup: Boolean;
begin
  // Do not use any user defined vars in here such as {app}
  Result := not ( CheckProcessRunning( 'MyApp.exe',      'MyApp' ));
end;


function InitializeUninstall: Boolean;
begin
  Result := not ( CheckProcessRunning( 'MyApp.exe',      'MyApp' ));
end;

This works for 99% of the cases but every now and then users report a false positive and are unable to proceed with installation.

Users report that in command line tasklist /FI "IMAGENAME eq MyApp.exe" /FO CSV (which is used by the Pascal script) is returning nothing.

Is there an error in the script that may give false positives or is there a better way to determine if the app is running than tasklist?

回答1:

Is there an error in the script that may give false positives?

No error.

Are you aware, that tasklist might not be available? Think of "XP Home" (yes, it's fading out), but still in use and your solution will not work there, because tasklist is simply not available.

Or is there a better way to determine if the app is running than 'tasklist'?

Yes, there are some other and maybe more reliable ways to do this. For instance, it's quite common to include psvince in the installer and use it for process detection. Quite nice is also the WMI based solution.

Here are some approaches for "process detection" with InnoSetup:

  • AppMutex - http://www.jrsoftware.org/ishelp/index.php?topic=setup_appmutex
  • PSVince http://www.vincenzo.net/isxkb/index.php?title=PSVince
  • PSVince Fork https://github.com/XhmikosR/psvince
  • without external DLL https://raw.githubusercontent.com/git-for-windows/build-extra/master/installer/modules.inc.iss
  • WMI + Win32_Process https://stackoverflow.com/a/9950718/1163786 + https://stackoverflow.com/a/25518046/1163786
  • ProcessViewer https://github.com/lextm/processviewer