Doppelte Instanz eines Programmes beenden.

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Doppelte Instanz eines Programmes beenden.

Beitrag von NicTheQuick »

Wenn man den Code startet kommt zunächst eine Meldung, dass das Server-Programm gestartet wurde. Diese einfach bestätigen. Das ist dann sozusagen das Programm, von dem nicht mehr als eine Instanz gestartet werden soll.
Wenn man den Code bei laufendem Server-Programm dann nochmal startet, wird das Client-Programm gestartet. Das ist ein kleiner InputRequester, mit dem man Befehle an das Server-Programm schicken kann. Es gibt die folgenden Befehle:
  • 'beenden' - Beendet das Serverprogramm
  • 'sichtbar' - Macht das Server-Programmfenster sichtbar
  • 'unsichtbar' - Macht das Server-Programmfenster unsichtbar
  • etwas anderes - Schreibt den Text in das Log-Fenster des Serverprogramms
  • nichts - Beendet das Client-Programm. Server-Programm läuft weiter, wenn es nicht zuvor beendet wurd.
Den Code kann man zum Beispiel dafür verwenden, wenn man sein Programm mit einem Dateityp verknüpft hat. Wenn man jetzt mehrere Dateien diesen Dateityps im Explorer nacheinander öffnet würden mehrere Instanzen dieses Programmes gestartet werden. Das ist aber meistens unerwünscht. Nachdem die erste Datei geöffnet wurde und dann die zweite folgt, gibt diese zweite temporäre Instanz der ersten Instanz des Programmes nur noch Befehl die aufgerufene Datei zu öffnen oder in die Queue anzuhängen über den Window-Callback.

Aber was ihr dann wirklich damit macht ist eure Sache. Viel Spaß mit dem Code. Auch wenn er nicht wirklich kommentiert ist. Aber funktionieren tut er auf jeden Fall.

Wer Speicherlecks oder nicht geschlossene Resourcen findet, bitte melden. Ich ändere das dann direkt.

Das hier ist der Code. Er stammt aus dem PBOR (PureBoard-Backup-Offline-Reader) und ist etwas abgeändert. Ich weiß leider nicht mehr, wer mir damals dabei geholfen hat.

Code: Alles auswählen

;- Variablen und Konstanten aus Common.pbi
#ProgramName = "Programm"
#Win_Main = 0
#Win_OneInstance = 1
Global NewParameter.l, Parameter.s



Global FBOR_Msg_RunOnce.l, FBOR_OneInstance_Mutex.l
Global OneInstance_AlreadyRunning.l

#FBOR_Msg_Request = 0
#FBOR_Msg_Reply = 1

FBOR_Msg_RunOnce = RegisterWindowMessage_(#ProgramName + "_Msg_RunOnce")

FBOR_OneInstance_Mutex = CreateMutex_(0, 0, #ProgramName + "_OneInstance_Mutex")
If GetLastError_() = #ERROR_ALREADY_EXISTS
  OneInstance_AlreadyRunning = #True
Else
  OneInstance_AlreadyRunning = #False
EndIf
  
Procedure OneInstance_IsRunning()
  ProcedureReturn OneInstance_AlreadyRunning
EndProcedure

Procedure OneInstance_End()
  ReleaseMutex_(FBOR_OneInstance_Mutex)
EndProcedure

Procedure OneInstance_Close()
  CloseHandle_(FBOR_OneInstance_Mutex)
EndProcedure

Procedure OneInstance_SendParameter(Text.s)
  Protected EventID.l, CopyData.COPYDATASTRUCT
  
  If OpenWindow(#Win_OneInstance, 0, 0, 0, 0, #PB_Window_Invisible, #ProgramName)
    PostMessage_(#HWND_BROADCAST, FBOR_Msg_RunOnce, #FBOR_Msg_Request, WindowID(#Win_OneInstance))
    
    SetTimer_(WindowID(#Win_OneInstance), 0, 5000, 0)
    
    Repeat
      EventID = WaitWindowEvent()
      
      If EventID = #WM_TIMER
        Break
        
      ElseIf EventID = FBOR_Msg_RunOnce And EventwParam() = #FBOR_Msg_Reply
        CopyData\cbData = Len(Text)
        CopyData\lpData = @Text
        
        SendMessage_(EventlParam(), #WM_COPYDATA, WindowID(#Win_OneInstance), @CopyData)
        Break
      EndIf
    ForEver
    
    CloseWindow(#Win_OneInstance)
  EndIf
EndProcedure

Procedure OneInstance_Callback(hWindow.l, Message.l, wParam.l, lParam.l)
  Protected *CopyData.COPYDATASTRUCT
  
  Result = #PB_ProcessPureBasicEvents
  
  Select Message
    Case #WM_COPYDATA
      *CopyData = lParam
      
      Parameter = PeekS(*CopyData\lpData, *CopyData\cbData)
      If Parameter <> ""
        NewParameter = #True
      EndIf
      
      Result = #True
    
    Case FBOR_Msg_RunOnce
      If wParam = #FBOR_Msg_Request
        PostMessage_(lParam, FBOR_Msg_RunOnce, #FBOR_Msg_Reply, WindowID(#Win_Main))
      EndIf
  EndSelect
  
  ProcedureReturn Result
EndProcedure

If OneInstance_IsRunning()
  Repeat
    Text.s = InputRequester("Info", "'sichtbar', 'unsichtbar', 'beenden' oder nichts zum Beenden.", "")
    OneInstance_SendParameter(Text)
  Until Text = ""
  OneInstance_Close()
  End
EndIf

MessageRequester("Info", "Das Server-Programm wurde gestartet.")

If OpenWindow(#Win_Main, 0, 0, 500, 200, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, #ProgramName)
  SetWindowCallback(@OneInstance_Callback())
  If CreateGadgetList(WindowID(0))
    EditorGadget(0, 0, 0, 500, 200)
    AddGadgetItem(0, -1, "Programm gestartet. Fenster sichtbar.")
    Repeat
      If NewParameter
        NewParameter = #False
        Select LCase(Parameter)
          Case "sichtbar"
            HideWindow(#Win_Main, 0)
            AddGadgetItem(0, -1, "Fenster wieder sichtbar.")
            
          Case "unsichtbar"
            HideWindow(#Win_Main, 1)
            AddGadgetItem(0, -1, "Fenster unsichtbar.")
            
          Case "beenden" : Break
            AddGadgetItem(0, -1, "Programm wieder in 3 Sekunden beendet.")
            While WindowEvent() : Wend
            Delay(3000)
            
          Default
            AddGadgetItem(0, -1, "Text: " + Parameter)
            
        EndSelect
      EndIf
      Delay(1)
    Until WindowEvent() = #PB_EventCloseWindow
  EndIf
EndIf

OneInstance_End()

MessageRequester("Info", "Das Server-Programm wurde beendet.")
Bild
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: Doppelte Instanz eines Programmes beenden.

Beitrag von NicTheQuick »

Kann mal jemand schauen, ob der Code noch unter Windows geht? Oder muss man was am Code ändern?

Jaja, ich weiß. Leichenschänderei und so. :P
Bild
Benutzeravatar
Josh
Beiträge: 1028
Registriert: 04.08.2009 17:24

Re: Doppelte Instanz eines Programmes beenden.

Beitrag von Josh »

Um es mal lauffähig zu bekommen:

- bei den beiden OpenWindow Titel und Flags austauschen
- #PB_EventCloseWindow gegen #PB_Event_CloseWindow tauschen
- CreateGadgetList entfernen

Sonst noch nichts getestet
Benutzeravatar
Imhotheb
Beiträge: 192
Registriert: 10.10.2014 13:14
Computerausstattung: Intel 8086, 640 KB RAM, Hercules Video Adapter, 2 x 5 1/4" 360kb Floppy, MS-DOS 3
Wohnort: Wolfenbüttel

Re: Doppelte Instanz eines Programmes beenden.

Beitrag von Imhotheb »

Ich hab mal den Titel mit den Flags und #PB_EventCloseWindow gegen #PB_Event_CloseWindow vertauscht. CreategadgetList habe ich erstmal ignoriert.

PB 5.31/x86 auf Win 7 64Bit

Mit Unicode
Ausgabe des "Servers"

Code: Alles auswählen

Programm gestartet. Fenster sichtbar.
Text: sich궷璟
Text: unsic
Text: sich궷璟
Text: been궷璟
ohne Unicode scheint es zu funktionieren
Ausgabe des Servers:

Code: Alles auswählen

Programm gestartet. Fenster sichtbar.
Fenster unsichtbar.
Fenster wieder sichtbar.
Bei "beenden" geschiet nichts.
weil einfach einfach einfach ist ... mach' ich es anders
Antworten