Programm nur einmal starten



  • In der Suche finde ich nichts hilfreiches, daher frag ich einfach kurz und knapp: Wie kann ich bei meinem Programm "einstellen", dass es nur einmal gestartet werden kann (Unter Windows)?



  • Was meinst du mit "nur einmal starten"? Du könntest das Programm so schreiben, daß es sich bei Programmende von der Platte löscht, dann kann es kein zweites Mal gestartet werden 😃 *scnr*





  • hrhr, aber nee, das ist nicht was ich meinte. was ich meine ist, dass wenn ich das programm schon einmal ausgeführt habe (also noch am ausführen bin) darf es sich nicht ein zweites mal öffnen wenn ich auf die .exe klicke



  • Verhindern, daß jemand zweimal startet, kannst du nicht (zumindest nicht in einem Multi-Tasking-OS). Du kannst nur beim Programmstart feststellen, ob schon eine Version des Programms läuft - und wenn ja, dich kommentarlos wieder beenden (und die bereits offene Version in den Vordergrund schieben).

    Lösungsansätze zu dem Ziel findest du hinter dem Link, den scnr dort ^^ gepostet hat.



  • Dieser Thread wurde von Moderator/in HumeSikkins aus dem Forum C++ in das Forum WinAPI verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • danke für die antworten, ich habs mir mal angeguckt und es hat geklappt. aber nun möchte ich versuchen falls das programm schon gestartet ist es im vordergrund zu bringen, daher meine frage wie krieg ich die hWnd von einem existierenden mutex objekt raus (aus dem beispiel von den link der gepostet wurde werde ich net ganz schlau)?



  • Zu dem Mutex hast du keinen hWnd. Und Windows weiß noch nichtmal, ob der Mutex-Besitzer einen hWnd hat.

    Wenn du ein Fenster-Handle benötigst, müsstest du über FindWindow() das bereits bestehende Programmfenster suchen. Alternativ kannst du auch einen Event setzen und am anderen Ende überwachen (die erste Inkarnation richtet den Event ein und fragt ihn z.B. in der Idle-Verarbeitung ab, die zweite Inkarnation aktiviert den Event, bevor sie sich wieder verabschiedet).



  • mit FindWindow() kann man sich aber nicht sicher sein ob das nun wirklich das fenster ist was man sucht oder? man könnte z.b ja ein cmd fenster den gleichen title wie das programm was ich suche geben. und mit dem event weiß ich nicht wie ich das umsetzen soll, gibt es keine einfache lösung um ein programm zu identifizieren?



  • slump schrieb:

    mit FindWindow() kann man sich aber nicht sicher sein ob das nun wirklich das fenster ist was man sucht oder? man könnte z.b ja ein cmd fenster den gleichen title wie das programm was ich suche geben.

    FindWindow() liefert dir zumindest schonmal einen möglichen Kandidaten für das Zielfenster. Als nächstes könntest du dieses Fenster fragen, ob es das "richtige" ist (eine Lösung ist es, dem gefundenen Fenster eine WM_USER+x Nachricht zu schicken und auszuwerten, was es antwortet)

    *nachsieht* Genau so arbeitet auch das Beispielprogramm von oben 😃

    und mit dem event weiß ich nicht wie ich das umsetzen soll, gibt es keine einfache lösung um ein programm zu identifizieren?

    Das könntest du so ähnlich machen wie mit dem Mutex.



  • Wenn ich Dich richtig verstanden habe, möchtest Du nur, daß Dein Programm nur einmal im System geladen und gestartet wurde.
    Wenn das so ist, würde ich den folgenden Weg empfehlen, dieser ist auch sehr sicher (keine Zweideutigkeiten bei FindWindow() usw.):

    1.) Deine Applikation MyApp1 richtet einen Mutex ein.
    2.) Wenn dieser Mutex bereits existiert (also Deine Applikation läuft bereits schon länger als MyApp2 im System), schickt Deine Applikation MyApp1 an ALLE Prozesse eine von Dir selbst definierte Nachricht und beendet sich daraufhin.
    3.) Die (bereits laufende) Applikation MyApp2 empfängt diese selbst definierte Nachricht, überprüft sie auf Plausibilität und bringt sein eigenes Fenster in den Vordergrund.
    4.) That's all, kein Gehampel mit hWnd oder Namenskonflikte bei FindWindow() usw.

    Du solltest bei Punkt 3.) wissen, daß Du bei Bedarf die API-Funktion SetForegroundWindow() über AttachThreadInput() realisieren sollst!

    Gruß
    Martin

    Folgenden Code implementierst Du am besten bei der Initialisierung in WinMain():

    uint32 ui32_registered_message_id_UWM_ARE_YOU_ME;
    TCHAR tcharsz_255stellen[255 + 1];
    HANDLE handle_mutex_multiple_instance;
    #define TCHARSZ_APPGUID  TEXT( "MyApp AppGUID {7CB1F734-9A34-944e-72AA-AFEFF2370962}" )
                                                                  //Diese Zeichenfolge ist eine GUID, damit haben wir weltweit eine einigermaßen einmalige Identifikation. (googeln falls mehr Infos nötig!)
    
    //********************************************************
    //** Prüfen ob die Applikation mehrfach gestartet wurde **
    //********************************************************
    strcpy( tcharsz_255stellen, TEXT( "UWM_ARE_YOU_ME " ) );
    strcat( tcharsz_255stellen, TCHARSZ_APPGUID );
    ui32_registered_message_id_UWM_ARE_YOU_ME = RegisterWindowMessage( tcharsz_255stellen );
                                                                  //Meine eigene Nachricht selbst definieren.
    strcpy( tcharsz_255stellen, TCHARSZ_APPGUID );
    handle_mutex_multiple_instance = CreateMutex( NULL, FALSE, tcharsz_255stellen );
                                                                  //Mutex erzeugen.
    if ( ( handle_mutex_multiple_instance == NULL )
         || ( GetLastError() == ERROR_ALREADY_EXISTS )            //Mutex existiert bereits -> Ende.
         || ( GetLastError() == ERROR_ACCESS_DENIED ) )           //In Umgebeung mit mehreren Usern schlägt Aufruf CreateMutex()
                                                                  //wegen Wert NULL für Parameter lpMutexAttributes fehl!
    {
      //Eine andere MyApp ist bereits aktiv -> Dieser Applikation eine Nachricht über Broadcast schicken (um z.B. dessen Fenster
      //in Vordergrund zu bringen oder wieder sichtbar zu machen). Anschließend werde ich mich selbst beenden.
      SendMessageTimeout( HWND_BROADCAST, ui32_registered_message_id_UWM_ARE_YOU_ME,
                          (WPARAM)0, (LPARAM)0, SMTO_BLOCK | SMTO_ABORTIFHUNG, 200, &dword_result );
      Programm_ende_mit_free_memory( -1, NULL );                    //Ein Fehler ist aufgetreten, Abbruch
                                                                    //des Programms ohne Fehlermeldung.
    }
    
    //Ab hier Initialisierung fortsetzen, z.B. Fenster definieren ....
    

    Folgenden Code baust Du in die Window-Prozedur ein:

    LRESULT CALLBACK Procedure_Window( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
    {
    ...
    
    if ( message == ui32_registered_message_id_UWM_ARE_YOU_ME )
    {
      //*******************************************************************
      //** Es wurde versucht, die gleiche Appikation mehrfach zu starten **
      //*******************************************************************
      Bring_Window_To_Top( ptr_hwnd_frame );                        //Das eigene Fenster in den Vordergrund bringen.
      return( 0 );
    }
    
    //Ab hier kommt die klassische Message-Auswertung.
    switch ( message )
    {
      case WM_CREATE:
      //*******************************************
      //** Das Applikationsfenster wurde erzeugt **
      //*******************************************
      ...
      ...
      break;
    
      case WM_DESTROY:
      //*************************************************************
      //** Ein Klick auf Schließfeld der Titelleiste oder "Alt+F4" **
      //*************************************************************
      PostQuitMessage( 0 );
      return( 0 );
      break;
    }
    
    return( DefWindowProc( ptr_hwnd_frame, message, wParam, lParam ) );
                                                                    //Die Routine DefWindowProc() übernimmt die Bearbeitung
                                                                    //aller Nachrichten, um die wir uns nicht gekümmert haben.
    } //Ende von Procedure_Window().
    

Anmelden zum Antworten