一个C#写的调用外部进程类

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/264487.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

lamp平台

LANMP平台LAMP指的Linux(操作系统)、ApacheHTTP 服务器,MySQL(有时也指MariaDB,数据库软件) 和PHP(有时也是指Perl或Python) 的第一个字母,一般用来建立web 服务器。lamp…

在预览fastreport报表之前改变一些报表对象的属性

在预览fastreport报表之前改变一些报表对象的属性 有时候许多报表很可能大同小异,只是有个别地方显示的不同,如报表标题,一些控件标题等等。这样我们只需要设计一次报表,在许多地方调用同一份报表,这时候,我…

centos7 配置静态ip时出现双ip问题解决

1、先用ifconfig,看看有几个网卡 2、执行vi /etc/sysconfig/network-scripts/ifcfg-eth0最后的网卡名字改为实际的 3、静态ip只需要设置着几个地方,BOOTPROTOstatic,特别要注意检查是否有NM_CONTROLLEDno,我就是加了这句重启了就没有两个ip了…

晴天php下载,x.php · 一步晴天/smart - Gitee.com

//get拦截规则$getfilter "\\<.>|<.>|\\b(alert\\(|confirm\\(|expression\\(|prompt\\(|benchmark\s*?\(.*\)|sleep\s*?\(.*\)|\\b(group_)?concat[\\s\\/\\*]*?\\([^\\)]?\\)|\bcase[\s\/\*]*?when[\s\/\*]*?\([^\)]?\)|load_file\s*?\\()|]*?\\…

【编程题目】复杂链表的复制☆

76.复杂链表的复制&#xff08;链表、算法&#xff09;题目&#xff1a;有一个复杂链表&#xff0c;其结点除了有一个 m_pNext 指针指向下一个结点外&#xff0c;还有一个 m_pSibling 指向链表中的任一结点或者 NULL。其结点的 C定义如下&#xff1a;struct ComplexNode{ int m…

我的asp.net学习心得

首先说明&#xff0c;本人仅是初学者&#xff0c;不足之处请见谅。 最开始接触.net时大约是四年前&#xff08;四年前,.net应该有了吧&#xff09;。当时是个老师推荐我学习asp.net的&#xff0c;可事实上当时我对asp.net&#xff0c;甚至制作网页都没有太多概念。 然后大约是两…

angularJS 路由加载js controller 未定义 解决方案

说明    本文主要说明&#xff0c;在angularJS框架使用中&#xff0c;angularJS 路由加载js controller 未定义 解决方案。    路由 $routeProvider 异步加载js    路由的基本用法&#xff0c;请查看官方文档&#xff0c;下面实例只说明&#xff0c;懒加载用法。 …

求解哈夫曼编码Java实现,用Java实现哈夫曼编码解决方法

当前位置:我的异常网 J2SE 用Java实现哈夫曼编码解决方法用Java实现哈夫曼编码解决方法www.myexceptions.net 网友分享于&#xff1a;2013-01-08 浏览&#xff1a;13次用Java实现哈夫曼编码我有一个程序 但是运行结果不对 而且 也没有界面设计请各位高手帮忙修改下 用JAVA实…

mysql大数据优化要注意的细节

值得学习的东西&#xff0c;转载~1、对查询进行优化、应尽量避免全表扫描、首先应考虑在 where 及 order by 涉及的列上建立索引。2、应尽量避免在 where 子句中对字段进行 null 值判断、否则将导致引擎放弃使用索引而进行全表扫描、如&#xff1a;select id from t where num …

mssql sqlserver 不固定行转列数据(动态列)

mssql sqlserver 不固定行转列数据(动态列) 原文:mssql sqlserver 不固定行转列数据(动态列)转自:http://www.maomao365.com/?p5471摘要: 下文主要讲述动态行列转换语句&#xff0c;列名会根据行数据的不同&#xff0c; 动态的发生变化 -------------------------------------…

Linux自动备份脚本

今天网上一个朋友问了我一个shell的题目&#xff0c;让我帮他做下。下面是题目以及解题思路。题目&#xff1a;写作一个备份/etc目录的脚本&#xff0c;要求&#xff1a;将/etc目录下的所有文件cp到/var/backups目录下的以当天的日期命名的目录中例如&#xff08;/var/backups/…

wopi php,Office Online Server WOPI 接口

class WopiCheckFileInfo{//Boolean类型 指示wopi客户端可以连接到外部的微软服务提供额外的功能。如果该值为false&#xff0c;则wopi客户决不允许这样的连接public $AllowAdditionalMicrosoftServices false;//Boolean 类型&#xff0c;表示WOPI客户端允许连接文件中对于外部…

WebBrowser控件禁用超链接转向、脚本错误提示、默认右键菜单和快捷键

转载于:https://www.cnblogs.com/sjcatsoft/archive/2008/11/19/1336425.html

centos 6.x 64位 运行32位程序

缘由&#xff1a;使用luajit的程序编译为32位&#xff0c;在64位系统上执行安装如下&#xff1a;基础依赖 yum install glibc.i686可能的libstdc依赖 yum install libstdc.i686 若报版本不一致&#xff0c;请依次执行 yum install libstdc yum install …

主键与聚集索引的区别

主键可为聚集索引也可为非聚集索引。 两者的比较 下面是一个简单的比较表 主键聚集索引用途强制表的实体完整性对数据行的排序&#xff0c;方便查询用一个表多少个一个表最多一个主键一个表最多一个聚集索引是否允许多个字段来定义一个主键可以多个字段来定义一个索引可以多个字…

在php里让字体划过变色,鼠标划过字体时如何用css来实现字体变色?(代码实测)...

当我们在浏览网页时&#xff0c;鼠标划过某段文字会出现变色效果&#xff0c;这就是css字体变色&#xff0c;一方面是为了主动吸引人用户目光去点击&#xff0c;另一方面是为了防止用户点击错其他文字段落。其实这种css鼠标经过字体变色的效果是非常容易实现的。只要你略懂css知…

使用svn进行版本控制

以前都是别人建好并配置好了svn&#xff0c;然后我使用。今天自己简单尝试了下建svn来管理项目文档。中间也遇到些问题。下面是我总结的一个完整流程&#xff0c;许多步骤可以有另外的方法来完成&#xff0c;但在这我都只给我认为比较简单的方法。 我使用系统是: Microsoft Win…

Android面试,BroadCastReceiver的两种注册方式的异同

在Android手机应用程序中开发中&#xff0c;需要用到BroadcastReceiver来监听广播的消息。在自定义好BroadcastReceiver &#xff0c;需要对其进行注册&#xff0c;注册有两种方法&#xff1a; 一种是在代码当中注册&#xff0c;注册的方法是registerReceiver&#xff08;recei…

php session_regenerate_id,什么时候以及为什么我应该使用session_regenerate_id()?

什么session_regenerate_id()啊就像函数名称所说的那样&#xff0c;它是一个函数&#xff0c;它将用新的ID替换当前的会话ID&#xff0c;并保留当前的会话信息。它有什么作用&#xff1f;它主要有助于防止会话固定攻击。会话固定攻击是恶意用户试图利用系统中的漏洞固定(设置)另…

DataTable的计算功能(转)

C#--详解DataTable的计算功能 using System;using System.ComponentModel;using System.Data;using System.Windows.Forms;namespace WindowsApplication1{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void button1_Click(object sende…