【发布时间】:2021-03-17 00:30:51
【问题描述】:
我无法使用 WINAPI 的 CreateProcess 和 CREATE_SUSPENDED 和 VBA 的 ResumeThread。
我想启动一个进程(并接收它的进程 ID)并能够暂停和恢复其主线程(取决于考虑到我计算机的资源利用率使用的更复杂的方案 - 此处不详述)。我想出了以下代码并遇到以下问题:
-
调用 CreateProcess 后 LastDllError 为 18 虽然返回 值非零。这是什么意思?
-
ResumeThread 失败并出现 ERROR_INVALID_HANDLE,并且不会恢复 它。这里有什么问题?
我的代码:
Option Explicit
Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type
Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Byte
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type
Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessId As Long
dwThreadId As Long
End Type
Private Const CREATE_SUSPENDED As Long = 4
Private Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" ( _
ByVal lpApplicationName As String, _
ByVal lpCommandLine As String, _
ByRef lpProcessAttributes As SECURITY_ATTRIBUTES, _
ByRef lpThreadAttributes As SECURITY_ATTRIBUTES, _
ByVal bInheritHandles As Long, _
ByVal dwCreationFlags As Long, _
ByRef lpEnvironment As Any, _
ByVal lpCurrentDirectory As String, _
ByRef lpStartupInfo As STARTUPINFO, _
ByRef lpProcessInformation As PROCESS_INFORMATION) As Long
Private Declare Function SuspendThread Lib "kernel32" (hThread As Long) As Long
Private Declare Function ResumeThread Lib "kernel32" (hThread As Long) As Long
Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
Private Declare Function DebugActiveProcess Lib "kernel32" (ByVal dwProcessId As Long) As Long
Private Declare Function DebugActiveProcessStop Lib "kernel32" (ByVal dwProcessId As Long) As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Public Function WinApi_CreateProcess(strCommandLine As String, Optional strCurrentDirectory As String = vbNullString) As Long
If strCurrentDirectory = vbNullString Then
strCurrentDirectory = ThisWorkbook.Path
End If
Dim sap As SECURITY_ATTRIBUTES: sap.nLength = Len(sap)
Dim sat As SECURITY_ATTRIBUTES: sat.nLength = Len(sat)
Dim si As STARTUPINFO: si.cb = Len(si)
Dim pi As PROCESS_INFORMATION
Debug.Print Err.LastDllError ' 0 => ERROR_SUCCESS
Dim dwResult As Long: dwResult = CreateProcess(vbNullString, strCommandLine, sap, sat, 0, CREATE_SUSPENDED, 0, strCurrentDirectory, si, pi)
Debug.Print Err.LastDllError ' 18 => ERROR_NO_MORE_FILES (but dwResult <> 0 => Success)
If dwResult = 0 Then
WinApi_CreateProcess = 0: Exit Function
End If
CloseHandle pi.hProcess
Debug.Print Err.LastDllError ' 0 => ERROR_SUCCESS
Dim dwSuspendCount As Long: dwSuspendCount = ResumeThread(pi.hThread)
Debug.Print dwSuspendCount ' -1
If dwSuspendCount = -1 Then
Debug.Print Err.LastDllError ' 6 => ERROR_INVALID_HANDLE
CloseHandle pi.hThread
WinApi_CreateProcess = 0: Exit Function
Else
Debug.Print Err.LastDllError ' Not this branch
CloseHandle pi.hThread
WinApi_CreateProcess = pi.dwProcessId: Exit Function
End If
End Function
【问题讨论】:
-
告诉您 hThread 字段包含无效的句柄值。它会在 VBA 代码在 64 位模式下运行时,句柄是 LongPtr。碰巧对 hProcess 起作用,因为它是结构中的第一个字段。
-
@HansPassant 这怎么可能?我有一台 x64 计算机,但我的 Office 是 32 位的,我创建的进程也是 32 位的。 (在任务管理器中我看到
EXCEL.EXE *32和cmd.exe *32。后者的路径是C:\Windows\SysWOW64\cmd.exe。) -
好的,下一个bug是STARTUPINFO.lpReserved2,它是一个指针。 So Long 或 LongPtr,而不是 Byte。当操作系统写入太多数据而不适合变量中的空间时,这会导致内存损坏,从而影响相邻的变量。这恰好是这段代码中的 pi 变量。还不足以破坏 hThread 字段,但鞋子很合适。
-
谢谢,我更正了那个。但是,它并没有解决它。由于操作系统只从 si 中读取数据,因此不会损坏 pi。
标签: vba winapi createprocess