How to create a suspended subprocess in Python on Windows?
Question:
I would like to create a subprocess via subprocess.Popen
that starts in a suspended state so I can have it ready to run at a later point.
I found a solution for Linux here but couldn’t find any solution for Windows. Does anyone know if there’s a Windows equivalent to this?
Answers:
After some more investigation I managed to create a suspended process and resume it later. Creating a suspended process using Popen and Windows is thankfully pretty simple.
First you will need to install pywin32 by running:
pip install pywin32
Once pywin32 is installed you can create a suspended process with subprocess.Popen
by using:
from win32process import CREATE_SUSPENDED
from subprocess import Popen
pipe = subprocess.Popen(<command>, <**kwargs>, creationflags=CREATE_SUSPENDED)
Resuming this suspended process, however, is quite a bit more difficult since it requires a PyHandle for the suspended thread. Unfortunately Popen doesn’t return a Thread ID which is required to open a PyHandle for the suspended thread. As a work-around I ended up monkeypatching Popen’s _execute_child function to store the Thread ID returned by _winapi.CreateProcess. Now that we have the suspended process’ Thread ID we can resume the thread.
To resume a suspended process assuming you monkeypatched Popen to store the Thread ID use:
from win32api import OpenThread, CloseHandle
from win32con import THREAD_SUSPEND_RESUME
from win32process import ResumeThread
thread_handle = OpenThread(THREAD_SUSPEND_RESUME, <inherit handle (T/F)>, pipe.tid)
ResumeThread(thread_handle)
CloseHandle(thread_handle)
If anyone knows a way to get the Thread ID from Popen without monkeypatching _execute_child or any better methods of suspending and resuming a process please share!
Resources:
- Pywin32 Docs: https://mhammond.github.io/pywin32/
- Creation Flags: https://learn.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
- Popen: https://docs.python.org/3/library/subprocess.html#subprocess.Popen
- OpenThread: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthread
- CloseHandle: https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
- Thread Security and Access Rights: https://learn.microsoft.com/en-us/windows/win32/procthread/thread-security-and-access-rights
- Resume Thread: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-resumethread
I also created a wrapper for subprocess.Popen that kills the child process when the parent dies if anyone would like to see my specific implementation.
I would like to create a subprocess via subprocess.Popen
that starts in a suspended state so I can have it ready to run at a later point.
I found a solution for Linux here but couldn’t find any solution for Windows. Does anyone know if there’s a Windows equivalent to this?
After some more investigation I managed to create a suspended process and resume it later. Creating a suspended process using Popen and Windows is thankfully pretty simple.
First you will need to install pywin32 by running:
pip install pywin32
Once pywin32 is installed you can create a suspended process with subprocess.Popen
by using:
from win32process import CREATE_SUSPENDED
from subprocess import Popen
pipe = subprocess.Popen(<command>, <**kwargs>, creationflags=CREATE_SUSPENDED)
Resuming this suspended process, however, is quite a bit more difficult since it requires a PyHandle for the suspended thread. Unfortunately Popen doesn’t return a Thread ID which is required to open a PyHandle for the suspended thread. As a work-around I ended up monkeypatching Popen’s _execute_child function to store the Thread ID returned by _winapi.CreateProcess. Now that we have the suspended process’ Thread ID we can resume the thread.
To resume a suspended process assuming you monkeypatched Popen to store the Thread ID use:
from win32api import OpenThread, CloseHandle
from win32con import THREAD_SUSPEND_RESUME
from win32process import ResumeThread
thread_handle = OpenThread(THREAD_SUSPEND_RESUME, <inherit handle (T/F)>, pipe.tid)
ResumeThread(thread_handle)
CloseHandle(thread_handle)
If anyone knows a way to get the Thread ID from Popen without monkeypatching _execute_child or any better methods of suspending and resuming a process please share!
Resources:
- Pywin32 Docs: https://mhammond.github.io/pywin32/
- Creation Flags: https://learn.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
- Popen: https://docs.python.org/3/library/subprocess.html#subprocess.Popen
- OpenThread: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthread
- CloseHandle: https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
- Thread Security and Access Rights: https://learn.microsoft.com/en-us/windows/win32/procthread/thread-security-and-access-rights
- Resume Thread: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-resumethread
I also created a wrapper for subprocess.Popen that kills the child process when the parent dies if anyone would like to see my specific implementation.