以下代码应该在调试模式下启动一个新进程
calc.exe
。但是,它失败并显示代码 2 或 ERROR_FILE_NOT_FOUND
。然而,这个文件calc.exe
确实存在于系统中。这段代码可能有什么问题?路径是否存在可以改进的问题,以便可以正常工作?
from ctypes import *
kernel32 = windll.kernel32
WORD = c_ushort
DWORD = c_ulong
LPBYTE = POINTER(c_ubyte)
LPTSTR = POINTER(c_char)
HANDLE = c_void_p
class STARTUPINFO(Structure):
_fields_ = [
("cb", DWORD),
("lpReserved", LPTSTR),
("lpDesktop", LPTSTR),
("lpTitle", LPTSTR),
("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),
]
class PROCESS_INFORMATION(Structure):
_fields_ = [
("hProcess", HANDLE),
("hThread", HANDLE),
("dwProcessId", DWORD),
("dwThreadId", DWORD),
]
DEBUG_PROCESS = 0x00000001
creation_flags = DEBUG_PROCESS
startupinfo = STARTUPINFO()
startupinfo.dwFlags = 0x1
startupinfo.wShowWindow = 0x0
startupinfo.cb = sizeof(startupinfo)
process_information = PROCESS_INFORMATION()
result = kernel32.CreateProcessA("C:\\Windows\\System32\\calc.exe",
None,
None,
None,
None,
creation_flags,
None,
None,
byref(startupinfo),
byref(process_information)
)
print(result)
print(kernel32.GetLastError())
有很多错误的地方:
缺少 ArgTypes 和 ResType 定义,该定义会产生 Undefined Behavior(尽管可能不可见)。检查[SO]:通过 ctypes 从 Python 调用的 C 函数返回不正确的值(@CristiFati 的答案),了解使用 CTypes(调用函数)时的常见陷阱
函数或字符串相关类型的A(ANSI,ASCII)和W(WIDE,UNICODE)变体之间的混淆(检查[MS.Learn]:函数原型的约定)及其所需的Python参数。您正在使用 A,因此您必须传递一个 Bytes 实例。检查[SO]:将 utf-16 字符串传递给 Windows 函数(@CristiFati 的答案)了解更多详细信息
不要重新发明轮子,使用定义了许多
Win特定类型的
ctypes.wintypes
。作为此处的注释,我没有检查结构是否有错误(只是调整了它们的定义)
code00.py:
#!/usr/bin/env python
import ctypes as cts
import sys
from ctypes import wintypes as wts
class STARTUPINFOA(cts.Structure):
_fields_ = (
("cb", wts.DWORD),
("lpReserved", wts.LPSTR),
("lpDesktop", wts.LPSTR),
("lpTitle", wts.LPSTR),
("dwX", wts.DWORD),
("dwY", wts.DWORD),
("dwXSize", wts.DWORD),
("dwYSize", wts.DWORD),
("dwXCountChars", wts.DWORD),
("dwYCountChars", wts.DWORD),
("dwFillAttribute", wts.DWORD),
("dwFlags", wts.DWORD),
("wShowWindow", wts.WORD),
("cbReserved2", wts.WORD),
("lpReserved2", wts.LPBYTE),
("hStdInput", wts.HANDLE),
("hStdOutput", wts.HANDLE),
("hStdError", wts.HANDLE),
)
LPSTARTUPINFOA = cts.POINTER(STARTUPINFOA)
class PROCESS_INFORMATION(cts.Structure):
_fields_ = (
("hProcess", wts.HANDLE),
("hThread", wts.HANDLE),
("dwProcessId", wts.DWORD),
("dwThreadId", wts.DWORD),
)
LPPROCESS_INFORMATION = cts.POINTER(PROCESS_INFORMATION)
LPSECURITY_ATTRIBUTES = cts.c_void_p
DEBUG_PROCESS = 0x00000001
def main(*argv):
kernel32 = cts.windll.kernel32
GetLastError = kernel32.GetLastError
GetLastError.argtypes = ()
GetLastError.restype = wts.DWORD
CreateProcessA = kernel32.CreateProcessA
CreateProcessA.argtypes = (
wts.LPCSTR, wts.LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES,
wts.BOOL, wts.DWORD, wts.LPVOID, wts.LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION
)
CreateProcessA.restype = wts.BOOL
creation_flags = DEBUG_PROCESS
creation_flags = 0 # Not automatically killed when Python terminates
startupinfo = STARTUPINFOA()
startupinfo.dwFlags = 0x1
startupinfo.wShowWindow = 0x0
startupinfo.cb = cts.sizeof(STARTUPINFOA)
process_information = PROCESS_INFORMATION()
result = kernel32.CreateProcessA(
b"C:\\Windows\\System32\\calc.exe",
None,
None,
None,
False,
creation_flags,
None,
None,
cts.byref(startupinfo),
cts.byref(process_information)
)
print(f"CreateProcessA returned {result}")
if not result:
print(f" Error: {GetLastError()}")
else:
print(f" Created process (PId: {process_information.dwProcessId},"
f" TId: {process_information.dwThreadId})")
if __name__ == "__main__":
print(
"Python {:s} {:03d}bit on {:s}\n".format(
" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32,
sys.platform,
)
)
rc = main(*sys.argv[1:])
print("\nDone.\n")
sys.exit(rc)
输出:
(py_pc064_03.10_test0) [cfati@CFATI-5510-0:e:\Work\Dev\StackExchange\StackOverflow\q078680399]> sopr.bat ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [prompt]> python ./code00.py Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr 5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] 064bit on win32 CreateProcessA returned 1 Created process (PId: 32444, TId: 22832) Done. [prompt]> :: Calculator window is pops up
作为 CTypes 的替代方案,您可以尝试 [GitHub]:mhammond/pywin32 - Python for Windows (pywin32) Extensions,它是 WinAPI 的 Python 包装器(并且包含大量 Python 的样板代码) 程序员不必编写)。文档 (WiP) 可在 [GitHub.MHammond]:Python for Win32 扩展帮助(或 [ME.TimGolden]:Python for Win32 扩展帮助)找到。