Sto lavorando con C# e non riesco a capire come leggere stdout in modo asincrono da un processo figlio. Quello che voglio fare è creare un processo figlio che esegua un'applicazione e quindi presenti ciò che viene ricevuto dallo stdout di quel processo in una casella di testo. Devo vedere immediatamente tutti i caratteri di output del processo figlio e non posso aspettare il completamento di una riga, quindi non penso che l'evento Process.OutputDataReceived
soddisfi il mio scopo. Puoi dirmi un modo sano per realizzare questo?C# Leggi lo stdout del processo figlio in modo asincrono
Ho provato a chiamare Process.StandardOutput.BaseStream.BeginRead()
e passare una funzione di richiamata ad esso, ma in questa funzione di richiamata ricevo un'eccezione da Process.StandardOutput.BaseStream.EndRead()
.
Il mio codice è simile al seguente (il processo figlio è un motore di script - abbreviato "SE" -. Per verificare la funzionalità di un dispositivo esterno Gli script vengono eseguiti in sequenza e ogni script richiede un'istanza dell'applicazione SE)
private bool startScript()
{
// Starts the currently indexed script
if (null != scriptList)
{
if (0 == scriptList.Count || scriptListIndexer == scriptList.Count)
{
// If indexer equals list count then there are no active scripts in
// the list or the last active script in the list has just finished
return false; // ## RETURN ##
}
if (ScriptExecutionState.RUNNING == scriptList[scriptListIndexer].executionState)
{
return false; // ## RETURN ##
}
if (0 == SE_Path.Length)
{
return false; // ## RETURN ##
}
SE_Process = new Process();
SE_Process.StartInfo.FileName = SE_Path;
SE_Process.StartInfo.CreateNoWindow = true;
SE_Process.StartInfo.UseShellExecute = false;
SE_Process.StartInfo.RedirectStandardError = true;
SE_Process.StartInfo.RedirectStandardOutput = true;
SE_Process.EnableRaisingEvents = true;
SE_Process.StartInfo.Arguments = scriptList[scriptListIndexer].getParameterString();
// Subscribe to process exit event
SE_Process.Exited += new EventHandler(SE_Process_Exited);
try
{
if (SE_Process.Start())
{
// Do stuff
}
else
{
// Do stuff
}
}
catch (Exception exc)
{
// Do stuff
}
// Assign 'read_SE_StdOut()' as call-back for the event of stdout-data from SE
SE_Process.StandardOutput.BaseStream.BeginRead(SE_StdOutBuffer, 0, SE_BUFFERSIZE, read_SE_StdOut, null);
return true; // ## RETURN ##
}
else
{
return false; // ## RETURN ##
}
}
private void read_SE_StdOut(IAsyncResult result)
{
try
{
int bytesRead = SE_Process.StandardOutput.BaseStream.EndRead(result); // <-- Throws exceptions
if (0 != bytesRead)
{
// Write the received data in output textbox
...
}
// Reset the callback
SE_Process.StandardOutput.BaseStream.BeginRead(SE_StdOutBuffer, 0, SE_BUFFERSIZE, read_SE_StdOut, null);
}
catch (Exception exc)
{
// Do stuff
}
}
void SE_Process_Exited(object sender, EventArgs e)
{
// Keep track of whether or not the next script shall be started
bool continueSession = false;
switch (SE_Process.ExitCode)
{
case 0: // PASS
{
// Do stuff
}
...
}
SE_Process.Dispose(); // TODO: Is it necessary to dispose of the process?
if (continueSession)
{
ts_incrementScriptListIndexer();
if (scriptListIndexer == scriptList.Count)
{
// Last script has finished, reset the indexer and re-enable
// 'scriptListView'
...
}
else
{
if (!startScript())
{
// Do stuff
}
}
}
else
{
ts_resetScriptListIndexer();
threadSafeEnableScriptListView();
}
}
quello che succede è che dopo un processo SE termina ottengo un'eccezione di tipo InvalidOperationException
che dice
StandardOut non è stato reindirizzato o il processo non è ancora iniziata.
dalla chiamata a SE_Process.StandardOutput.BaseStream.EndRead()
. Non capisco perché, perché ho impostato SE_Process.StartInfo.RedirectStandardOutput
prima di iniziare ogni nuovo processo. Mi sembra che se il flusso stdout di un processo uscito chiama la mia funzione read_SE_StdOut()
dopo che il processo è stato eliminato, è possibile?
Grazie per la lettura!
Potrebbe interessarti la libreria [MedallionShell] (https://github.com/madelson/MedallionShell), che semplifica la gestione dei flussi di processo io, in particolare le operazioni asincrone – ChaseMedallion