Public Class CPLINK
#Region "WINAPI定义"
Private Class WINAPI
<System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)> _
Private Structure STARTUPINFO
Dim cb As DWORD
Dim lpReserved As LPTSTR
Dim lpDesktop As LPTSTR
Dim lpTitle As LPTSTR
Dim dwX As DWORD
Dim dwY As DWORD
Dim dwXSize As DWORD
Dim dwYSize As DWORD
Dim dwXCountChars As DWORD
Dim dwYCountChars As DWORD
Dim dwFillAttribute As DWORD
Dim dwFlags As DWORD
Dim wShowWindow As WORD
Dim cbReserved2 As WORD
Dim lpReserved2 As LPBYTE
Dim hStdInput As HANDLE
Dim hStdOutput As HANDLE
Dim hStdError As HANDLE
End Structure
<System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)> _
Private Structure PROCESS_INFORMATION
Dim hProcess As HANDLE
Dim hThread As HANDLE
Dim dwProcessId As DWORD
Dim dwThreadId As DWORD
End Structure
Private Declare Unicode Function _CreateProcess Lib "Kernel32.dll" Alias "CreateProcessW" (ByVal _in_ApplicationName As String,ByVal _inout_CommandLine As String,ByVal _opt_lpProcessAttributes As Zero,ByVal _opt_lpThreadAttributes As Zero,ByVal _in_InheritHandles As BOOL,ByVal _in_CreationFlags As DWORD,ByVal _opt_lpEnvironment As Zero,ByVal _opt_lpCurrentDirectory As Zero,ByRef _in_StartupInfo As STARTUPINFO,ByRef _out_ProcessInformation As PROCESS_INFORMATION) As BOOL
Private Declare Auto Function _GetLastError Lib "Kernel32.dll" Alias "GetLastError" () As DWORD
Private Const STARTF_USESTDHANDLES As DWORD = &H100
Private Const CREATE_NO_WINDOW As DWORD = &H8000000
Private Const CREATE_NEW_CONSOLE As DWORD = &H10
Private Const [TRUE] As DWORD = 1
Public Shared Function CreateProcess(AppPath As String,Arguements As String,hStdin As Microsoft.Win32.SafeHandles.SafePipeHandle,hStdout As Microsoft.Win32.SafeHandles.SafePipeHandle,hStderr As Microsoft.Win32.SafeHandles.SafePipeHandle) As Integer
Dim si As New STARTUPINFO
Dim pi As New PROCESS_INFORMATION
si.cb = Len(si)
#If 不用特别调试 = True Then
si.hStdInput = 0
si.hStdOutput = hStdout.DangerousGetHandle
si.hStdError = hStderr.DangerousGetHandle
si.dwFlags = STARTF_USESTDHANDLES
If 0 = _CreateProcess(AppPath,"appname.exe " & Arguements,0,[TRUE],CREATE_NEW_CONSOLE,si,pi) Then
#Else
si.hStdInput = hStdin.DangerousGetHandle
si.hStdOutput = hStdout.DangerousGetHandle
si.hStdError = hStderr.DangerousGetHandle
si.dwFlags = STARTF_USESTDHANDLES
If 0 = _CreateProcess(AppPath,"plink.exe " & Arguements,CREATE_NO_WINDOW,pi) Then
#End If
Dim errcode As Integer = _GetLastError()
MsgBox("CreateProcess Failed and lasterror code is: " & errcode)
Return 0
Else
Return pi.dwProcessId
End If
End Function
End Class
#End Region
#Region "工作区"
Private plinkPath As String,plinkEncoding As System.Text.Encoding
Private plnkCStdin,plnkCStdout,plnkCStderr As System.IO.Pipes.AnonymousPipeServerStream
Private plnkProcessID As Integer,thRdCStdout,thRdCstderr As System.Threading.Thread
Private rtaa(2) As ReadThreadArgs
Public CStdin As System.IO.StreamWriter,CStdout,CStderr As System.IO.StreamReader
Public ReadTimeout_ms As Integer = 75
Private Event E_CharRecieved(ch As Char,channel As Integer)
Public Event E_PlinkOutRecieved(data As String,iscompleteline As Boolean)
Private Structure ReadThreadArgs
Dim sr As System.IO.StreamReader
Dim channel As Integer
Dim strb As System.Text.StringBuilder
Dim rdTimer As System.Timers.Timer
End Structure
Private Sub ReadThreadMain(rta As ReadThreadArgs)
Dim ch As Char
Do
Try
ch = ChrW(rta.sr.Read())
RaiseEvent E_CharRecieved(ch,rta.channel)
Catch ex As Exception
Exit Do
End Try
Loop
End Sub
Public Function PlinkStartWithEvents(argline As String) As Boolean
If Not PlinkStart(argline) Then Return False
thRdCstderr = New System.Threading.Thread(AddressOf ReadThreadMain)
thRdCStdout = New System.Threading.Thread(AddressOf ReadThreadMain)
thRdCstderr.IsBackground = True
thRdCStdout.IsBackground = True
rtaa(2) = New ReadThreadArgs With {.sr = CStderr,.channel = 2,.strb = New System.Text.StringBuilder,.rdTimer = New System.Timers.Timer With {.Interval = ReadTimeout_ms}}
rtaa(1) = New ReadThreadArgs With {.sr = CStdout,.channel = 1,.rdTimer = New System.Timers.Timer With {.Interval = ReadTimeout_ms}}
AddHandler rtaa(2).rdTimer.Elapsed,AddressOf OnTimeOut_channel2
AddHandler rtaa(1).rdTimer.Elapsed,AddressOf OnTimeOut_channel1
thRdCstderr.Start(rtaa(2))
thRdCStdout.Start(rtaa(1))
Return True
End Function
Private Sub OnTimeOut_channel2(sender As Object,e As System.Timers.ElapsedEventArgs)
Call WhenTimeOut(2)
End Sub
Private Sub OnTimeOut_channel1(sender As Object,e As System.Timers.ElapsedEventArgs)
Call WhenTimeOut(1)
End Sub
Private Sub WhenTimeOut(channel As Integer)
With rtaa(channel)
.rdTimer.Enabled = False
If .strb.Length > 0 Then
RaiseEvent E_PlinkOutRecieved(.strb.ToString,channel,False)
.strb.Clear()
End If
End With
End Sub
Private Sub OnCharRecieved(ch As Char,channel As Integer) Handles Me.E_CharRecieved
Dim chCode As Integer = AscW(ch)
Dim te As Boolean = True
With rtaa(channel)
.rdTimer.Enabled = False
Select Case chCode
Case 13
Case 10
RaiseEvent E_PlinkOutRecieved(.strb.ToString,True)
.strb.Clear()
te = False
Case &H1 To &HF
.strb.Append("\x0" & Hex(chCode))
Case &H10 To &H1F,&H7F
.strb.Append("\x" & Hex(chCode))
Case Else
.strb.Append(ch)
End Select
.rdTimer.Enabled = te
End With
End Sub
Public Function PlinkStart(argline As String) As Boolean
Try
plnkCStderr = New System.IO.Pipes.AnonymousPipeServerStream(IO.Pipes.PipeDirection.In,IO.HandleInheritability.Inheritable)
plnkCStdout = New System.IO.Pipes.AnonymousPipeServerStream(IO.Pipes.PipeDirection.In,IO.HandleInheritability.Inheritable)
plnkCStdin = New System.IO.Pipes.AnonymousPipeServerStream(IO.Pipes.PipeDirection.Out,IO.HandleInheritability.Inheritable)
CStderr = New System.IO.StreamReader(plnkCStderr,plinkEncoding)
CStdout = New System.IO.StreamReader(plnkCStdout,plinkEncoding)
CStdin = New System.IO.StreamWriter(plnkCStdin,plinkEncoding) : CStdin.AutoFlush = True
plnkProcessID = WINAPI.CreateProcess(plinkPath,argline,plnkCStdin.ClientSafePipeHandle,plnkCStdout.ClientSafePipeHandle,plnkCStderr.ClientSafePipeHandle)
Return CBool(plnkProcessID)
Catch ex As Exception
MsgBox("EXCEPTION@CPLINK::Start: " & ex.Message)
Return False
End Try
End Function
Public Sub PlinkEnd()
Try
Dim pp As Process = System.Diagnostics.Process.GetProcessById(plnkProcessID)
pp.Kill()
Catch ex As Exception
End Try
Try
CStderr.Close()
CStdin.Close()
CStdout.Close()
Catch ex As Exception
End Try
Try
plnkCStderr.Close()
plnkCStdin.Close()
plnkCStdout.Close()
Catch ex As Exception
End Try
End Sub
Sub New(in_plinkpath As String,Optional in_encoding As System.Text.Encoding = Nothing)
If System.IO.File.Exists(in_plinkpath) Then
plinkPath = in_plinkpath
If in_encoding Is Nothing Then
plinkEncoding = System.Text.Encoding.UTF8
Else
plinkEncoding = in_encoding
End If
Else
Throw New Exception("Failed@CPLINK::New: 指定的文件【" & in_plinkpath & "】不存在")
End If
End Sub
Protected Overrides Sub Finalize()
MyBase.Finalize()
Me.PlinkEnd()
End Sub
#End Region
End Class