2008-05-21 07:00 作者: 肖波 出处: 天极网

 C# 调用外部进程的类,网上可以搜出很多来,为什么要再写一遍,实在是因为最近从网上拷贝了一个简单的例程用到项目中,运行有问题,后来研究了半天,才解决了这些问题。于是打算重写,一来说说调用一个外部进程这么简单的一件事究竟会有哪些问题,二来也希望我写的这个相对比较完整的类可以为软件开发的同道们节约一些脑细胞,以便集中优势兵力解决那些真正高深复杂的软件问题。

  在开始正题之前,我们先来看一看网上比较常见的执行外部进程的函数

  


private string RunCmd(string command)
   {
   //例Process
   Process p = new Process();
  
   p.StartInfo.FileName = "cmd.exe"; //确定程序名
   p.StartInfo.Arguments = "/c " + command; //确定程式命令行
   p.StartInfo.UseShellExecute = false; //Shell的使用
   p.StartInfo.RedirectStandardInput = true; //重定向输入
   p.StartInfo.RedirectStandardOutput = true; //重定向输出
   p.StartInfo.RedirectStandardError = true; //重定向输出错误
   p.StartInfo.CreateNoWindow = true; //设置置不显示示窗口
  
   p.Start(); //00
  
   //p.StandardInput.WriteLine(command); //也可以用这种方式输入入要行的命令
   //p.StandardInput.WriteLine("exit"); //要得加上Exit要不然下一行程式
  
   return p.StandardOutput.ReadToEnd(); //输出出流取得命令行结果
   }

  

  这个方法应该是比较常见的调用外部进程的方法,我以前也一直是这样调用外部进程的,也没有碰到过什么问题。但这次调用的外部进程比较特殊,用这种方法调用就出现了两个问题。

  第一个问题是这个被调用的外部进程有时候会出现异常,出现异常后Windows会弹出错误报告框,程序于是吊死在那里,必须手工干预。这个问题比较好解决,程序中设置一下注册表搞定。

  第二个问题是调用这个外部进程(是一个控制台进程)后,程序会阻塞在p.StandardOutput.ReadToEnd();这一句,永远无法出来,被调用的那个控制台程序也被吊死。但该控制台进程在CMD 中是可以正常执行的。后来看来一些资料才发现原来原因是出在该控制台程序控制台输出大量字符串,管道重定向后,调用程序没有及时将管道中的输出数据取出,结果导致管道被阻塞,程序吊死。在这里还有另外一个问题,虽然这次没有遇到,但网上有其他人遇到,就是错误信息管道不及时取出数据,也会被阻塞,而且如果要同时取出两个管道的数据,必须要利用一个辅助线程才能实现。

  问题讲完了,下面给出这个类的完整代码

  


using System;
  using System.Collections.Generic;
  using System.Text;
  using System.Runtime.InteropServices;
  using System.Threading;
  
  namespace Laboratory.Process
  {
   class ReadErrorThread
   {
   System.Threading.Thread m_Thread;
   System.Diagnostics.Process m_Process;
   String m_Error;
   bool m_HasExisted;
   object m_LockObj = new object();
  
   public String Error
   {
   get
   {
   return m_Error;
   }
   }
  
   public bool HasExisted
   {
   get
   {
   lock (m_LockObj)
   {
   return m_HasExisted;
   }
   }
  
   set
   {
   lock (m_LockObj)
   {
   m_HasExisted = value;
   }
   }
   }
  
   private void ReadError()
   {
   StringBuilder strError = new StringBuilder();
   while (!m_Process.HasExited)
   {
   strError.Append(m_Process.StandardError.ReadLine());
   }
  
   strError.Append(m_Process.StandardError.ReadToEnd());
  
   m_Error = strError.ToString();
   HasExisted = true;
   }
  
   public ReadErrorThread(System.Diagnostics.Process p)
   {
   HasExisted = false;
   m_Error = "";
   m_Process = p;
   m_Thread = new Thread(new ThreadStart(ReadError));
   m_Thread.Start();
   }
  
   }
  
   class RunProcess
   {
   private String m_Error;
   private String m_Output;
  
   public String Error
   {
   get
   {
   return m_Error;
   }
   }
  
   public String Output
   {
   get
   {
   return m_Output;
   }
   }
  
   public bool HasError
   {
   get
   {
   return m_Error != "" && m_Error != null;
   }
   }
  
   public void Run(String fileName, String para)
   {
   StringBuilder outputStr = new StringBuilder();
  
   try
   {
   //disable the error report dialog.
   //reference: http://www.devcow.com/blogs/adnrg/archive/2006/07/14/Disable-Error-Reporting-Dialog-for-your-application-with-the-registry.aspx
   Microsoft.Win32.RegistryKey key;
   key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"software\microsoft\PCHealth\ErrorReporting\", true);
   int doReport = (int)key.GetValue("DoReport");
  
   if (doReport != 0)
   {
   key.SetValue("DoReport", 0);
   }
  
   int showUI = (int)key.GetValue("ShowUI");
   if (showUI != 0)
   {
   key.SetValue("ShowUI", 0);
   }
   }
   catch
   {
   }
  
  
   m_Error = "";
   m_Output = "";
   try
   {
   System.Diagnostics.Process p = new System.Diagnostics.Process();
  
   p.StartInfo.FileName = fileName;
   p.StartInfo.Arguments = para;
   p.StartInfo.UseShellExecute = false;
   p.StartInfo.RedirectStandardInput = true;
   p.StartInfo.RedirectStandardOutput = true;
   p.StartInfo.RedirectStandardError = true;
   p.StartInfo.CreateNoWindow = true;
  
   p.Start();
  
   ReadErrorThread readErrorThread = new ReadErrorThread(p);
  
   while (!p.HasExited)
   {
   outputStr.Append(p.StandardOutput.ReadLine()+"\r\n");
   }
  
   outputStr.Append(p.StandardOutput.ReadToEnd());
  
   while (!readErrorThread.HasExisted)
   {
   Thread.Sleep(1);
   }
  
   m_Error = readErrorThread.Error;
   m_Output = outputStr.ToString();
   }
   catch (Exception e)
   {
   m_Error = e.Message;
   }
   }
  
   }
  }
  

转载于:https://www.cnblogs.com/gofficer/archive/2008/10/30/1322825.html

一个C#写的调用外部进程类相关推荐

  1. Qt工作笔记-使用Qt中QProcess与iostream中system调用外部进程

    目录 基础概念 演示 基础概念 Qt中的QProcess类可以调用外部程序! 同时iostream有个函数system也可以调用外部程序!这个system也是Windows,Linux上通用的 演示 ...

  2. ABAP 发布webservice调用外部webservice

    本文讲述了SAP如何发布一个webservice已经如何调用外部的webservice. 1.SE37创建一个函数并且开启远程启用模块 2.se80---->右键创建企业服务 3.SOAMANA ...

  3. SAP接口集成-abap调用外部数据库

    SAP接口集成-abap调用外部数据库 前言 一.SAP配置外部数据源 二.使用步骤 1.新建测试程序 2.使用场景介绍 总结 前言 PI/PO集成方式很多,但是有趣的灵魂不多,现在介绍一个直接用ab ...

  4. 实现一个在JNI中调用Java对象的工具类,从此只需一行代码

    前言 我们知道在jni中执行一个java函数需要调用几行代码才行,如 jclass objClass = (*env).GetObjectClass(obj); jmethodID methodID ...

  5. Linux下 Qt界面程序嵌入另一个Qt界面程序_Qt应用嵌入外部进程窗口

    项目工程的实现,想要使用多个程序进行实现,在里面存在一定的调用的过程:调查的情况如下 Qt界面程序嵌入另一个Qt界面程序[Linux] Qt界面程序嵌入另一个Qt界面程序[Linux]_ptc321的 ...

  6. C#中调用外部exe的使用、调用powershell、退出进程、委托和事件

    针对几种情况,简单总结学习一下 竟然找到一个超级简单的方法调用exe文件 代码就一句,并且调用的效果特别好.加上后面的.WaitForExit()就是为了等调用的程序运行完后再执行下面的代码,没有后面 ...

  7. 分享一个自己写的取中国农历相关数据的类。包含:农历年月日,生肖,星座,年龄,天干,地支等方法...

    分享一个自己写的取中国农历相关数据的类.包含:农历年月日,生肖,星座,年龄,天干,地支等方法.此类自己花了一上午的时间写的,适用于像相亲网等类似的网站 主要使用了微软针对东亚地区的农历类Chinese ...

  8. as3调用外部swf里的类的方法

    as3项目要调用外部swf里的类有3种方法: 1.将外部的swf发布为swc,使用时将swc引用添加到相应的项目中,这应该是最简单的一种引用.不过当项目中的类或组件比较多时就会使项目发布生成的swf文 ...

  9. 进程P1、P2、P3共享一个表格F,P1对F只读不写,P2对F只写不读,P3对F先读后写。进程可同时读F,但有进程写时,其他进程不能读和写。

    进程P1.P2.P3共享一个表格F,P1对F只读不写,P2对F只写不读,P3对F先读后写.进程可同时读F,但有进程写时,其他进程不能读和写.要求:(1)正常运行时不能产生死锁.(2)F的并发度要高. ...

最新文章

  1. List、Set、Map的区别
  2. import 快捷键 自动调整顺序_一文搞定PPT中的快捷键
  3. Centos Another app is currently holding the yum lock
  4. 美团/力扣(647)--回文字串
  5. Hadoop学习之整体介绍及环境搭建
  6. win10安装mysql5.7.15_win10上如何安装mysql5.7.16(解压缩版)
  7. python打开csv文件绘制折线图,[转载]python绘制简单折线图
  8. WEB小知识学习集锦
  9. 路由器访问控制列表基础知识
  10. 数据结构——树的概述
  11. Mysql添加远程访问权限
  12. 算法笔记:tarjan算法求强连通分量割点桥
  13. qss样式表之QComboBox
  14. scrapy 搜索关键字_基于scrapy框架输入关键字爬取有关贴吧帖子
  15. 睡眠时的局部目标记忆再激活
  16. Oracle11g下导入SDO_GEOMETRY类型的数据异常处理
  17. git 拉取其他分支代码
  18. Android 前置摄像头预览与编码
  19. Unity 3D光源-Point Light点光源详解/灯泡、模拟灯光效果教程
  20. 相关系数R-判定系数R方的matlab实现

热门文章

  1. qt开发环境 - 简易二进制文件打开,串口自发自收
  2. html5内容切换特效,html5+jQuery图片和文字内容同时左右切换特效
  3. 地址池命令 思科理由_论CCNA基础之常用命令
  4. 详解MTK系统中字符转换问题
  5. ASP.NET Core Web 应用程序系列(三)- 在ASP.NET Core中使用Autofac替换自带DI进行构造函数和属性的批量依赖注入(MVC当中应用)...
  6. Selenium常用API的使用java语言之13-多表单切换
  7. 6.1团队第二阶段冲刺(七)
  8. (五)Unity插件生成
  9. Switch语句的参数是什么类型的?
  10. 《Hive编程指南》14.3 投影变换的实践出错原因分析