Killing Like Task Manager - python

Inside Task Manager [Windows 8+], in the "Processes" tab it lists all the processes currently running. If we open 2 windows of MS Word, it will only appear once, however this is actually a group and can be expanded to be able to see and end both tasks separately.
This is great, however it DOES NOT carry over to the "Details" tab where WINWORD.EXE is listed but only 1 occurrence! And thus only 1 PID! Sharing a PID is an issue because an attempt to close it results in the entire thingbeing closed.
I want to only kill a specific word window, not ALL word windows which has been happening when I try to kill windows programatically (currently i'm using taskkill through an import os in python, any other way to do it without additional modules would be alright as well).
Right now when I run taskkill.... "WordDoc.docx" it kills every open word document which is extremely annoying and potentially data losing. Is there a way to be able to kill "proccesses" like how it is done in task manager?
Thank you
PS I am not using /T so that is not the issue

When closing a single window of a process on the Process tab, Task Manager does not kill the process the window belongs to, but just sends a WM_CLOSE message to that window. You will notice that the Word window is not "killed" as you will still get a prompt to save and unsaved changes in your Word document.
You can do the same as Task Manager using the following code, which enumerates all top-level windows, and then sends WM_CLOSE if the window title matches a desired value:
import win32gui
def enumHandler(hwnd, lParam):
if win32gui.IsWindowVisible(hwnd):
if 'My Word Document' in win32gui.GetWindowText(hwnd):
win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)
win32gui.EnumWindows(enumHandler, None)

Related

Kill secondary task of a given process

I'm trying to kill a secondary task of a process using powershell, batch, python...anything I can save as script and run it remotely. TaskManager picture as following:
I'd like to kill the one with longer title leaving the "SAP Logon 740" open. Every task of the tree have the same PID, so I can't just kill the process.
I guess this is posible, because I can do it manually going to Task MAnager, expanding the process and ending that specific task but everything I've found consist in killing the process, which isn't possible in my case.
I've so far tried with tasklist/taskkill, powershell (Get-Process, Get-Object Win32_Process...) but I haven't been able to find how to.
Here you have the output of TaskList (Status=Running)
Only one of the task (the one which is front) is showing there.
As you have used the powershell tag, and even ran your tasklist command using powerhell.exe, I have decided to provide an examples using it.
If your criteria is to stop the process named saplogon with the longest window title string:
GPs saplogon|Sort{$_.mainWindowTitle.Length}|Select -L 1|SpPs -Wh
If your criteria is to stop all processes named saplogon except for the one with the shortest window title string:
GPs saplogon|Sort{$_.mainWindowTitle.Length}|Select -Skip 1|SpPs -Wh`
If you're happy with the output, you can remove  -Wh, (-WhatIf), to actually perform the task. If needed you could even replace that with the  -F, (-Force) option, if necessary.

How to catch a process in python?

I'm currently making a lil' launcher for PortableMu while in an internship.
We (company and I) modeled a special mode for the Mu-Editor and we are shipping it with PortableMu so that users don't need to install Mu and/or Python to use it.
The problem of PortableMu for Windows is, that you start it with a .bat and this doesnt give you any feedback.
You click, you wait ~1-2min and maybe Mu-Editor will popup.
This is not very userfriendly.
So my duty is to create a launcher.
My launcher is a simple thing: Only lil "welcome" a picture and a button to start PortableMu. It works on my private windows10.
Now I want to add in randomly picked messages for simulating "loading" which shall stop when the Mu-Editor pops up. Simply to bridge the time
Is there a method to catch when this happens?
Alas:
Can Python catch the moment when Windows opens the task/process for Mu-Editor?
If, how?
use the tasklist
subprocess.Popen('tasklist').comunicate()[0] will return all the tasks currently happening in windows, simply do this every minute or so and check for your task. There are ways to make this pass without a command window popping up, here's one that i use often
command =subprocess.Popen(["ping","-n","1","-w","100", str(ip)], stdout=subprocess.PIPE, shell=False, creationflags = 0x08000000)
reply = str(command.communicate()[0])

Python subprocess kill is working for "notepad.exe" but not working for "calc.exe"

OS: Windows 10
Python: 3.5.2
I am trying to open calc.exe do some actions and than close it.
Here is my code sample
import subprocess, os, time
p = subprocess.Popen('calc.exe')
#Some actions
time.sleep(2)
p.kill()
So this is not working for calc.exe, it just opens the calculator, but does not close it, But same code is working fine for "notepad.exe".
I am guessing that there is a bug in subprocess lib for process kill method. so the notepad.exe process name in task manager is notepad.exe, but the calc.exe process name is calculator.exe, so I am guessing it is trying to kill by name and do not find it.
There's no bug in subprocess.kill. If you're really worried about that, just check the source, which is linked from the docs. The kill method just calls send_signal, which just calls os.kill unless the process is already done, and you can see the Windows implementation for that function. In short: subprocess.Process.kill doesn't care what name the process has in the kernel's process table (or the Task Manager); it remembers the PID (process ID) of the process it started, and kills it that way.
The most likely problem is that, like many Windows apps, calc.exe has some special "single instance" code: when you launch it, if there's already a copy of calc.exe running in your session, it just tells that copy to come to the foreground (and open a window, if it doesn't have one), and then exits. So, by the time you try to kill it 2 seconds later, the process has already exited.
And if the actual running process is calculator.exe, that means calc.exe is just a launcher for the real program, so it always tells calculator.exe to come to the foreground, launching it if necessary, and then exits.
So, how can you kill the new calculator you started? Well, you can't, because you didn't start a new one. You can kill all calc.exe and/or calculator.exe processes (the easiest way to do this is with a third-party library like psutil—see the examples on filtering and then kill the process once you've found it), but that will kill any existing calculator process you had open before running your program, not just the new one you started. Since calc.exe makes it impossible to tell if you've started a new process or not, there's really no way around that.
This is one way to kill it, but it will close every open calculator.
It calls a no window command prompt and gives the command to close the Calculator.exe process.
import subprocess, os, time
p = subprocess.Popen('calc.exe')
print(p)
#Some actions
time.sleep(2)
CREATE_NO_WINDOW = 0x08000000
subprocess.call('taskkill /F /IM Calculator.exe', creationflags=CREATE_NO_WINDOW)

Close console while process is running

I'm writing a small application that uses an "index-file" to open folders in explorer from just a few button presses. Anyway I would like to update that index file in a "background process" every time the applications shuts down. Updating the index file means scanning through our network and for some remote users it could take a few minutes. That's why I would like it to hide the console during the scanning process in order to avoid the process being aborted by user.
I tried several things similar to:
#these are just dummy lines
path = get_user_input()
subprocess.Popen(r'explorer "%s"' % path)
#Here I start my update process
multiprocessing.Process(target=update_index).start()
#end of script, now I want that process to continue until finished while main console closes. I only seem to get one or the other.
I also tried using:
DETACHED_PROCESS = 0x00000008
CREATE_NO_WINDOW = 0x08000000
subprocess.Popen(command, shell=True, stdin=None, stdout=None,
stderr=None,
creationflags=DETACHED_PROCESS|CREATE_NO_WINDOW)
and managed to get a separate console window but still no way from preventing the user for closing down the process.
Also keep in mind I would like to distribute this script with something like py2exe later to make it accessible for those without python so I guess using pythonw.exe is out of question. or?
That's not really the answer you're looking for, but you could redesign your system architecture: Write your index updater as a server process that's communicating with your actual application over sockets. Then you just have the index updater server process run continuously (maybe even on another machine) and have the index updater process do all the time-consuming work.
If you just want to perform background tasks that happen at certain intervals, then use cron. If you want to run a command in the background and keep it running even if you logout of the console, use nohup.

How to unhide and show a process created with subprocess.popen()?

I am trying to create a simple command-line process and show it to the user (I do NOT want the process to be hidden):
import subprocess
import win32con
kwargs = {}
info = subprocess.STARTUPINFO()
info.dwFlags |= subprocess.STARTF_USESHOWWINDOW
info.wShowWindow = win32con.SW_SHOWMAXIMIZED
ExecuteString = ('process.cmd')
kwargs['startupinfo'] = info
sp = subprocess.Popen(ExecuteString, **kwargs)
It works with e.g. notepad.exe but not with the simple process.cmd:
echo "This is a process run from python"
pause
I run out of ideas, how to achieve this. I find all kind of stuff, how to HIDE a process. But I want to achieve the opposite.
Any idea?
Thanks!
You seem to be confusing the notions of process and window. All windows are associated to a process, but a certain process may not be associated with any window.
Your simple batch script is interpreted from the cmd.exe process. If you're used to the behaviour of windows when you open batch scripts with a double-click, might believe cmd.exe is always associated with a window, but that is not true. You can check this yourself by simply running cmd.exe inside a existing command prompt - it doesn't open a new window (as running notepad.exe, for example, would).
In python, processes run "as if" they were run from a command prompt - which is why you don't get another window.
This doesn't actually answer the question, but it might be useful in understanding the problem.
For Windowed applications, you simply need to use the SW_HIDE constant instead of SW_SHOWMAXIMIZED.
If you also want to cover console applications that start up a terminal window, I'm guessing that you would want to run something like this:
start the process;
use EnumWindows();
in your EnumWindowsProc implementation, check for a top-level window (using GetParent()) that is owned by the process you just launched (use GetWindowThreadProcessId()).
This will allow you to find the top-level window(s) of the process you just launched. From there, you can call ShowWindow() to show/hide the Window.
Note that this may be subject to some timing issues (if your search runs before the child process can create its window, the search will yield no results) as well as flicker (because you'll hide the window after it displays).

Categories