mayho33
Goto Top

C-Sharp Process.Start und SubProcesses

Hallo @ All,

Ich kämpfe gerade mit SystemDiagnostics.Process.WaitForExit() bei Sub-Prozessen. Leider bin ich weit von einer Lösung entfernt und hoffe auf Hilfe hier im Forum.

Mein Problem im Detail:

Über eine GUI deinstalliere ich einige Programme die ich vorher in einer XML definiert habe. Natürlich sollen nicht alle Progrämmchen gleichzeitig aufgerufen werden. Deshalb warte ich auf das Ende des jeweiligen Prozesses mit SystemDiagnostics.Process.WaitForExit().
Z.B. Firefox verhält sich aber recht unkooperativ weil der HauptProcess ("C:\Program Files\Mozilla Firefox\uninstall\helper.exe") eine andere EXE aus %TMP% called (AU_.exe) und sich sofort wieder beendet. SystemDiagnostics.Process wartet nicht weil der Haupt-Process klarerweise schon beendet ist.

Ich habe versucht die PID für den Main-Prozess auszulesen und davon alle Childs, jedoch ohne Erfolg. mit dem Handle dito.

Meine Frage:

Wie kann ich alle Sub-Processe zum jeweiligen Main überwachen, und das Beenden der Subs abwarten bevor ich aus der Methode() springe??

Ich möchte die Funktionalität so generisch (nicht auf einen bestimmten Prozess festgenagelt) halten, weil sich die Programme die deinstalliert werden sollen immer wieder ändern können.

Für Ideen, Ansätze, CodeSnippeds und natürlich vollständige Lösungen face-winkface-winkface-wink bin ich dankbar!

Grüße,

Mayho

Content-Key: 339438

Url: https://administrator.de/contentid/339438

Ausgedruckt am: 19.03.2024 um 09:03 Uhr

Mitglied: 133417
133417 31.05.2017 aktualisiert um 20:21:28 Uhr
Goto Top
Schau mal hier rein:
https://stackoverflow.com/questions/7189117/find-all-child-processes-of- ...
Das "Killen" natürlich weg denken.

Gruß v.
Mitglied: H41mSh1C0R
H41mSh1C0R 01.06.2017 um 05:09:20 Uhr
Goto Top
Mitglied: mayho33
mayho33 01.06.2017 um 12:31:49 Uhr
Goto Top
Hi @ H41mSh1C0R und vollidiot ,

die hatte ich beide schon versucht. Bekomme bei beiden processList.Count == 0.

hier ein CodeSnipped wie ich das momentan umgesetzt habe. Läuft in einem BackgroundTask. Den habe ich aber hier mal außen vor gelassen:

var return = Execute.This(_uninstallString);

public static class Execute
    {
        public static int This(string startExeFilePath)
        {
            int toReturn                            = 0;
            System.Diagnostics.Process p            = new System.Diagnostics.Process();
            System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
            psi                                     = GetProcessInfo(startExeFilePath);
            p.StartInfo                             = psi;
            try
            {
                
                p.Start();
                while (ProcessHasRunningChilds(p.Id) == true)
                {
                    System.Threading.Thread.Sleep(2000);
                }
                
                p.WaitForExit();
                toReturn = p.ExitCode;
            }
            catch (Exception e)
            {
                MessageBox.Show("Es ist ein Fehler aufgetreten! Sehen sie:" + Environment.NewLine + e.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);  
                toReturn = 1;
            }
            
            return toReturn;
        }

        public static bool ProcessHasRunningChilds(int parentProcessId)
        {
            bool toReturn = false;
            String myQuery = string.Format("select * from win32_process where ParentProcessId={0}", parentProcessId);  
            ObjectQuery objQuery = new ObjectQuery(myQuery);
            ManagementObjectSearcher objSearcher = new ManagementObjectSearcher(objQuery);
            ManagementObjectCollection processList = objSearcher.Get();


            if (processList.Count > 0)
                toReturn = true;
            
            return toReturn;
        }

        public static System.Diagnostics.ProcessStartInfo GetProcessInfo(string startExeFilePath)
        {
            System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
            string _startExeFilePath    = Regex.Replace(startExeFilePath, @"([""])", "");  
            string extension            = Path.GetExtension(_startExeFilePath);
            switch (extension)
            {
                case ".vbs":  
                    psi.CreateNoWindow  = false;
                    psi.UseShellExecute = true;
                    psi.WindowStyle     = System.Diagnostics.ProcessWindowStyle.Normal;
                    psi.FileName        = "cmd.exe";  
                    psi.Arguments       = "cscript " + (char)34 + _startExeFilePath + (char)34;  
                    break;
                case ".cmd":  
                case ".bat":  
                    psi.CreateNoWindow  = false;
                    psi.UseShellExecute = true;
                    psi.WindowStyle     = System.Diagnostics.ProcessWindowStyle.Normal;
                    psi.FileName        = "cmd.exe";  
                    psi.Arguments       = (char)34 + _startExeFilePath + (char)34;
                    break;
                case ".ps1":  
                    psi.CreateNoWindow  = false;
                    psi.UseShellExecute = false;
                    psi.WindowStyle     = System.Diagnostics.ProcessWindowStyle.Normal;
                    psi.FileName        = "powershell.exe";  
                    psi.Arguments       = (char)34 + _startExeFilePath + (char)34;
                    break;
                case ".exe":  
                    psi.CreateNoWindow  = false;
                    psi.UseShellExecute = false;
                    psi.WindowStyle     = System.Diagnostics.ProcessWindowStyle.Normal;
                    psi.FileName        = (char)34 + _startExeFilePath + (char)34;
                    break;
                case ".msi":  
                    psi.CreateNoWindow  = false;
                    psi.UseShellExecute = false;
                    psi.WindowStyle     = System.Diagnostics.ProcessWindowStyle.Normal;
                    psi.FileName        = "msiexec.exe";  
                    psi.Arguments       = "/i " + (char)34 + _startExeFilePath + (char)34 + " ALLUSERS=1, RESTART=REALLYSUPPRESS /norestart MSIRESTARTMANAGERCONTROL=Disable";  
                    break;
            }
            return psi;
        }
}

Güße, Mayho
Mitglied: mayho33
mayho33 07.06.2017 aktualisiert um 11:31:48 Uhr
Goto Top
Hi @ All!

Ich habe nun eine Lösung. Sie ist zwar nicht unbedingt "smart" aber funktioniert auch mit Exoten-Setups ala Firefox aka NullSoft-Installer usw. welche sich an keinen einzigen Punkt der MS-Whitelist für Microsoft Installer halten hier und hier :

Vor Process.Start() erstelle ich einen Snapshot aller laufenden Prozesse und hole mir DateTime(now).Ticks
Nach Process.WaitForExit() mache ich das gleiche und erstelle ein Diff der Prozess-Liste und Ticks.

Ist das Diff der Ticks kleiner 5000 (0,5 Millisekunden) gehe ich davon aus, dass Process nicht gewartet hat und laufe solange in einer Schleife bis Diff in einer aktuelle Liste der laufenden Prozesse nicht mehr vorkommt.

Beenden der Schleife, alles fertig abarbeiten.

Danke für eure Unterstützung! Das "Zur Lösung beigetragen"-Tag darf ich mir dieses mal selbst anheften face-wink. Auch mal was Schönes face-wink

Grüße Mayho