2012-10-16 26 views
8

Piszę aplikację w języku C#, która w pewnym momencie uruchamia aplikację jako proces potomny przy użyciu klasy Proces z Asynchroniczne IO przekierowanie, jak pokazano poniżej:Jak asynchronicznie przekierować TYLKO standardowy strumień błędów, a nie standardowy strumień wyjściowy procesu w 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); 
    } 

problem ten kawałek kodu jest to, że podczas gdy ja dostać stderr przekierowywany odpowiednio do mojego tekstowym, to przekierowanie wydaje hide się proces wyjściowe wyjście, którego nie chcę przekierować!

Jeśli przekierowuję standardowe wyjście, widzę, że został poprawnie przekierowany, ale czy nie jest możliwe przekierowanie stderr, a nie standardowe wyjście? Rozejrzałem się i szukałem w Google informacji na ten temat, ale wszystkie dyskusje wydają się być związane z przekierowywaniem stdouta ... takiego jak: How to asynchronously read the standard output stream and standard error stream at once

Byłbym wdzięczny za każdą pomoc dotyczącą tego!

+1

Na pewno nie da się tego zrobić - flagą jest "przekierowanie wszystkich uchwytów", w takim przypadku wszystkie standardowe uchwyty procesów są teraz za ciebie odpowiedzialne. Jeśli chcesz, aby standardowe wyjście zapisywało się na konsoli macierzystej, możesz po prostu je przeczytać, a następnie zapisać je z powrotem tam, gdzie chcesz (np. Konsola). – Justin

+1

Ale jaki jest sens posiadania dwóch poniższych instrukcji, jeśli zawsze jest przekierowywany? ? 'StartInfo.RedirectStandardError = true; StartInfo.RedirectStandardOutput = true lub false // w tym przypadku; 'Również chcę stdout napisać do konsoli dziecka, w przeciwnym razie mogę tylko dodać polecenie Console.WriteLine() w prawym obsługi? – bethrezan

Odpowiedz

2

Nie jest to możliwe, ponieważ jest - przekierowania wyjściowe i błędy są przekierowywane jednocześnie. Artykuł MSDN STARTUPINFO opisuje flagę STARTF_USESTDHANDLES.

Ale jest dobra wiadomość. Zachowanie wyjściowego procesu potomnego jest nadal możliwe. Po prostu trzeba:

  • przekierowaniem wyjścia procesu potomnego
  • dołączyć do konsoli procesu dziecko
  • wyjście proces dziecko
  • odpisać na jego konsoli

Więc zaraz po procesie zacząć powoływać

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

a następnie użyć prostego Console.WriteLine w swojej obsługi DataReceived.

+0

Dzięki za pomoc! Jednak za każdym razem, gdy próbuję wykonać powyższe przy użyciu następującego kodu, nadal otrzymuję błąd w dołączaniu procesu ... GetLastError zgłasza kod błędu 0x31 lub General Device Failure! Kod: 'uint consoleStatus = Utilities.AttachConsole (appProcess.Id); int lasterr = Marshal.GetLastWin32Error(); MessageBox.Show ("CS:" + consoleStatus.ToString() + "--- ERR:" + lasterr); ' – bethrezan

+0

Przepraszamy za słabą formatowania! Wydaje mi się, że nie pozwala mi to na zwrot karetki! – bethrezan

+0

Musisz zadzwonić do attachconsole po uruchomieniu procesów. Co to jest wartość consoleStatus? I prawdopodobnie są inne informacje o OS, których nie jestem świadomy. – mikalai

Powiązane problemy