Check if a process is running or not on Windows?
Asked Answered
C

22

76

I am trying to create a python script which I will later run as a service. Now I want to run a particular part of the code only when iTunes is running. I understand from some research that polling the entire command list and then searching for the application for that list is expensive.

I found out that processes on UNIX-based operating systems create a lock file to notify that a program is currently running, at which point we can use os.stat(location_of_file) to check if the file exists to determine if a program is running or not.

Is there a similar lock file created on Windows?

If not what are the various ways in Python by which we can determine if a process is running or not?

I am using python 2.7 and iTunes COM interface.

Choreographer answered 16/10, 2011 at 20:33 Comment(3)
What does the COM interface do if iTunes isn't running?Pannonia
If make an object using the COM interface in python, the COM interface automatically opens up iTunes.Choreographer
For what it's worth, it's up to an individual program whether or not it wants to create a lock file or PID file. Not all Linux/UNIX programs do.Weis
T
109

You can not rely on lock files in Linux or Windows. I would just bite the bullet and iterate through all the running programs. I really do not believe it will be as "expensive" as you think. psutil is an excellent cross-platform python module cable of enumerating all the running programs on a system.

import psutil    
"someProgram" in (p.name() for p in psutil.process_iter())
Terina answered 17/10, 2011 at 1:54 Comment(10)
Upon trying out this program, access is denied for some processes even when I run it as an administrator. I will probably just use try and except to ignore these instances, but it is something to watch out forCalida
Appears to be BSD nowRuberta
Warning: this causes a psutil.NoSuchProcess exception if a process that psutil.get_pid_list() returned has already exited when psutil.Process(i).name is executed. Be sure to catch this.Postdoctoral
Beware of the case. The result is case sensitive.Decury
In the tests I've run, this method is just over 10x faster than a subprocess call to tasklist (for Windows).Iberia
For additional speed-up, specify psutil.process_iter(attrs=['name']) to only obtain the name attribute, which will be faster (marginally). psutil.readthedocs.io/en/latest/#psutil.process_iterProgrammer
@Postdoctoral This answer doesn't use psutil.get_pid_list. psutil.process_iter is safe from this race condition based on the docs.Programmer
@ChrisCollett, this also avoids the NoSuchProcess issue that @Postdoctoral mentions, which is more annoying to workaround so a better reason to use your attrs=['name'] approachChromite
This works well to detect that "python" is running. But I get about a dozen such processes. Can I also find out, which script each python process is running?Decency
@Decency Yes, this information can be found in the "cmdline" attribute.Veinlet
S
30

Although @zeller said it already here is an example how to use tasklist. As I was just looking for vanilla python alternatives...

import subprocess

def process_exists(process_name):
    call = 'TASKLIST', '/FI', 'imagename eq %s' % process_name
    # use buildin check_output right away
    output = subprocess.check_output(call).decode()
    # check in last line for process name
    last_line = output.strip().split('\r\n')[-1]
    # because Fail message could be translated
    return last_line.lower().startswith(process_name.lower())

and now you can do:

>>> process_exists('eclipse.exe')
True

>>> process_exists('AJKGVSJGSCSeclipse.exe')
False

To avoid calling this multiple times and have an overview of all the processes this way you could do something like:

# get info dict about all running processes
import subprocess
output = subprocess.check_output(('TASKLIST', '/FO', 'CSV')).decode()
# get rid of extra " and split into lines
output = output.replace('"', '').split('\r\n')
keys = output[0].split(',')
proc_list = [i.split(',') for i in output[1:] if i]
# make dict with proc names as keys and dicts with the extra nfo as values
proc_dict = dict((i[0], dict(zip(keys[1:], i[1:]))) for i in proc_list)
for name, values in sorted(proc_dict.items(), key=lambda x: x[0].lower()):
    print('%s: %s' % (name, values))
Suttles answered 26/3, 2015 at 9:50 Comment(6)
check_output was introduced in python 2.7 so won't work for < 2.7.Cowart
Is that really a problem for you? 2.7 is around since 2010 😐 and its going to be deprecated soon pythonclock.orgSuttles
It's just for info. And yes in my case it is a problem, because we have legacy code in python 2.6.Cowart
@May.D thanks for the edit! But I'd rather keep the lower() just at the right spot! Sure it was ineffective before! 👍Suttles
To work in Python 3, use output = subprocess.check_output(call).decode().Wore
thanks. @martineau. I fixed both snippets. Works in py 2 & 3 now the same way 👍Suttles
C
10

win32ui.FindWindow(classname, None) returns a window handle if any window with the given class name is found. It raises window32ui.error otherwise.

import win32ui

def WindowExists(classname):
    try:
        win32ui.FindWindow(classname, None)
    except win32ui.error:
        return False
    else:
        return True

if WindowExists("DropboxTrayIcon"):
    print "Dropbox is running, sir."
else:
    print "Dropbox is running..... not."

I found that the window class name for the Dropbox tray icon was DropboxTrayIcon using Autohotkey Window Spy.

See also

MSDN FindWindow

Cariotta answered 20/8, 2012 at 16:17 Comment(2)
Thanks, I really like this method. My only objection is that I could not find the class name for my application, even with a program like AHK Window Spy. I ended up using WMIC import subprocess cmd = 'WMIC PROCESS get Caption,Commandline,Processid' proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) for line in proc.stdout: print lineTatouay
You can get it without subprocess --> procList = wmi.WMI ().Win32_Process () print "\n".join (proc.Caption for proc in procList)Levantine
T
8

Try this code:

import subprocess
def process_exists(process_name):
    progs = str(subprocess.check_output('tasklist'))
    if process_name in progs:
        return True
    else:
        return False

And to check if the process is running:

if process_exists('example.exe'):
    #do something
Transport answered 6/11, 2020 at 2:7 Comment(0)
P
7

Lock files are generally not used on Windows (and rarely on Unix). Typically when a Windows program wants to see if another instance of itself is already running, it will call FindWindow with a known title or class name.

def iTunesRunning():
    import win32ui
    # may need FindWindow("iTunes", None) or FindWindow(None, "iTunes")
    # or something similar
    if FindWindow("iTunes", "iTunes"):
        print "Found an iTunes window"
        return True
Pannonia answered 16/10, 2011 at 21:9 Comment(9)
This might work for iTunes, but what about processes that can run as a headless instance for example Excel. This approach will not work for those applications.Qnp
I think the question was quite specific about wanting to check for iTunes.Harmonious
@anijhaw: Are you suggesting that Excel will be running without a window, or that FindWindow won't find Excel's hidden window?Pannonia
Thanks win32ui.FindWindow('iTunes,'iTunes') will do the work (Y)Choreographer
Yes excel can run a headless instance without a windowQnp
@anijhaw: Just because the window isn't visible, that doesn't mean it doesn't exist. When Excel is running and you don't see its window, the window is still there.Pannonia
I am not a 100% sure but I will definitely try it.Qnp
@anijhaw: Look for a window with class XLMAIN.Pannonia
win32ui.FindWindow doesn't return a falsy value when no window is found. Instead it raises an error. Also, if a seemingly headless program has a tray icon, you can still test for the tray icon. I demonstrate both points in my answerCariotta
A
7

I'd like to add this solution to the list, for historical purposes. It allows you to find out based on .exe instead of window title, and also returns memory used & PID.

processes = subprocess.Popen('tasklist', stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE).communicate()[0]
# Put a regex for exact matches, or a simple 'in' for naive matches

A slice of example output:

notepad.exe                  13944 Console                    1     11,920 K
python.exe                    5240 Console                    1     28,616 K
conhost.exe                   9796 Console                    1      7,812 K
svchost.exe                   1052 Services                   0     18,524 K
iTunes.exe                    1108 Console                    1    157,764 K
Approachable answered 31/12, 2016 at 16:17 Comment(0)
M
4
import psutil

for p in psutil.process_iter(attrs=['pid', 'name']):
    if "itunes.exe" in (p.info['name']).lower():
        print("yes", (p.info['name']).lower())

for python 3.7


import psutil

for p in psutil.process_iter(attrs=['pid', 'name']):
    if p.info['name'] == "itunes.exe":
        print("yes", (p.info['name']))

This works for python 3.8 & psutil 5.7.0, windows

Melly answered 30/8, 2019 at 0:33 Comment(0)
E
3

Psutil suggested by Mark, is really the best solution, its only drawback is the GPL compatible license. If that's a problem, then you can invoke Windows' process info commands: wmic process where WMI is available (XP pro, vista, win7) or tasklist. Here is a description to do it: How to call an external program in python and retrieve the output and return code? (not the only possible way...)

Energid answered 4/9, 2012 at 11:21 Comment(1)
Just a warning: tasklist truncates the name of the process on long names. For example, it truncates exe here: vmware-usbarbitrator64.ex 2076 Services 0 9,348 K. Running wmic process does not have this problem.Blais
P
3

According to the ewerybody post: https://mcmap.net/q/265775/-check-if-a-process-is-running-or-not-on-windows

Multiple problems can arise:

  • Multiple processes with the same name
  • Name of the long process

The 'ewerybody's' code will not work if the process name is long. So there is a problem with this line:

last_line.lower().startswith(process_name.lower())

Because last_line will be shorter than the process name.

So if you just want to know if a process/processes is/are active:

from subprocess import check_output

def process_exists(process_name):
    call = 'TASKLIST', '/FI', 'imagename eq %s' % process_name
    if check_output(call).splitlines()[3:]:
        return True

Instead for all the information of a process/processes

from subprocess import check_output

def process_exists(process_name):
    call = 'TASKLIST', '/FI', 'imagename eq %s' % process_name
    processes = []
    for process in check_output(call).splitlines()[3:]:
        process = process.decode()
        processes.append(process.split())
    return processes
Pylorectomy answered 29/5, 2020 at 11:6 Comment(1)
This is great. I'll also throw in the recommendation to use subprocess.run as it's the newer, more succinct and more readable way to call subprocesses since Python 3.5. Docs refer to call, check_call and check_output as the older API, albeit without deprecating them yet. This answer does a good job summarizing run.Snapp
H
2

Would you be happy with your Python command running another program to get the info?

If so, I'd suggest you have a look at PsList and all its options. For example, The following would tell you about any running iTunes process

PsList itunes

If you can work out how to interpret the results, this should hopefully get you going.

Edit:

When I'm not running iTunes, I get the following:

pslist v1.29 - Sysinternals PsList
Copyright (C) 2000-2009 Mark Russinovich
Sysinternals

Process information for CLARESPC:

Name                Pid Pri Thd  Hnd   Priv        CPU Time    Elapsed Time
iTunesHelper       3784   8  10  229   3164     0:00:00.046     3:41:05.053

With itunes running, I get this one extra line:

iTunes              928   8  24  813 106168     0:00:08.734     0:02:08.672

However, the following command prints out info only about the iTunes program itself, i.e. with the -e argument:

pslist -e itunes
Harmonious answered 16/10, 2011 at 20:41 Comment(5)
I guess this would be equivalent to - os.popen('query process') and reading the lines of output and then searching for iTuens. For I actually want is to make the method simpler. as in os.stat(file). As I intend to keep the script running all the time.Choreographer
Well, you could always just query it periodically, e.g. once a second, depending on how frequently you need to check.Harmonious
I guess this is one solution that will work. Still hoping that someone might be able to shed some light on whether or not lock files are created by programs in windows. ThanksChoreographer
OK, I've just added another answer, with info to help you try and track that down yourself.Harmonious
That answer described using Process Monitor to track what files iTunes created at start-up, to see if there were any indicator files that were created.Harmonious
P
2

If can't rely on the process name like python scripts which will always have python.exe as process name. If found this method very handy

import psutil
psutil.pid_exists(pid)

check docs for further info http://psutil.readthedocs.io/en/latest/#psutil.pid_exists

Pictish answered 17/12, 2017 at 16:41 Comment(0)
P
2

There is a python module called wmi.

import wmi
c=wmi.WMI()
def check_process_running(str_):
    if(c.Win32_Process(name=str_)):
        print("Process is running")
    else:
        print("Process is not running")

         
check_process_running("yourprocess.exe")  
Provencal answered 9/9, 2020 at 3:48 Comment(0)
A
1

This method below can be used to detect whether the process [ eg: notepad.exe ] is runing or not.

from pymem import Pymem
import pymem

while (True):

    try:

        pm = Pymem('notepad.exe')
        print('Notepad Started And Is Running....')

    except:

        print ('Notepad Is Not Running....')

Pymem Package Is Needed. To Install It,

pip install pymem
Asthenia answered 16/2, 2021 at 8:59 Comment(0)
M
1

I liked the solution of @ewerybody with this little change

import subprocess

def process_exists(process_name):
    call = 'TASKLIST', '/FI', 'imagename eq %s' % process_name
    # use buildin check_output right away
    output = subprocess.check_output(call).decode()

    # check in last line for process name
    last_line = output.split('\r\n')
    
    #first result is 3 because the headers
    #or in case more than one, you can use the last one using [-2] index
    data = " ".join(last_line[3].split()).split()  

    #return a list with the name and pid 
    return( [data[0], data[1]] )  
Mastat answered 13/2, 2022 at 6:25 Comment(0)
M
0

This works nicely

def running():
    n=0# number of instances of the program running 
    prog=[line.split() for line in subprocess.check_output("tasklist").splitlines()]
    [prog.pop(e) for e in [0,1,2]] #useless 
    for task in prog:
        if task[0]=="itunes.exe":
            n=n+1
    if n>0:
        return True
    else:
        return False
Mimosaceous answered 13/4, 2016 at 21:55 Comment(0)
M
0

If you are testing application with Behave you can use pywinauto. Similar with previously comment, you can use this function:

def check_if_app_is_running(context, processName):
try:
    context.controller = pywinauto.Application(backend='uia').connect(best_match = processName, timeout = 5)
    context.controller.top_window().set_focus()
    return True
except pywinauto.application.ProcessNotFoundError:
    pass
return False

backend can be 'uia' or 'win32'

timeout if for force reconnect with the applicaction during 5 seconds.

Minutely answered 11/9, 2019 at 14:34 Comment(0)
J
0
import subprocess as sp
for v in str(sp.check_output('powershell "gps | where {$_.MainWindowTitle}"')).split(' '):
    if len(v) is not 0 and '-' not in v and '\\r\\' not in v and 'iTunes' in v: print('Found !')
Justino answered 16/10, 2019 at 16:6 Comment(0)
F
0
import psutil

def check_process_status(process_name):
    """
    Return status of process based on process name.
    """
    process_status = [ proc.status() for proc in psutil.process_iter() if proc.name() == process_name ]
    if process_status:
        print("Process name %s and staus %s"%(process_name, process_status[0]))
    else:
        print("Process name not valid", process_name)
Funderburk answered 24/4, 2020 at 12:43 Comment(0)
P
0

Psutil is the best solution for this.

import psutil

processes = list(p.name() for p in psutil.process_iter())
# print(processes)
count = processes.count("<app_name>.exe")

if count == 1:
    logging.info('Application started')
    # print('Application started')
else:
    logging.info('Process is already running!')
    # print('Process is already running!')
    sys.exit(0)                          # Stops duplicate instance from running
Pittel answered 9/2, 2021 at 12:21 Comment(0)
T
0

You can just use os.kill sending a 0 signal (that doesn't kill the process) and checking for errors.

from os import kill

def check_if_running(pid):
    try:
        kill(pid, 0)
    except:
        return False
    return True
Taproom answered 3/7, 2021 at 17:37 Comment(0)
D
0
if tasklist.find("chrome.exe") > 0:
    os.system("taskkill /im chrome.exe")  # kill if it is running.
Deranged answered 10/4, 2023 at 8:54 Comment(0)
W
0

I found psutil very slow. A much more performant solution:

import win32gui
window_titles = set()
def winEnumHandler( hwnd, ctx ):
    if win32gui.IsWindowVisible( hwnd ):
        window_titles.add(win32gui.GetWindowText( hwnd ) )
win32gui.EnumWindows( winEnumHandler, None )
print(window_titles)
Weakling answered 15/1 at 23:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.