进程通信之匿名管道VFB使用说明

  勇芳 2018-5-19 6694

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

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

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

准备工作:

#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  




因国家互联网安全管理要求,关闭回帖功能。大家需要留言,请使用【勇芳软件客服】即时联系勇芳点此打开->>勇芳软件客服
返回
联系勇芳
发新帖 搜索 反馈 回顶部