Richtiges Vorgehen zum Beenden einer vorherigen Instanz

  • VB.NET

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von Achilleus.

    Richtiges Vorgehen zum Beenden einer vorherigen Instanz

    Hallo Leute,

    ich habe eine kleine Mini-Konsolenanwendung und muss bei einigen Aufrufen verhindern, dass es eine zweite Instanz gibt.
    Hierzu habe ich folgende Programmroutine erstellt, die auch funktioniert.

    VB.NET-Quellcode

    1. ' Anwendung bereits gestartet?
    2. Public Function CleanAppPrevInstance(Optional ByVal bShowMsg As Boolean = True, Optional ByVal bAppActivate As Boolean = True) As Boolean
    3. Dim p() As Process
    4. Dim appName As String = Process.GetCurrentProcess.ProcessName
    5. p = Process.GetProcessesByName(appName)
    6. If p.Count > 1 Then
    7. ' Process is running
    8. If bShowMsg Then
    9. Select Case MessageBox.Show("Das Programm Crypto kann nicht mehrfach gestartet werden." & vbNewLine _
    10. & "Die vorherige Instanz muss geschlossen werden." & vbNewLine _
    11. & "" & vbNewLine _
    12. & "Möchten Sie fortfahren?", "Mehrfachstart von Crypto", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
    13. Case DialogResult.Yes
    14. Application.DoEvents()
    15. Process.GetProcessesByName(appName)(1).Kill()
    16. Return True
    17. Case DialogResult.No
    18. Return False
    19. End Select
    20. End If
    21. End If
    22. Return True
    23. End Function


    Meine Frage ist nun, ist das auch wirklich ein sauberes vorgehen oder gibt es eine bessere Lösung? ?(

    Vielen Dank im Voraus.

    Gruß Achilleus
    @Achilleus Besser ist es, Du arbeitest mit einem Mutex, da bekommst Du beim Start mitgeteilt, ob schon eine Instanz läuft.
    Ich hab ein Beispiel in C# für WinForm, das musst Du dann an Deine Bedürfnisse anpassen:
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Diagnostics;
    3. using System.Runtime.InteropServices;
    4. using System.Threading;
    5. using System.Windows.Forms;
    6. namespace DeviceControl
    7. {
    8. static class Program
    9. {
    10. /// <summary>
    11. /// Prozeduren zur Anzeige der ersten instanz
    12. /// </summary>
    13. private static class NativeMethods
    14. {
    15. [DllImport("User32.dll")]
    16. [return: MarshalAs(UnmanagedType.Bool)]
    17. internal static extern bool SetForegroundWindow(IntPtr hWnd);
    18. [DllImport("User32.dll")]
    19. [return: MarshalAs(UnmanagedType.Bool)]
    20. internal static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
    21. }
    22. //----------------------------------------------------------
    23. /// <summary>Der Haupteinstiegspunkt für die Anwendung.</summary>
    24. [STAThread]
    25. static void Main()
    26. {
    27. Application.EnableVisualStyles();
    28. Application.SetCompatibleTextRenderingDefault(false);
    29. bool isFirstInstance;
    30. // Please use a unique name for the mutex to prevent conflicts with other programs
    31. using (Mutex mtx = new Mutex(true, "Application Test", out isFirstInstance))
    32. {
    33. if (isFirstInstance)
    34. {
    35. Application.Run(new MainForm());
    36. }
    37. else
    38. {
    39. // The application is already running
    40. // TODO: Display message box or change focus to existing application instance
    41. MessageBox.Show("Application already running!", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
    42. Process current = Process.GetCurrentProcess();
    43. foreach (Process process in Process.GetProcessesByName(current.ProcessName))
    44. {
    45. if (process.Id != current.Id)
    46. {
    47. // Fenster des Prozesses in den Vordergrund holen
    48. NativeMethods.SetForegroundWindow(process.MainWindowHandle);
    49. NativeMethods.ShowWindowAsync(process.MainWindowHandle, 9);
    50. break;
    51. }
    52. }
    53. }
    54. } // releases the Mutex
    55. }
    56. }
    57. }
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hallo @RodFromGermany,

    vielen Dank für die Info.
    Ich werde mir das einmal in Ruhe anschauen und versuchen es umzusetzen.

    Ich wunder mich immer wieder, was es alles gibt. :D

    Gruß Achilleus



    Hallo @RodFromGermany,

    also ich habe es nicht hinbekommen, aber ich habe meine Programmroutine etwas verändert.

    VB.NET-Quellcode

    1. Public Function CleanAppPrevInstance(Optional ByVal bShowMsg As Boolean = True, Optional ByVal bAppActivate As Boolean = True) As Boolean
    2. Dim current As Process = Process.GetCurrentProcess()
    3. For Each process As Process In Process.GetProcessesByName(current.ProcessName)
    4. If process.Id <> current.Id Then
    5. If bShowMsg Then
    6. Select Case MessageBox.Show("Das Programm Crypto kann nicht mehrfach gestartet werden." & vbNewLine _
    7. & "Die vorherige Instanz muss geschlossen werden und es werden alle eingefügten Dateien gelöscht." & vbNewLine _
    8. & "" & vbNewLine _
    9. & "Möchten Sie fortfahren?", "Mehrfachstart von Crypto", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
    10. Case DialogResult.Yes
    11. Application.DoEvents()
    12. process.Kill()
    13. Return True
    14. Case DialogResult.No
    15. Return False
    16. End Select
    17. End If
    18. Exit For
    19. End If
    20. Next
    21. Return True
    22. End Function


    Nun taucht aber ein anderes Problem auf und zwar befindet sich mein Programm im Netz und wir haben eine Terminalsystem.
    Anscheinend meldet mein Programm jetzt auch eine zweite Instanz an, wenn ein anderer Nutzer mein Programm gestartet hat.

    Ich bräuchte das ja aber nur, wenn ich selber eine zweite Instanz öffnen möchte. Es muss doch so etwas wie Owner geben oder?

    Hast du oder auch andere eine Idee hierzu?
    Das wäre mir schon sehr wichtig.

    Vielen Dank im Voraus.

    Gruß Achilleus

    Beiträge zusammengefügt. ~Thunderbolt

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Thunderbolt“ ()

    Achilleus schrieb:

    und zwar befindet sich mein Programm im Netz und wir haben eine Terminalsystem.
    Solch unwichtige Information gehört in den eröffnungspost :!:
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich mach das so, dass mein Programm eine leere Datei X erstellt und diese geöffnet lässt. Wenn eine 2. Instanz im Netz gestartet wird, versucht die 2. Instanz, die Datei X zu löschen. Wenn es geht, läuft die 2. Instanz alleine im Netz, wenn eine Zugriffsverletzung kommt, läuft logischerweise noch die 1. Instanz im Netz.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Ihr solltet euch zweimal überlegen, ob ihr einen Mutex verwendet.
    Wenn Programm A schon auf dem Server aktiv ist und ihr entwickelt ein Programm B, das auch auf dem Server laufen soll, dann kann es passieren, dass Programm B Schwierigkeiten bekommt. Ich hatte das auf der Arbeit. Der Trick ist dann, Objekte zu nutzen, die mehrere Threads vertragen, wie z.B. ein Concurrent Dictionary
    . (Ja, ich weiß, ist nicht das Thema).

    Ich prüfe wie folgt, ob bereits eine Programminstanz läuft:
    ​bool anotherInstanceOfTheProgramIsRunning = System.Diagnostics.Process.GetProcessesByName(System.IO.Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetEntryAssembly().Location)).Count() > 1;
    GetProcessesByName dürfte aber nur auf dem lokalen PC funktionieren, oder?

    ##########

    Ah, es gibt ja ne Überladung mit Angabe des ZielPCs, auch wenn Du diese anscheinend nicht nutzt.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „VaporiZed“ ()

    Also ich habe den Lösungsvorschlag von @VaporiZed mit einer Lockdatei genommen, die ich einfach mit einem Streamwriter öffne und erst beim Beenden schließe und lösche. Das Verzeichnis überwache ich mit einem Filesystemwatcher, sodass ich die Änderungen im Verzeichnis auch von außen mitbekomme. Das funktioniert in den ersten Tests einwandfrei und ich kann damit den Aufruf einer 2. Instanz sinnvoll verhindern.

    Für diese kleine Anwendung ist meine Lösung völlig ausreichend. Ist am einfachsten und am sichersten so.

    Vielen Dank noch einmal an alle für Eure Unterstützung.

    Gruß Achilleus