勇芳软件 发表于 2018-5-19 13:19:01

【VFB】进程通信之匿名管道

匿名管道可以用来父进程与子进程通信,非父子关系的无法用匿名管道通信

匿名管道功能单一,使用简单,用很少代码即可。

我们用代码启动一个软件,那么被启动的软件成为我们软件的子进程了

准备工作:
#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)此处要改,用于输出获取的内容
'            PrintMid(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

xiawan 发表于 2022-5-17 10:19:52


珍惜生命,果断回帖。
页: [1]
查看完整版本: 【VFB】进程通信之匿名管道