我在python中编写了一个简单的命令行应用程序,它通过调用win32 API创建一个新进程,当使用ctypes包装器调用函数CreateProcess时,应用程序退出并抛出内存访问冲突错误,代码如下: / p>
from ctypes import windll, byref, POINTER, GetLastError, Structure, sizeof,Union,pointer
from ctypes.wintypes import (
LPCWSTR, LPWSTR, WCHAR, DWORD, HANDLE, BOOL,LPCVOID,ULONG,BYTE,WORD
)
import sys
import time
class STARTUPINFO(Structure):
_field_=[("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",POINTER(BYTE)),
("hStdInput",HANDLE),
("hStdOutput",HANDLE),
("hStdError",HANDLE)]
class PROCESS_INFORMATION(Structure):
_field_=[("hProcess",HANDLE),
("hThread",HANDLE),
("dwProcessId",DWORD),
("dwThreadId",DWORD)]
class SECURITY_ATTRIBUTES(Structure):
_field_=[("nLength",DWORD),("lpSecurityDescriptor",LPCVOID)]
HANDLE_FLAG_INHERIT=0x1
STARTF_USESTDHANDLES=0x100
CreatePipe=windll.Kernel32.CreatePipe
CreatePipe.argtype=[POINTER(HANDLE),POINTER(HANDLE),POINTER(SECURITY_ATTRIBUTES),DWORD]
CreatePipe.restype=BOOL
SetHandleInformation=windll.Kernel32.SetHandleInformation
SetHandleInformation.argtype=[HANDLE,DWORD,DWORD]
SetHandleInformation.restype=BOOL
CloseHandle = windll.Kernel32.CloseHandle
CloseHandle.argtypes = [HANDLE]
CloseHandle.restype = BOOL
CreateProcess=windll.Kernel32.CreateProcessW
CreateProcess.argtypes=[LPCWSTR,LPWSTR,POINTER(SECURITY_ATTRIBUTES),POINTER(SECURITY_ATTRIBUTES),BOOL,DWORD,LPCVOID,LPCWSTR,POINTER(STARTUPINFO),POINTER(PROCESS_INFORMATION)]
CreateProcess.restype=BOOL
class test(object):
def __init__(self):
self.g_hChildStd_OUT_Rd=HANDLE()
self.g_hChildStd_IN_Rd=HANDLE()
self.g_hChildStd_OUT_Wr=HANDLE()
self.g_hChildStd_IN_Wr=HANDLE()
def CreateChildProcess(self):
szCmdline = "c:\\windows\\System32\\cmd.exe"
saAttr = SECURITY_ATTRIBUTES()
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES)
saAttr.bInheritHandle = True
saAttr.lpSecurityDescriptor = None
# Create a pipe for the child process's STDOUT.
if not CreatePipe(byref(self.g_hChildStd_OUT_Rd), byref(self.g_hChildStd_OUT_Wr), byref(saAttr), 0):
raise Exception("failed to create console process.")
if not SetHandleInformation(self.g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0):
raise Exception("failed to create console process.")
# Create a pipe for the child process's STDIN.
if not CreatePipe(byref(self.g_hChildStd_IN_Rd), byref(self.g_hChildStd_IN_Wr), byref(saAttr), 0):
raise Exception("failed to create console process.")
if not SetHandleInformation(self.g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0):
raise Exception("failed to create console process.")
piProcInfo = PROCESS_INFORMATION()
siStartInfo = STARTUPINFO()
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = self.g_hChildStd_OUT_Wr
siStartInfo.hStdOutput = self.g_hChildStd_OUT_Wr
siStartInfo.hStdInput = self.g_hChildStd_IN_Rd
siStartInfo.dwFlags = STARTF_USESTDHANDLES
piProcInfo.hProcess = None
piProcInfo.hThread = None
piProcInfo.dwProcessId = 0
piProcInfo.dwThreadId = 0
bSuccess = CreateProcess(szCmdline, # executable name
None, # command line name
None, # primary process security attributes
None, # primary thread security attributes
True, # handles are inherited
0, # creation flags
None, # use parent's environment
None, # use parent's current directory
byref(siStartInfo), # STARTUPINFO pointer
pointer(piProcInfo)) # child process's information. piProcInfo struct won't be modified and not contain the child process infomation after this call if I use byref here.
if not bSuccess:
rc = GetLastError()
raise Exception("failed to create console process. error code %u" % rc)
else:
"""// Close handles to the child process and its primary thread.
// Some applications might keep these handles to monitor the status
// of the child process, for example."""
CloseHandle(piProcInfo.hProcess)
CloseHandle(piProcInfo.hThread)
print "[Info] Create cmd process successfully"
#follows some codes to write to and read from pipes
if __name__=="__main__":
obj=test()
obj.CreateChildProcess()
stacktrace messeages是以下
Traceback (most recent call last):
File "test01.py", line 104, in <module>
obj.CreateChildProcess()
File "test01.py", line 90, in CreateChildProcess
pointer(piProcInfo)) # child process's information
WindowsError: exception: access violation reading 0x00000001
我猜这个错误信息的原因是参数piProcInfo对win32 API不可变,windows函数不能修改内存结构piProcInfo并且失败但是我不太确定我的猜测而且我不知道如何初始化一个可变的内存结构并将其作为参数传递给Windows API,任何人都可以帮我解决这个问题吗?
另外,我试图将byref(piProcInfo)作为参数传递,但是piProcInfo结构中的子进程信息没有改变,我需要这些信息以便进一步的步骤。