Multithreading VB6外壳进程在继续主线程之前等待客户端
我想创建一个应用程序来启动CMD或MySQL控制台之类的进程,并向其输入命令,然后读取输出,而不使用文件 当我需要使用Multithreading VB6外壳进程在继续主线程之前等待客户端,multithreading,vb6,Multithreading,Vb6,我想创建一个应用程序来启动CMD或MySQL控制台之类的进程,并向其输入命令,然后读取输出,而不使用文件 当我需要使用ReadAllOutput()时,我从stackoverflow获得的代码会一直挂起主线程,即使在我关闭客户端线程之后,主线程也不会收到来自客户端的输出 我需要保持客户端线程处于活动状态,因为我需要登录到某些系统 以下是我正在使用的类: Option Explicit DefObj A-Z Private Const MODULE_NAME As String = "cExec"
ReadAllOutput()
时,我从stackoverflow获得的代码会一直挂起主线程,即使在我关闭客户端线程之后,主线程也不会收到来自客户端的输出
我需要保持客户端线程处于活动状态,因为我需要登录到某些系统
以下是我正在使用的类:
Option Explicit
DefObj A-Z
Private Const MODULE_NAME As String = "cExec"
'=========================================================================
' API
'=========================================================================
'--- for CreateProcess
Private Const STARTF_USESHOWWINDOW As Long = 1
Private Const STARTF_USESTDHANDLES As Long = &H100
Private Const SW_HIDE As Long = 0
Private Const SW_MINIMIZE As Long = 6
Private Const NORMAL_PRIORITY_CLASS As Long = &H20&
'--- for WaitForSingleObject
Private Const INFINITE As Long = &HFFFFFFFF
'--- for DuplicateHandle
Private Const DUPLICATE_SAME_ACCESS As Long = &H2
'--- for GetExitCodeProcess
Private Const STATUS_PENDING As Long = &H103
Private Declare Function CreateProcessA Lib "kernel32" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByVal lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function CreatePipe Lib "kernel32" (phReadPipe As Long, phWritePipe As Long, lpPipeAttributes As SECURITY_ATTRIBUTES, ByVal nSize As Long) As Long
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
Private Declare Function DuplicateHandle Lib "kernel32" (ByVal hSourceProcessHandle As Long, ByVal hSourceHandle As Long, ByVal hTargetProcessHandle As Long, lpTargetHandle As Long, ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwOptions As Long) As Long
Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, ByVal lpOverlapped As Long) As Long
Private Declare Function TerminateProcess Lib "kernel32" (ByVal hProcess As Long, ByVal uExitCode As Long) As Long
Private Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, ByVal lpOverlapped As Long) As Long
Private Declare Function FlushFileBuffers Lib "kernel32" (ByVal hFile As Long) As Long
Private Declare Function PeekNamedPipe Lib "kernel32" (ByVal hNamedPipe As Long, lpBuffer As Any, ByVal nBufferSize As Long, lpBytesRead As Long, lpTotalBytesAvail As Long, lpBytesLeftThisMessage As Long) As Long
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 Long
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 Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type
'=========================================================================
' Constants and member variables
'=========================================================================
Private m_hProcess As Long
Private m_hReadOutput As Long
Private m_hReadError As Long
Private m_hWriteInput As Long
'=========================================================================
' Error handling
'=========================================================================
Private Sub PrintError(sFunc As String)
MsgBox Error & " in " & MODULE_NAME & "." & sFunc & "(" & Erl & ")", vbCritical, App.EXEName
End Sub
'=========================================================================
' Methods
'=========================================================================
Public Function Run( _
sFile As String, _
sParams As String, _
Optional ByVal bStartHidden As Boolean, _
Optional ByVal bStartMimized As Boolean) As Boolean
Const FUNC_NAME As String = "Run"
Dim uProcInfo As PROCESS_INFORMATION
Dim uStart As STARTUPINFO
Dim sCommandLine As String
Dim uSA As SECURITY_ATTRIBUTES
Dim hTmp As Long
Dim hWriteOutput As Long
Dim hWriteError As Long
Dim hReadInput As Long
On Error GoTo EH
'--- cleanup previous
If m_hProcess <> 0 Then
Call CloseHandle(m_hProcess)
m_hProcess = 0
End If
If m_hReadOutput <> 0 Then
Call CloseHandle(m_hReadOutput)
m_hReadOutput = 0
End If
If m_hReadError <> 0 Then
Call CloseHandle(m_hReadError)
m_hReadError = 0
End If
'--- win9x: fix spaces or not working on 9X
If InStr(sFile, " ") > 0 And Left$(sFile, 1) <> """" Then
sCommandLine = """" & sFile & """" & " " & sParams
Else
sCommandLine = sFile & " " & sParams
End If
'--- create pipes
uSA.nLength = Len(uSA)
uSA.bInheritHandle = 1
Call CreatePipe(hTmp, hWriteOutput, uSA, 0)
Call DuplicateHandle(GetCurrentProcess(), hTmp, GetCurrentProcess(), m_hReadOutput, 0, False, DUPLICATE_SAME_ACCESS)
Call CloseHandle(hTmp)
Call CreatePipe(hTmp, hWriteError, uSA, 0)
Call DuplicateHandle(GetCurrentProcess(), hTmp, GetCurrentProcess(), m_hReadError, 0, False, DUPLICATE_SAME_ACCESS)
Call CloseHandle(hTmp)
Call CreatePipe(hReadInput, hTmp, uSA, 0)
Call DuplicateHandle(GetCurrentProcess(), hTmp, GetCurrentProcess(), m_hWriteInput, 0, False, DUPLICATE_SAME_ACCESS)
Call CloseHandle(hTmp)
'--- setup start info
uStart.cb = Len(uStart)
uStart.dwFlags = STARTF_USESTDHANDLES
uStart.hStdInput = hReadInput ' GetStdHandle(STD_INPUT_HANDLE)
uStart.hStdOutput = hWriteOutput
uStart.hStdError = hWriteError
If bStartHidden Then
uStart.dwFlags = uStart.dwFlags Or STARTF_USESHOWWINDOW
uStart.wShowWindow = SW_HIDE
End If
If bStartMimized Then
uStart.dwFlags = uStart.dwFlags Or STARTF_USESHOWWINDOW
uStart.wShowWindow = SW_MINIMIZE
End If
If CreateProcessA(vbNullString, sCommandLine, 0, 0, 1, NORMAL_PRIORITY_CLASS, 0, vbNullString, uStart, uProcInfo) <> 0 Then
Call CloseHandle(uProcInfo.hThread)
m_hProcess = uProcInfo.hProcess
Else
Call CloseHandle(m_hReadOutput)
m_hReadOutput = 0
Call CloseHandle(m_hReadError)
m_hReadError = 0
End If
Call CloseHandle(hWriteOutput)
Call CloseHandle(hWriteError)
'--- success (or failure)
Run = (m_hProcess <> 0)
Exit Function
EH:
PrintError FUNC_NAME
End Function
Public Function AtEndOfError() As Boolean
Dim lTotal2 As Long
If m_hReadError <> 0 Then
If PeekNamedPipe(m_hReadError, ByVal 0, 0, 0, lTotal2, 0) = 0 Then
Call CloseHandle(m_hReadError)
m_hReadError = 0
End If
End If
AtEndOfError = (m_hReadError = 0)
End Function
Public Function ReadError(ByVal lSize As Long) As String
Dim szBuffer As String
Dim lRead As Long
If m_hReadError <> 0 Then
szBuffer = String(lSize, 0)
If ReadFile(m_hReadError, ByVal szBuffer, lSize, lRead, 0) <> 0 Then
ReadError = Left$(szBuffer, lSize)
Else
Call CloseHandle(m_hReadError)
m_hReadError = 0
End If
End If
End Function
Public Function ReadLineError(Optional sTerminator As String) As String
Do While Not AtEndOfError
ReadLineError = ReadLineError & ReadError(1)
If Right$(ReadLineError, 2) = vbCrLf Then
Exit Function
ElseIf LenB(sTerminator) <> 0 And Right$(ReadLineError, Len(sTerminator)) = sTerminator Then
Exit Function
End If
DoEvents
Loop
End Function
Public Function ReadAllError() As String
Do While Not AtEndOfError
ReadAllError = ReadAllError & ReadError(100)
DoEvents
Loop
End Function
Public Function ReadPendingError() As String
Dim lTotal As Long
Do While Not AtEndOfError
lTotal = 0
If PeekNamedPipe(m_hReadError, ByVal 0, 0, 0, lTotal, 0) = 0 Then
Call CloseHandle(m_hReadError)
m_hReadError = 0
End If
If lTotal > 0 Then
ReadPendingError = ReadPendingError & ReadError(lTotal)
Else
Exit Function
End If
DoEvents
Loop
End Function
Public Function AtEndOfOutput() As Boolean
Dim lTotal2 As Long
If m_hReadOutput <> 0 Then
If PeekNamedPipe(m_hReadOutput, ByVal 0, 0, 0, lTotal2, 0) = 0 Then
Call CloseHandle(m_hReadOutput)
m_hReadOutput = 0
End If
End If
AtEndOfOutput = (m_hReadOutput = 0)
End Function
Public Function ReadOutput(ByVal lSize As Long) As String
Dim szBuffer As String
Dim lRead As Long
If m_hReadOutput <> 0 Then
szBuffer = String(lSize, 0)
If ReadFile(m_hReadOutput, ByVal szBuffer, lSize, lRead, 0) <> 0 Then
ReadOutput = Left$(szBuffer, lSize)
Else
Call CloseHandle(m_hReadOutput)
m_hReadOutput = 0
End If
End If
End Function
Public Function ReadLineOutput() As String
Do While Not AtEndOfOutput
ReadLineOutput = ReadLineOutput & ReadOutput(1)
If Right$(ReadLineOutput, 2) = vbCrLf Then
Exit Function
End If
DoEvents
Loop
End Function
Public Function ReadAllOutput() As String
Do While Not AtEndOfOutput
ReadAllOutput = ReadAllOutput & ReadOutput(100)
DoEvents
Loop
End Function
Public Function ReadPendingOutput() As String
Dim lTotal As Long
Do While Not AtEndOfOutput
lTotal = 0
If PeekNamedPipe(m_hReadOutput, ByVal 0, 0, 0, lTotal, 0) = 0 Then
Call CloseHandle(m_hReadOutput)
m_hReadOutput = 0
End If
If lTotal > 0 Then
ReadPendingOutput = ReadPendingOutput & ReadOutput(lTotal)
Else
Exit Function
End If
DoEvents
Loop
End Function
Public Function WriteInput(sValue As String) As Boolean
Dim lWritten As Long
DoEvents
If m_hWriteInput <> 0 Then
If WriteFile(m_hWriteInput, ByVal sValue, Len(sValue), lWritten, 0) <> 0 Then
DoEvents
'Call FlushFileBuffers(m_hWriteInput)
WriteInput = True
Else
WriteInput = False
End If
End If
End Function
Public Function GetExitCode() As Long
If m_hProcess <> 0 Then
Call GetExitCodeProcess(m_hProcess, GetExitCode)
If GetExitCode = STATUS_PENDING Then
If m_hReadOutput <> 0 Then
Call CloseHandle(m_hReadOutput)
m_hReadOutput = 0
End If
If m_hReadError <> 0 Then
Call CloseHandle(m_hReadError)
m_hReadError = 0
End If
If m_hWriteInput <> 0 Then
Call CloseHandle(m_hWriteInput)
m_hWriteInput = 0
End If
Call WaitForSingleObject(m_hProcess, INFINITE)
Call GetExitCodeProcess(m_hProcess, GetExitCode)
End If
Call CloseHandle(m_hProcess)
m_hProcess = 0
End If
End Function
Public Function KillProcess() As Boolean
If Not AtEndOfOutput And Not AtEndOfError Then
If TerminateProcess(m_hProcess, 0) <> 0 Then
KillProcess = True
End If
End If
End Function
Private Sub Class_Terminate()
If m_hProcess <> 0 Then
KillProcess
Call CloseHandle(m_hProcess)
m_hProcess = 0
End If
If m_hReadOutput <> 0 Then
Call CloseHandle(m_hReadOutput)
m_hReadOutput = 0
End If
If m_hReadError <> 0 Then
Call CloseHandle(m_hReadError)
m_hReadError = 0
End If
If m_hWriteInput <> 0 Then
Call CloseHandle(m_hWriteInput)
m_hWriteInput = 0
End If
End Sub
选项显式
DefObj A-Z
私有常量模块\u名称为String=“cExec”
'=========================================================================
"空气污染指数
'=========================================================================
'---用于CreateProcess
Private Const STARTF_USESHOWWINDOW的长度=1
私人Const STARTF_USESTDHANDLES的长度=&H100
私有常量SW_隐藏长度=0
私有常量SW_最小化为长=6
Private Const NORMAL_PRIORITY_类的长度=&H20&
'---用于WaitForSingleObject
私有常量无限长=&hffffff
“---用于重复句柄
Private Const DUPLICATE\u与Long=&H2访问相同
'---用于GetExitCodeProcess
私有常量状态_挂起,长度=&H103
私有声明函数CreateProcessA Lib“kernel32”(ByVal lpApplicationName作为字符串,ByVal lpCommandLine作为字符串,ByVal lpProcessAttributes作为长,ByVal lpThreadAttributes作为长,ByVal bInheritHandles作为长,ByVal dwCreationFlags作为长,ByVal lpEnvironment作为长,ByVal lpCurrentDirectory作为字符串,lpStartupInfo作为STARTUPINFO,lpProcessInformation作为进程信息)作为长
私有声明函数WaitForSingleObject库“kernel32”(ByVal hHandle尽可能长,ByVal DWM尽可能长)尽可能长
私有声明函数getExitCode进程库“kernel32”(ByVal hProcess As Long,lpExitCode As Long)为Long
私有声明函数CloseHandle Lib“kernel32”(ByVal hObject As Long)为Long
私有声明函数CreatePipe Lib“kernel32”(phReadPipe为Long,phWritePipe为Long,lpPipeAttributes为SECURITY_属性,ByVal nSize为Long)为Long
私有声明函数GetCurrentProcess Lib“kernel32”(长度为
私有声明函数DuplicateHandle Lib“kernel32”(ByVal hSourceProcessHandle为Long,ByVal hSourceHandle为Long,ByVal hTargetProcessHandle为Long,lpTargetHandle为Long,ByVal dwDesiredAccess为Long,ByVal bInheritHandle为Long,ByVal dwOptions为Long)为Long
私有声明函数ReadFile Lib“kernel32”(ByVal hFile尽可能长,lpBuffer尽可能长,ByVal nNumberOfBytesToRead尽可能长,lpNumberOfBytesRead尽可能长,ByVal lpOverlapped尽可能长)尽可能长
私有声明函数TerminateProcess Lib“kernel32”(ByVal hProcess As Long,ByVal uExitCode As Long)作为Long
私有声明函数WriteFile Lib“kernel32”(ByVal hFile尽可能长,lpBuffer尽可能长,ByVal nnumberofbytes尽可能长,lpnumberofbytes尽可能长,ByVal lpOverlapped尽可能长)尽可能长
私有声明函数FlushFileBuffers Lib“kernel32”(ByVal hFile作为Long)作为Long
私有声明函数PeekNamedPipe Lib“kernel32”(ByVal hNamedPipe尽可能长,lpBuffer尽可能长,ByVal nBufferSize尽可能长,lpBytesRead尽可能长,lpTotalBytesAvail尽可能长,lpBytesLeftThisMessage尽可能长)尽可能长
私有类型STARTUPINFO
只要
保留为字符串
lpDesktop作为字符串
lpTitle作为字符串
dwX尽可能长
只要
dwXSize尽可能长
尽可能长
dwXCountChars的长度为
德怀康查斯一样长
dwFillAttribute尽可能长
把旗子拖得一样长
wShowWindow作为整数
cbReserved2为整数
lpReserved2尽可能长
HST输入长度为
hst输出长度
hStdError尽可能长
端型
私有类型进程信息
hProcess尽可能长
hThread尽可能长
dwProcessId尽可能长
dwThreadId尽可能长
端型
私有类型安全属性
长度等于
lpSecurityDescriptor的长度
长柄
端型
'=========================================================================
'常量和成员变量
'=========================================================================
私有m_hProcess尽可能长
私有m_线程输出长度为
私有m_线程错误,长度为
专用m_硬件输入长度
'=========================================================================
'错误处理
'=========================================================================
私有子打印错误(sFunc作为字符串)
MsgBox错误&“在”&MODULE_NAME&“&sFunc&”(&Erl&“)中”,vbCritical,App.EXEName
端接头
'=========================================================================
"方法",
'=========================================================================
公众活动(_
sFile作为字符串_
斯巴拉姆斯作为弦_
可选的ByVal bStartHidden作为布尔值_
可选的ByVal bStartMimized As Boolean)作为Boolean
常量FUNC_名称为String=“Run”
作为过程信息的信息
作为STARTUPINFO的Dim uStart
作为字符串的Dim sCommandLine
作为安全属性的Dim uSA
将hTmp变暗为长
将输出变长
长时的模糊错误
将输入变长
关于错误转到EH
“---上一篇
如果m_h进程为0,则
调用CloseHandle(m_hProcess)
m_hProcess=0
如果结束
如果m_线程输出为0,则
调用CloseHandle(m_线程输出)
m_线程输出=0
如果结束
如果m_线程错误为0,则
调用CloseHandle(m_线程错误)