匿名管道可以用来父进程与子进程通信,非父子关系的无法用匿名管道通信
匿名管道功能单一,使用简单,用很少代码即可。
我们用代码启动一个软件,那么被启动的软件成为我们软件的子进程了
准备工作:
#include Once "fbthread.bi" '需要多线程
Type PipeStruct '
hPipeInputRead As HANDLE '数据输入管道
hPipeInputWrite As HANDLE '数据输入管道
hPipeOutputRead As HANDLE '数据输出管道
hPipeOutputWrite As HANDLE '数据输出管道
bConsole As PROCESS_INFORMATION '控制台
End Type
Dim Shared pipe As PipeStruct '保存管道的变量
一、建立匿名管道,因为管道是单向的,要双向通信,必须建立2个
Dim Sa As SECURITY_ATTRIBUTES
With Sa '设置管道句柄安全属性
.nLength = SizeOf(SECURITY_ATTRIBUTES)
.bInheritHandle = True '必须为TRUE
.lpSecurityDescriptor = 0
End With
'数据输入管道
CreatePipe(@pipe.hPipeInputRead, @pipe.hPipeInputWrite, @sa, 0)
'数据输出管道
CreatePipe(@pipe.hPipeOutputRead, @pipe.hPipeOutputWrite, @sa, 0)
二、启动子进程,以 CMD 为例题,当然可以是任意软件,而且隐藏掉软件,在背后偷偷运行
Dim si As STARTUPINFO, CmdStr As String
'设置进程的启动信息,这是一个输入参数
si.cb = SizeOf(STARTUPINFO)
GetStartupInfo(@si)
si.dwFlags = STARTF_USESTDHANDLES Or STARTF_USESHOWWINDOW '这个必须设置,否则仍将显示窗口
si.hStdOutput = pipe.hPipeOutputWrite '输出由标准输出 -> 输出到管道
si.hStdError = pipe.hPipeOutputWrite '输出由标准输出 -> 输出到管道
Si.hStdInput = pipe.hPipeInputRead '输入由标准输入 -> 从管道中读取
si.wShowWindow = SW_HIDE '隐藏子进程
'使用刚才设置的各个参数创建隐秘的进程
'此进程将把ping程序运行的结果写到管道
CreateProcessA(Null, "CMD", Null, Null, True, Null, Null, Null, @Si, @pipe.bConsole)
三、启动读取内容线程,不用多线程会发生堵塞。读取来自子进程,子读父,需要稍微改改即可
Threaddetach ThreadCreate(Cast(Any Ptr, @PipeLineInput), @pipe) '读取无内容时线程会被挂起,因此必须用多线程
Sub PipeLineInput(ByRef pipe As PipeStruct) '读取内容,的线程
'从管道读取上述进程的输出,并显示于界面
Dim bRet As WINBOOL, buffer As ZString * 1024, dwBytesRead As Long
Dim BtRead As Long, BtTotal As Long, BtLeft As Long, OutData As String, ff As Long
Dim tt As String
Do
bRet = ReadFile(pipe.hPipeOutputRead, @buffer, 1024, @dwBytesRead, Null)
If bRet=0 Then Exit Do
If dwBytesRead > 0 Then
If Left(buffer,dwBytesRead)="终止引擎" Then Exit Do
OutData &= Left(buffer,dwBytesRead)
Do
ff = InStr(OutData, vbCrLf)
If ff = 0 Then Exit Do
tt=FF_Control_GetText(HWND_FORM1_TEXT2) 此处要改,用于输出获取的内容
' Print Mid(OutData, 1, ff -1) 此处要改,用于输出获取的内容
tt &=vbCrLf & Mid(OutData, 1, ff -1) 此处要改,用于输出获取的内容
FF_Control_SetText HWND_FORM1_TEXT2,tt 此处要改,用于输出获取的内容
OutData = Mid(OutData, ff + 2)
Loop
End If
Sleep 100
Loop
' Print "完成了........"
End Sub
四、发送内容,这里是父发给子的,子发给父的稍微改改即可,就是那个句柄
Sub PipeLineOutput(ByRef pipe As PipeStruct, szLineStr As String) '发送
Dim Buflen As Long, BtWritten As Long, rtn As Long
rtn = WriteFile(pipe.hPipeInputWrite, StrPtr(szLineStr), Len(szLineStr), @BtWritten, Null)
' Print rtn, BtWritten
End Sub
五、关闭管道,结束子进程
Sub PipeClose(ByRef pipe As PipeStruct) '关闭引擎
Dim Buflen As Long, BtWritten As Long, rtn As Long, szLineStr As String
szLineStr = "终止引擎" '为了让线程退出,只有退了,才可以终止引擎
rtn = WriteFile(pipe.hPipeOutputWrite, StrPtr(szLineStr), Len(szLineStr), @BtWritten, Null)
Sleep 10 '留给时间给线程退出
CloseHandle pipe.hPipeInputRead
CloseHandle pipe.hPipeInputWrite
CloseHandle pipe.hPipeOutputRead
CloseHandle pipe.hPipeOutputWrite
CloseHandle pipe.bConsole.hThread
CloseHandle pipe.bConsole.hProcess
ProcessKill(pipe.bConsole.dwProcessId) 终止进程
End Sub
六、子进程获取父进程发来的管道句柄,有了句柄,在子进程里,仿照上面的写法,应该不难写出来吧。
Print GetStdHandle(STD_INPUT_HANDLE) 'Si.hStdInput 用来读取父进程发来的内容
Print GetStdHandle(STD_OUTPUT_HANDLE) 'si.hStdOutput 用来发送给父进程内容
Print GetStdHandle(STD_ERROR_HANDLE) 'si.hStdError
以上是为双向通信而写,假如单向,就只搞一个通道即可。
注:本例题源码下载,请进 B语言编程群:78458582