|
|
# A module to expose various thread/process/job related structures and
|
|
|
# methods from kernel32
|
|
|
#
|
|
|
# The MIT License
|
|
|
#
|
|
|
# Copyright (c) 2006 the Mozilla Foundation <http://www.mozilla.org>
|
|
|
#
|
|
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
# copy of this software and associated documentation files (the "Software"),
|
|
|
# to deal in the Software without restriction, including without limitation
|
|
|
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
# and/or sell copies of the Software, and to permit persons to whom the
|
|
|
# Software is furnished to do so, subject to the following conditions:
|
|
|
#
|
|
|
# The above copyright notice and this permission notice shall be included in
|
|
|
# all copies or substantial portions of the Software.
|
|
|
#
|
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
# DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
from ctypes import c_void_p, POINTER, sizeof, Structure, windll, WinError, WINFUNCTYPE
|
|
|
from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LPCWSTR, LPWSTR, UINT, WORD
|
|
|
|
|
|
LPVOID = c_void_p
|
|
|
LPBYTE = POINTER(BYTE)
|
|
|
LPDWORD = POINTER(DWORD)
|
|
|
|
|
|
SW_HIDE = 0
|
|
|
|
|
|
def ErrCheckBool(result, func, args):
|
|
|
"""errcheck function for Windows functions that return a BOOL True
|
|
|
on success"""
|
|
|
if not result:
|
|
|
raise WinError()
|
|
|
return args
|
|
|
|
|
|
# CloseHandle()
|
|
|
|
|
|
CloseHandleProto = WINFUNCTYPE(BOOL, HANDLE)
|
|
|
CloseHandle = CloseHandleProto(("CloseHandle", windll.kernel32))
|
|
|
CloseHandle.errcheck = ErrCheckBool
|
|
|
|
|
|
# AutoHANDLE
|
|
|
|
|
|
class AutoHANDLE(HANDLE):
|
|
|
"""Subclass of HANDLE which will call CloseHandle() on deletion."""
|
|
|
def Close(self):
|
|
|
if self.value:
|
|
|
CloseHandle(self)
|
|
|
self.value = 0
|
|
|
|
|
|
def __del__(self):
|
|
|
self.Close()
|
|
|
|
|
|
def __int__(self):
|
|
|
return self.value
|
|
|
|
|
|
def ErrCheckHandle(result, func, args):
|
|
|
"""errcheck function for Windows functions that return a HANDLE."""
|
|
|
if not result:
|
|
|
raise WinError()
|
|
|
return AutoHANDLE(result)
|
|
|
|
|
|
# PROCESS_INFORMATION structure
|
|
|
|
|
|
class PROCESS_INFORMATION(Structure):
|
|
|
_fields_ = [("hProcess", HANDLE),
|
|
|
("hThread", HANDLE),
|
|
|
("dwProcessID", DWORD),
|
|
|
("dwThreadID", DWORD)]
|
|
|
|
|
|
def __init__(self):
|
|
|
Structure.__init__(self)
|
|
|
|
|
|
self.cb = sizeof(self)
|
|
|
|
|
|
LPPROCESS_INFORMATION = POINTER(PROCESS_INFORMATION)
|
|
|
|
|
|
# STARTUPINFO structure
|
|
|
|
|
|
class STARTUPINFO(Structure):
|
|
|
_fields_ = [("cb", DWORD),
|
|
|
("lpReserved", LPWSTR),
|
|
|
("lpDesktop", LPWSTR),
|
|
|
("lpTitle", LPWSTR),
|
|
|
("dwX", DWORD),
|
|
|
("dwY", DWORD),
|
|
|
("dwXSize", DWORD),
|
|
|
("dwYSize", DWORD),
|
|
|
("dwXCountChars", DWORD),
|
|
|
("dwYCountChars", DWORD),
|
|
|
("dwFillAttribute", DWORD),
|
|
|
("dwFlags", DWORD),
|
|
|
("wShowWindow", WORD),
|
|
|
("cbReserved2", WORD),
|
|
|
("lpReserved2", LPBYTE),
|
|
|
("hStdInput", HANDLE),
|
|
|
("hStdOutput", HANDLE),
|
|
|
("hStdError", HANDLE)
|
|
|
]
|
|
|
LPSTARTUPINFO = POINTER(STARTUPINFO)
|
|
|
|
|
|
STARTF_USESHOWWINDOW = 0x01
|
|
|
STARTF_USESIZE = 0x02
|
|
|
STARTF_USEPOSITION = 0x04
|
|
|
STARTF_USECOUNTCHARS = 0x08
|
|
|
STARTF_USEFILLATTRIBUTE = 0x10
|
|
|
STARTF_RUNFULLSCREEN = 0x20
|
|
|
STARTF_FORCEONFEEDBACK = 0x40
|
|
|
STARTF_FORCEOFFFEEDBACK = 0x80
|
|
|
STARTF_USESTDHANDLES = 0x100
|
|
|
|
|
|
# EnvironmentBlock
|
|
|
|
|
|
class EnvironmentBlock:
|
|
|
"""An object which can be passed as the lpEnv parameter of CreateProcess.
|
|
|
It is initialized with a dictionary."""
|
|
|
|
|
|
def __init__(self, dict):
|
|
|
if not dict:
|
|
|
self._as_parameter_ = None
|
|
|
else:
|
|
|
values = ["%s=%s" % (key, value)
|
|
|
for (key, value) in dict.iteritems()]
|
|
|
values.append("")
|
|
|
self._as_parameter_ = LPCWSTR("\0".join(values))
|
|
|
|
|
|
# CreateProcess()
|
|
|
|
|
|
CreateProcessProto = WINFUNCTYPE(BOOL, # Return type
|
|
|
LPCWSTR, # lpApplicationName
|
|
|
LPWSTR, # lpCommandLine
|
|
|
LPVOID, # lpProcessAttributes
|
|
|
LPVOID, # lpThreadAttributes
|
|
|
BOOL, # bInheritHandles
|
|
|
DWORD, # dwCreationFlags
|
|
|
LPVOID, # lpEnvironment
|
|
|
LPCWSTR, # lpCurrentDirectory
|
|
|
LPSTARTUPINFO, # lpStartupInfo
|
|
|
LPPROCESS_INFORMATION # lpProcessInformation
|
|
|
)
|
|
|
|
|
|
CreateProcessFlags = ((1, "lpApplicationName", None),
|
|
|
(1, "lpCommandLine"),
|
|
|
(1, "lpProcessAttributes", None),
|
|
|
(1, "lpThreadAttributes", None),
|
|
|
(1, "bInheritHandles", True),
|
|
|
(1, "dwCreationFlags", 0),
|
|
|
(1, "lpEnvironment", None),
|
|
|
(1, "lpCurrentDirectory", None),
|
|
|
(1, "lpStartupInfo"),
|
|
|
(2, "lpProcessInformation"))
|
|
|
|
|
|
def ErrCheckCreateProcess(result, func, args):
|
|
|
ErrCheckBool(result, func, args)
|
|
|
# return a tuple (hProcess, hThread, dwProcessID, dwThreadID)
|
|
|
pi = args[9]
|
|
|
return AutoHANDLE(pi.hProcess), AutoHANDLE(pi.hThread), pi.dwProcessID, pi.dwThreadID
|
|
|
|
|
|
CreateProcess = CreateProcessProto(("CreateProcessW", windll.kernel32),
|
|
|
CreateProcessFlags)
|
|
|
CreateProcess.errcheck = ErrCheckCreateProcess
|
|
|
|
|
|
CREATE_BREAKAWAY_FROM_JOB = 0x01000000
|
|
|
CREATE_DEFAULT_ERROR_MODE = 0x04000000
|
|
|
CREATE_NEW_CONSOLE = 0x00000010
|
|
|
CREATE_NEW_PROCESS_GROUP = 0x00000200
|
|
|
CREATE_NO_WINDOW = 0x08000000
|
|
|
CREATE_SUSPENDED = 0x00000004
|
|
|
CREATE_UNICODE_ENVIRONMENT = 0x00000400
|
|
|
DEBUG_ONLY_THIS_PROCESS = 0x00000002
|
|
|
DEBUG_PROCESS = 0x00000001
|
|
|
DETACHED_PROCESS = 0x00000008
|
|
|
|
|
|
# CreateJobObject()
|
|
|
|
|
|
CreateJobObjectProto = WINFUNCTYPE(HANDLE, # Return type
|
|
|
LPVOID, # lpJobAttributes
|
|
|
LPCWSTR # lpName
|
|
|
)
|
|
|
|
|
|
CreateJobObjectFlags = ((1, "lpJobAttributes", None),
|
|
|
(1, "lpName", None))
|
|
|
|
|
|
CreateJobObject = CreateJobObjectProto(("CreateJobObjectW", windll.kernel32),
|
|
|
CreateJobObjectFlags)
|
|
|
CreateJobObject.errcheck = ErrCheckHandle
|
|
|
|
|
|
# AssignProcessToJobObject()
|
|
|
|
|
|
AssignProcessToJobObjectProto = WINFUNCTYPE(BOOL, # Return type
|
|
|
HANDLE, # hJob
|
|
|
HANDLE # hProcess
|
|
|
)
|
|
|
AssignProcessToJobObjectFlags = ((1, "hJob"),
|
|
|
(1, "hProcess"))
|
|
|
AssignProcessToJobObject = AssignProcessToJobObjectProto(
|
|
|
("AssignProcessToJobObject", windll.kernel32),
|
|
|
AssignProcessToJobObjectFlags)
|
|
|
AssignProcessToJobObject.errcheck = ErrCheckBool
|
|
|
|
|
|
# ResumeThread()
|
|
|
|
|
|
def ErrCheckResumeThread(result, func, args):
|
|
|
if result == -1:
|
|
|
raise WinError()
|
|
|
|
|
|
return args
|
|
|
|
|
|
ResumeThreadProto = WINFUNCTYPE(DWORD, # Return type
|
|
|
HANDLE # hThread
|
|
|
)
|
|
|
ResumeThreadFlags = ((1, "hThread"),)
|
|
|
ResumeThread = ResumeThreadProto(("ResumeThread", windll.kernel32),
|
|
|
ResumeThreadFlags)
|
|
|
ResumeThread.errcheck = ErrCheckResumeThread
|
|
|
|
|
|
# TerminateJobObject()
|
|
|
|
|
|
TerminateJobObjectProto = WINFUNCTYPE(BOOL, # Return type
|
|
|
HANDLE, # hJob
|
|
|
UINT # uExitCode
|
|
|
)
|
|
|
TerminateJobObjectFlags = ((1, "hJob"),
|
|
|
(1, "uExitCode", 127))
|
|
|
TerminateJobObject = TerminateJobObjectProto(
|
|
|
("TerminateJobObject", windll.kernel32),
|
|
|
TerminateJobObjectFlags)
|
|
|
TerminateJobObject.errcheck = ErrCheckBool
|
|
|
|
|
|
# WaitForSingleObject()
|
|
|
|
|
|
WaitForSingleObjectProto = WINFUNCTYPE(DWORD, # Return type
|
|
|
HANDLE, # hHandle
|
|
|
DWORD, # dwMilliseconds
|
|
|
)
|
|
|
WaitForSingleObjectFlags = ((1, "hHandle"),
|
|
|
(1, "dwMilliseconds", -1))
|
|
|
WaitForSingleObject = WaitForSingleObjectProto(
|
|
|
("WaitForSingleObject", windll.kernel32),
|
|
|
WaitForSingleObjectFlags)
|
|
|
|
|
|
INFINITE = -1
|
|
|
WAIT_TIMEOUT = 0x0102
|
|
|
WAIT_OBJECT_0 = 0x0
|
|
|
WAIT_ABANDONED = 0x0080
|
|
|
|
|
|
# GetExitCodeProcess()
|
|
|
|
|
|
GetExitCodeProcessProto = WINFUNCTYPE(BOOL, # Return type
|
|
|
HANDLE, # hProcess
|
|
|
LPDWORD, # lpExitCode
|
|
|
)
|
|
|
GetExitCodeProcessFlags = ((1, "hProcess"),
|
|
|
(2, "lpExitCode"))
|
|
|
GetExitCodeProcess = GetExitCodeProcessProto(
|
|
|
("GetExitCodeProcess", windll.kernel32),
|
|
|
GetExitCodeProcessFlags)
|
|
|
GetExitCodeProcess.errcheck = ErrCheckBool
|
|
|
|