今天有一个网友通过“发送短消息”向我提了一个题为《关于“C#重定向问题”的探讨》问题。本着对网友的负责,我决定写下完整示例。
关于网友所提的问题,因为描述的信息不够充足,我很难告知具体是哪里出了问题,直觉判断是masm.exe中的程序可能有点问题,但也不排除其他可能。希望能够提供更多的信息进行排错。
既然我写下了示例,而且自己也不曾做过相关的内容,就博留个脚印。
基本思路
应用程序的重定向问题基本上是通过启动另外一个进程运行另外的程序来执行一些处理,如果处理结果有返回值,主进程可以通过输出流的方式来进行获取。
准备
本示例采用WPF作为主进程的宿主程序,并通过构建控制台程序作为后台处理的程序进行处理。虽然采用WPF进行构建,但并不代表该文章所描述的内容仅限于此,WPF只是作为一个可视界面方便查看。如果您熟悉Winform也可以采用Winform编程的方式进行构建,甚至您仅用控制台应用程序也是可以的。(需要做一些小的改动)
基本步骤(简略)
1.添加如图所示的项目文件和程序界面:
2.分别为两个按钮添加事件处理程序:
(
左侧:其中白色文本框Name=txtInput,蓝色文本框Name=txtOutput,RunProcessSync执行同步调用进程的操作,RunProcessAsync执行异步调用进程的操作
右侧:CA_Processer用于处理具体操作的一个简单的控制台应用程序,WpfAppProcess即为左侧所示宿主程序
)
同步:
同步的操作相对比较简单,也就是当按下按钮后,启动另外一个进程进行处理,我们可以在处理完毕后从StandardOutput对象中获取处理进程输出流。
代码如下:
#region Sync
private
void RunProcessSync_Click(
object sender, RoutedEventArgs e)
{
string input = txtInput.Text;
ProcessStartInfo info = InitializeProcessStartInfo(input);
txtOutput.Text = DoProcessSync(info);
}
///
<summary>
///
同步处理COMMAND
///
</summary>
///
<param name="info"></param>
///
<param name="input"></param>
///
<returns></returns>
private
string DoProcessSync(ProcessStartInfo info)
{
Process pro = Process.Start(info);
return pro.StandardOutput.ReadToEnd();
}
#endregion
异步:
异步的操作仅仅只是相对比较麻烦一点,因为是示例,所以也看不出什么麻烦来。同样是启动另外一个进程进行处理,但是在处理的过程中可以通过调用订阅到OutputDataReceived的委托将数据分批获取下来。显然异步的操作带给我们更多的便利,特别是较长进程下给用户带来了更优质的用户体验。用户不必等处理完毕后才能获取输出流。
代码如下:
#region Async
private
void RunProcessAsync_Click(
object sender, RoutedEventArgs e)
{
ProcessStartInfo info = InitializeProcessStartInfo(txtInput.Text);
try
{
txtOutput.Text = DoProcessAsync(info);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
///
<summary>
///
异步处理COMMAND
///
</summary>
///
<param name="info"></param>
///
<param name="input"></param>
///
<returns></returns>
private
string DoProcessAsync(ProcessStartInfo info)
{
//
异步操作需要指定委托进行异步处理
Process pro =
new Process();
pro.OutputDataReceived +=
new DataReceivedEventHandler(pro_OutputDataReceived);
pro.StartInfo = info;
pro.Start();
//
此调用将启动 StandardOutput 上的异步读取操作。
pro.BeginOutputReadLine();
pro.WaitForExit();
pro.Close();
return _output;
}
string _output =
string.Empty;
void pro_OutputDataReceived(
object sender, DataReceivedEventArgs e)
{
//
可通过调用 CancelOutputRead 取消异步读取操作。可通过调用方或事件处理程序取消读取操作。取消之后,可以再次调用 BeginOutputReadLine 继续进行异步读取操作。
if (!
string.IsNullOrEmpty(e.Data))
{
_output += e.Data;
}
}
#endregion
以下文字来自MSDN(Process.BeginOutputReadLine):
注意到上文中有ProcessStartInfo信息,我们通过如下的代码进行初始化:
///
<summary>
///
初始化ProcessStartInfo对象
///
</summary>
///
<param name="input"></param>
///
<returns></returns>
private
static ProcessStartInfo InitializeProcessStartInfo(
string input)
{
//
参数1:启动程序路径
//
参数2:命令行参数
ProcessStartInfo info =
new ProcessStartInfo(
@"
C:\GoCoolCenter\MyCSharpProject\WpfApplication\WpfAppProcess\CA_Processer\bin\Debug\CA_Processer.exe
",
input);
//
因为要使用StandardOutput,因此以下两个属性均需要如此设置。
info.UseShellExecute =
false;
info.RedirectStandardOutput =
true;
info.WindowStyle = ProcessWindowStyle.Hidden;
return info;
}
另:我们可以通过CancelOutputRead和BeginOutputReadLine来实现“停止”和“继续”的功能。
CA_Processer是一个简单的控制台命令程序,仅作为一个示例,关键在于我们能够“输入”,也能够“输出”了。代码如下:
namespace CA_Processer
{
class Program
{
static
void Main(
string[] args)
{
string result =
string.Empty;
foreach (
string arg
in args)
{
result +=
"" + arg;
}
Console.Write(
"
Processer args = {0}
", result);
}
}
}
通过Console.Write的方式就可以将指定信息写入标准输出流。
除了通过刚才的参数进行传递,我们还可以使用StandardInput的方式指定同步输入流。
步骤:
A.修改宿主程序代码:
///
<summary>
///
异步处理COMMAND
///
</summary>
///
<param name="info"></param>
///
<param name="input"></param>
///
<returns></returns>
private
string DoProcessAsync(ProcessStartInfo info)
{
//
异步操作需要指定委托进行异步处理
Process pro =
new Process();
pro.OutputDataReceived +=
new DataReceivedEventHandler(pro_OutputDataReceived);
pro.StartInfo = info;
pro.StartInfo.RedirectStandardInput = true;
pro.Start();
//
此调用将启动 StandardOutput 上的异步读取操作。
pro.BeginOutputReadLine();
System.IO.StreamWriter swInput = pro.StandardInput;
swInput.Write("-=StandardInput=-");
swInput.Close();
pro.WaitForExit();
pro.Close();
return _output;
}
B.修改处理程序:
namespace CA_Processer
{
class Program
{
static
void Main(
string[] args)
{
string result =
string.Empty;
foreach (
string arg
in args)
{
result +=
"" + arg;
}
Console.Write(
"
Processer args = {0}{1}
",
Console.ReadLine(), result);
}
}
}
示例下载:
WpfAppProcess(http://files.cnblogs.com/volnet/WpfAppProcess.rar)
》点击查看原文...