2012-10-16 27 views
8

Tôi đang viết một ứng dụng trong C# tại một thời điểm nào đó bắt đầu một ứng dụng như một tiến trình con sử dụng lớp Process với IO không đồng bộ chuyển hướng như hình dưới đây:Cách chuyển hướng không đồng bộ một cách đơn giản luồng lỗi chuẩn và không phải luồng đầu ra chuẩn của quy trình trong C#, .net

private void AppLaunch_Click(object sender, RoutedEventArgs e) 
{ 

    Process appProcess = new Process(); 
    appProcess.StartInfo.FileName = currAppPath; 
    appProcess.StartInfo.Arguments = ""; 

    //Setup Redirection 
    appProcess.StartInfo.UseShellExecute = false; 
    appProcess.StartInfo.ErrorDialog = false; 
    appProcess.StartInfo.RedirectStandardError = true; 
    appProcess.EnableRaisingEvents = true; 
    // Attach Output Handler 
    appProcess.ErrorDataReceived += appProc_DataReceived; 
    appProcess.Exited += appProc_Exited; 
    buildLogConsoleOutputTxtbox.AppendText(currAppPath + "\n"); 

    appProcess.Start(); 
    appProcess.BeginErrorReadLine(); 

} 
private void appProc_DataReceived(object sender, DataReceivedEventArgs e) 
{ 
    if (!String.IsNullOrEmpty(e.Data)) 
    { 
    this.appendLogText(e.Data); 
    } 
} 

private void appProc_Exited(object sender, System.EventArgs e) 
{ 
    Process proc = (Process)sender; 
    // Wait a short while to allow all console output to be processed and appended 
    Thread.Sleep(40); 
    this.appendLogText("\n>>"); 
    proc.Close(); 
} 

private void appendLogText(string logText) 
{ 
    // Use a delegate if called from a different thread, 
    // else just append the text directly 
    if (buildLogConsoleOutputTxtbox.Dispatcher.CheckAccess()) 
    { 
    // Thread owns the TextBox 
    buildLogConsoleOutputTxtbox.AppendText(logText + Environment.NewLine); 
    } 
    else 
    { 
    //Invocation Required 
    appendLogCallBack appendLog = new appendLogCallBack(buildLogConsoleOutputTxtbox.AppendText); 
    buildlogScrollEnd buildlogscrl = new buildlogScrollEnd(buildLogConsoleOutputTxtbox.ScrollToEnd); 
    buildLogConsoleOutputTxtbox.Dispatcher.BeginInvoke(appendLog, new object[] { logText + Environment.NewLine }); 
    buildLogConsoleOutputTxtbox.Dispatcher.BeginInvoke(buildlogscrl); 
    } 

vấn đề với đoạn mã này là trong khi tôi làm được stderr chuyển hướng đúng để textbox của tôi, chuyển hướng này dường như ẩn quá trình stdout đầu ra, mà tôi không muốn chuyển hướng!

Nếu tôi chuyển hướng stdout, tôi có thể thấy nó chuyển hướng đúng cách, nhưng không thể chỉ chuyển hướng stderr và không stdout? Tôi đã nhìn xung quanh và googled về chủ đề này, nhưng tất cả các cuộc thảo luận dường như liên quan đến chuyển hướng stdout ... như thế này: How to asynchronously read the standard output stream and standard error stream at once

Tôi sẽ biết ơn vì sự giúp đỡ về điều này!

+1

Chắc chắn điều này không thể thực hiện được - cờ là "chuyển hướng tất cả các tay cầm", trong trường hợp đó tất cả các xử lý tiêu chuẩn hiện là trách nhiệm của bạn. Nếu bạn muốn đầu ra tiêu chuẩn ghi vào bảng điều khiển cha mẹ của bạn thì bạn có thể đọc chúng và sau đó viết chúng ra bất cứ nơi nào bạn thích (tức là giao diện điều khiển của bạn) – Justin

+1

Nhưng sau đó là gì ? 'StartInfo.RedirectStandardError = true; StartInfo.RedirectStandardOutput = true // hoặc false trong trường hợp này; 'Ngoài ra tôi muốn stdout để ghi vào bảng điều khiển Child, nếu không tôi chỉ có thể thêm một lệnh Console.Writeline() trong handler phải không? – bethrezan

Trả lời

2

Điều đó là không thể vì - đầu ra và xử lý lỗi được chuyển hướng cùng một lúc. MSDN article STARTUPINFO mô tả STARTF_USESTDHANDLES cờ.

Nhưng có một tin vui. Bảo quản đầu ra của quá trình con vẫn có thể thực hiện được. Bạn chỉ cần:

  • chuyển hướng quá trình đứa trẻ ra
  • gắn với quá trình con console
  • ghi child process sản lượng trở lại giao diện điều khiển của nó

Vì vậy, ngay sau khi quá trình bắt đầu gọi

[DllImport("Kernel32.dll", SetLastError = true) ] 
static extern uint AttachConsole(int pid); 

và sau đó sử dụng Console.WriteLine đơn giản trong trình xử lý DataReceived của bạn.

+0

Cảm ơn sự giúp đỡ! Tuy nhiên, bất cứ khi nào tôi cố gắng làm điều trên bằng cách sử dụng mã sau đây tôi tiếp tục nhận được một thất bại trong việc đính kèm quá trình ... GetLastError báo cáo mã lỗi 0x31 hoặc thất bại thiết bị chung! Mã: 'uint consoleStatus = Utilities.AttachConsole (appProcess.Id); int lasterr = Marshal.GetLastWin32Error(); MessageBox.Show ("CS:" + consoleStatus.ToString() + "--- ERR:" + lasterr); ' – bethrezan

+0

Xin lỗi vì định dạng kém! Nó dường như không cho phép tôi đưa vào Carriage Returns! – bethrezan

+0

Bạn phải gọi đến attachconsole sau khi quá trình được bắt đầu. Giá trị consoleStatus là gì? Và có lẽ có những chi tiết cụ thể khác mà tôi không biết. – mikalai