16

I've read the following post. My Code looks exactly the same, but does not work:
Inno Setup Checking for running process

I copied the example from http://www.vincenzo.net/isxkb/index.php?title=PSVince

But the example doesn't work either, even if I change the code like this:

[Code]
function IsModuleLoaded(modulename: AnsiString):  Boolean;
external 'IsModuleLoaded@files:psvince.dll stdcall';

The code always returns false (the program is not running, even it is running). Tested at Windows 2008 R2 and Windows 7.

In fact I want to check, if the tomcat5.exe is running or not. So I think I can't work with a AppMutex.

I have also seen https://code.google.com/p/psvince/source/detail?r=5
But I can't find any facts about compatibility of that DLL.

Complete code:

[Files]
Source: psvince.dll; Flags: dontcopy

[Code]
function IsModuleLoaded(modulename: AnsiString ):  Boolean;
external 'IsModuleLoaded@files:psvince.dll stdcall';

function InitializeSetup(): Boolean;
begin
  if(IsModuleLoaded( 'notepad.exe' )) then
    begin
      MsgBox('Running', mbInformation, MB_OK);
      Result := false;
    end
  else
    begin
      MsgBox('Not running', mbInformation, MB_OK);
      Result := true;
    end
end;
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Christian Kuetbach
  • 15,850
  • 5
  • 43
  • 79
  • 1
    Also asked on the [Inno Setup news groups](http://news.jrsoftware.org/read/article.php?id=95589&group=jrsoftware.innosetup#95589). – Deanna Mar 30 '12 at 14:19
  • Yes, thats right. Thanks for your usenet-reply. I had already seen the r5-commit of psvince, but I couldn't find facts about compatibility. – Christian Kuetbach Mar 30 '12 at 14:55
  • Deanna I tried the Bugfix from r5-commit of psvince. In fact make a 'IsModuleLoaded("app.exe") or IsModuleLoaded2("app.exe")' and it seems to work. if you would post it as answer, I'll accept it. – Christian Kuetbach Apr 02 '12 at 08:56

5 Answers5

57

You can use the WMI and the Win32_Process.

Try adding this function to your Inno Setup script.

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;
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
RRUZ
  • 134,889
  • 20
  • 356
  • 483
  • Yes, it worked for me! It works also in multi user scenario (like when running an installer on a server where more users are logged in using RDP) - no need to "run as administrator" in this case! – UnDiUdin Aug 27 '13 at 09:33
  • To use the code posted by RRUZ add a code section to the installer script. Add a function called InitializeSetup which calls IsAppRunning("appname.exe"). The InitializeSetup will be called when the installer starts. Check out my website for an example of how to use this code http://www.andrew-seaford.co.uk/check-program-running-installing-inno/ – Andrew Seaford Feb 23 '15 at 21:53
  • You made my day! Thanks :) – Jay Patel Oct 10 '18 at 11:37
  • I am getting a runtime error. An outgoing call cannot be made since the application is dispatching an input-synchronous call. In some devices. – cool_php Sep 03 '20 at 04:29
  • This approach has been working for many years, but today I received a bug report: `SWbemLocator: The specified service does notexist as an installed service` – Edwin Yip Oct 27 '22 at 09:30
9

I don't have enough rep points to add a comment to RRUZ's excellent answer, so I'll just add this here. Make sure you catch exceptions, otherwise the installer will fail for users who can't access the service.

try
      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);
except
end;
Jedao
  • 155
  • 2
  • 3
  • 1
    Swallowing exceptions is not a good practice since you won't know why any of the function calls failed. For instance I almost always let the exceptions to be thrown keeping on their caller handle them. – TLama Aug 27 '14 at 07:03
  • 1
    Of course, it's up to the developer to catch the exception and act accordingly. I was just pointing out the fact that those methods can fail, which will lead to the installer exiting without doing its job. – Jedao Aug 28 '14 at 02:34
2

There's an even simpler solution to this; using the code suggested by RRUZ depends on you knowing the install path, which if you run when the installer initialises, you don't know this.

The best solution is to use FindWindowByClassName. It does have a slight prerequisite that you have a main form that's always open, but you can always run multiple checks if you have a variety of forms that could be open. It also goes without saying that you need to make the classname as unique as possible!

Example function:

function IsAppRunning(): Boolean;
begin                                                                
  Result := (FindWindowByClassName( '{#AppWndClassName}') <> 0) or (FindWindowByClassName( '{#AltAppWndClassName}') <> 0);
end;

The # precompile references are defined earlier up the install script...

#define AppWndClassName "TMySplashScreen"
#define AltAppWndClassName "TMyMainForm"

Then in the code section, you call it as follows:

function InitializeUninstall(): Boolean;
begin
  // check if application is running
  if IsAppRunning() then
  begin
    MsgBox( 'An Instance of MyFantasticApp is already running. - Please close it and run the uninstall again.', mbError, MB_OK );
    Result := false;
  end
  else 
    Result := true;
End;

If you need anything more complex than this then you need to look into mutexes, but the beauty with the above code is that its simple, quick and as long as you have reasonably unique classnames, as good as anything else.

(Although admittedly if you're running on a multi-user system, then this probably won't find the window if its in another user's session. But as I said, for the majority of simple situations, this would be fine.)

Steve Childs
  • 1,832
  • 2
  • 20
  • 26
  • I think OP cannot use mutexes here since `tomcat5.exe` doesn't sound like a home brewn application. But if there would be the way to extend the application, mutexes are the best bet! In InnoSetup you could then use [`CheckForMutexes`](http://www.jrsoftware.org/ishelp/index.php?topic=isxfunc_checkformutexes), so it would be even simpler than your code. [+1] – TLama Sep 06 '13 at 13:58
1

A simple solution could be to try to delete the exe file. I assume that you are going to replace or uninstall it anyway. If the file exists and deleting it fails then it is probably running.

logicnet.dk
  • 193
  • 1
  • 7
1

Unfortunately psvince.dll cannot query 64 bit running processes based on my observation, and as I am not its developer, I don't know how to fix it to work on Windows x64.

My workaround is to use a home-cooked command line utility, processviewer.exe,

http://github.com/lextm/processviewer

This has been tested on Windows 7 x64 in Touch Mouse Mate

http://www.lextm.com/2012/03/new-inno-setup-installer-script-samples-version-compare-running-processes/

Lex Li
  • 60,503
  • 9
  • 116
  • 147
  • Thanks, I'll test it. But the installer and the process are 32bit. Just the operating system is 64bit. – Christian Kuetbach Mar 30 '12 at 11:52
  • Is it possible to embed the code directly to the installer (without deploying another executable)? – Christian Kuetbach Mar 30 '12 at 13:11
  • It depends on a not-so-simple unit, https://github.com/lextm/processviewer/blob/master/uDGProcessList.pas, so I don't think it can be easily ported to Pascal script. The WMI approach posted by @RRUZ may be simpler. – Lex Li Mar 31 '12 at 05:15