3 Pluspunkte 0 Minuspunkte

Ich rufe über einen asynchronen Task ein Powershell Script als Prozess auf und lese die Ausgabe des Prozess in eine Variable.

private async Task FetchProcesses(string serverName)
{
    try
    {
        dataGridView1.Rows.Clear();

        var psi = new ProcessStartInfo
        {
            FileName = "powershell.exe",
            //Arguments = "-ExecutionPolicy Bypass -NoProfile -Command \"Get-WMIObject -Class Win32_Service -computername " + serverName + " | select Name,StartMode,State,Status | ConvertTo-Csv -Delimiter ';' -NoTypeInformation | Select-Object -Skip 1\"",
            Arguments = "-ExecutionPolicy Bypass -NoProfile -Command \"Get-WMIObject -Class Win32_Service -ComputerName " + serverName + " | ForEach-Object { '{0};{1};{2};{3}' -f $_.Name, $_.StartMode, $_.State, $_.Status }\"",
            RedirectStandardOutput = true,
            UseShellExecute = false,
            CreateNoWindow = true
        };

        Process process = new Process { StartInfo = psi };

        // Hier sagst du dem Prozess, dass er für empfangene Daten deine Methode aufruft
        process.OutputDataReceived += Process_OutputDataReceived;

        process.Start();
        process.BeginOutputReadLine();
        await Task.Run(() => process.WaitForExit());
    }
    catch (Exception ex)
    {
        MessageBox.Show("Fehler beim Abrufen der Prozessinformationen: " + ex.Message, "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }

}

Dabei wird mit

process.OutputDataReceived += Process_OutputDataReceived;

jeder empfangene Datensatz in Echtzeit in einen DataGridView geschrieben. Das Problem ist das sich das Programm aufhängt wenn man das Form schließt während die Daten noch in den DataGridView eingetragen werden. Kann man das irgendwie umgehen ohne auf das asynchrone Laden zu verzichten?

von  

3 Antworten

0 Pluspunkte 0 Minuspunkte

Du kannst in der Invoke Methode prüfen ob das Handle auf das Form noch existiert.

if (this.IsHandleCreated && !this.IsDisposed)
{
    this.Invoke(new Action(() =>
    {
        if (!this.IsDisposed) // Zusätzliche Sicherheitsprüfung
        {
            dataGridView1.Rows.Add(
                values[0].Trim(), // Name
                values[1].Trim(), // StartMode
                values[2].Trim(), // State
                values[3].Trim()  // Status
            );
        }
    }));
}
von (1.1k Punkte)  
0 Pluspunkte 0 Minuspunkte

Eine Möglichkeit wäre, den Prozess als Variable zu speichern und beim Schließen des Form zu prüfen ob der Prozess noch läuft. Falls ja, kannst du den Prozess abbrechen.

private Process runningProcess;

private async Task FetchProcesses(string serverName)
{
    try
    {
        dataGridView1.Rows.Clear();

        var psi = new ProcessStartInfo
        {
            FileName = "powershell.exe",
            Arguments = "-ExecutionPolicy Bypass -NoProfile -Command \"Get-WMIObject -Class Win32_Service -ComputerName " + serverName + " | ForEach-Object { '{0};{1};{2};{3}' -f $_.Name, $_.StartMode, $_.State, $_.Status }\"",
            RedirectStandardOutput = true,
            UseShellExecute = false,
            CreateNoWindow = true
        };

        runningProcess = new Process { StartInfo = psi };
        runningProcess.OutputDataReceived += Process_OutputDataReceived;
        runningProcess.Start();
        runningProcess.BeginOutputReadLine();
        await Task.Run(() => runningProcess.WaitForExit());
    }
    catch (Exception ex)
    {
        MessageBox.Show("Fehler beim Abrufen der Prozessinformationen: " + ex.Message, "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

private void Services_FormClosing(object sender, FormClosingEventArgs e)
{
    if (runningProcess != null && !runningProcess.HasExited)
    {
        runningProcess.Kill();
        runningProcess.Dispose();
    }
}
von (844 Punkte)  
0 Pluspunkte 0 Minuspunkte

Am Einfachsten wäre Invoke durch BeginInvoke zu ersetzen und zusätzlich das Handle auf das Form zu prüfen.

if (this.IsHandleCreated && !this.IsDisposed)
{
    this.BeginInvoke(new Action(() =>
    {
        if (!this.IsDisposed)
        {
            dataGridView1.Rows.Add(
                values[0].Trim(), // Name
                values[1].Trim(), // StartMode
                values[2].Trim(), // State
                values[3].Trim()  // Status
            );
        }
    }));
}
von (1.3k Punkte)