之前在做一个自动化项目的时候运动到了管道(Process),在开发过程中直接使用了C#封装好的方法。但是在实际运用过程中出现了一定的问题,在扫描管道内容时时常出现卡死的显现。之后再网络上查询了很久在另一篇博客中找到了问题,是C#函数存在一定的BUG。目前已经忘记了那位大神是谁了。不过还是要谢谢他。接下来分享下这个方法以便于其他与我遇到相同问题的朋友可以借鉴。如有不足之处也可以直接指出。
/*变量定义*/ Str_Result = string.Empty; int BufferCount = 0; byte[] rf_Buffer = new byte[4096]; Process p = new Process(); /*初始化管道*/ p.StartInfo.FileName = "cmd.exe"; p.StartInfo.Arguments = string.Format("/c {0}", Str_Cmd);//命令 p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardInput = true; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.RedirectStandardError = true; p.StartInfo.CreateNoWindow = true; p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; p.Start();//启动道 p.WaitForExit(40000);//等待指令完成给定40秒正常指令都已经完成了
以上是管道的定义以及启动。
// 将返回资料付给文件系统 System.IO.FileStream TempStrem = (System.IO.FileStream)p.StandardOutput.BaseStream; uint StartTime = GetTickCount();//获取开始时间 用于超时跳出 if (B_IsResult) { do { // C#扫描存在BUG 沿用API函数 //最开始运用的C#封装好的函数但是一直会出现卡死后运用windowsAPI函数不知到4.0以后版本是否优化 BufferCount = 0; PeekNamedPipe(TempStrem.SafeFileHandle, rf_Buffer, 65535, ref BufferCount, 0, 0); if (BufferCount > 0) { break;//如果管道内已经为空则跳出 } } while (B_IsResult && (GetTickCount() - StartTime < I_TimeOut)); while (B_IsResult)//判断如果需要内容这读取 { //这里可能有点小问题 //如果不需要判断返回值没有读取管道内的值则可能会出现管道无法关闭 BufferCount = 0; PeekNamedPipe(TempStrem.SafeFileHandle, rf_Buffer, 65535, ref BufferCount, 0, 0); if (BufferCount > 0)//如果扫描到管道内有值则读取 { byte[] c_Buffer = new byte[BufferCount]; TempStrem.Read(c_Buffer, 0, BufferCount); string temp_Result = System.Text.Encoding.Default.GetString(c_Buffer);//转换为中文 Str_Result += temp_Result; } else { break; } Thread.Sleep(50); } }
以上为管道返回内容的读取
p.Close(); p.Dispose();//关闭并释放
以上为管道的关闭释放
[DllImport("kernel32.dll", SetLastError = true)] public static extern int PeekNamedPipe(//API函数扫描管道 SafeFileHandle hNamedPipe, byte[] lpBuffer, int nBufferSize, ref int lpBytesRead, int lpTotalBytesAvail, int lpBytesLeftThisMessage ); [DllImport("kernel32")] public static extern uint GetTickCount();//API函数获取时间
以上运用的API函数