Singleton funktioniert nicht :(

  • _singleton geht nicht unter win 7 64

    ich habe folgendes script, was leider nicht das multiple ausführen des scriptes verhindert:

    [autoit]


    #include <Misc.au3>
    Global $ToolTitle = "xyz";

    [/autoit][autoit][/autoit][autoit]

    _checkMutex($ToolTitle)

    [/autoit][autoit][/autoit][autoit]

    Func _checkMutex($TileofWin)
    if _Singleton($TileofWin,1) = 0 Then
    Msgbox(16,"Warning", $TileofWin&" is already running.", 10)
    Exit
    EndIf
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    While 1
    Sleep(3)
    WEnd

    [/autoit]


    hat jemand eine lösung ?


    EDIT:
    Habe gerade selber eine PID basierende lösung gefunden... wer sie gerne benutzen möchte:

    [autoit]

    Local $iSingleton = _SingletonPID('myUniqueName', 1)

    [/autoit][autoit][/autoit][autoit]

    If $iSingleton = 0 Then
    MsgBox(4096, '', 'This is the first instance of the program running: ' & $iSingleton)
    Else
    MsgBox(4096, '', 'There is another instance running. This PID is: ' & $iSingleton)
    EndIf

    [/autoit][autoit][/autoit][autoit][/autoit][autoit][/autoit][autoit]

    ; #FUNCTION# ====================================================================================================================
    ; Name ..........: _SingletonPID
    ; Description ...: Enforce a design paradigm where only one instance of the script may be running.
    ; Syntax ........: _SingletonPID($sOccurenceName[, $iFlag = 0])
    ; Parameters ....: $sOccurenceName - String to identify the occurrence of the script.
    ; $iFlag - [optional] Optional parameters. Default is 0.
    ; 0 - Exit the script with the exit code -1 if another instance already exists.
    ; 1 - Return the PID of the main executable and without exiting the script too.
    ; Return values .: Success - 0 No other process is running.
    ; Failure - The PID of the main executable.
    ; Author ........: guinness with initial ideas by Valik for _Singleton & KaFu for _EnforceSingleInstance.
    ; Example .......: Yes
    ; ===============================================================================================================================
    Func _SingletonPID($sOccurenceName, $iFlag = 0)
    Local $hWnd = WinGetHandle($sOccurenceName)
    If @error Then
    AutoItWinSetTitle($sOccurenceName)
    $hWnd = WinGetHandle($sOccurenceName)
    ControlSetText($hWnd, '', ControlGetHandle($hWnd, '', 'Edit1'), @AutoItPID)
    Else
    If BitAND($iFlag, 1) Then
    Return Number(ControlGetText($hWnd, '', ControlGetHandle($hWnd, '', 'Edit1')))
    Else
    Exit -1
    EndIf
    EndIf
    Return 0
    EndFunc ;==>_SingletonPID

    [/autoit]

    4 Mal editiert, zuletzt von WhiteLion (26. Februar 2013 um 14:37)

  • Das geht viiiiiel kürzer ;)

    [autoit]


    $iInstance = ProcessList("DeinProgrammName.exe")
    If $iInstance[0][0] > 1 Then
    Exit
    EndIf

    [/autoit][autoit][/autoit][autoit]

    ; Weiterer Code

    [/autoit]

    Läuft natürlich nur, wenn es schon kompiliert ist.

    Da es hier doch einige falsch machen:

    Zitat von einem User dieses Forums

    Die Standard-Standart eines Flamingos ist einbeinig. ;)

  • Joriktos Das ist aber eine unsaubere Lösung...

    WhiteLion Kannst du mal beschreiben was nicht funktionieren soll? Dein Script lässt sich bei mir nicht 2 mal ausführen. Auch wenn das jetzt gelöst ist, würde mich interessieren was das eigentliche Problem war.

  • Eine alternative währ:
    Theorie:
    Alle Prozesse auflisten und aus deren Datei ein (Md5) Hashwert ziehen
    und kontrollieren ob eine mit der von dem eigenem Programm übereinstimmt.
    (grad keine zeit für ein beispiel)

    Sind TV-Quizfragen zu einfach? A) Ja B) Harry Potter

    Spoiler anzeigen

    Ich gebe zu dieser Post hat wahrscheinlich nicht viel geholfen,
    aber ich versuche wenigstens zu helfen :rolleyes:

  • Zitat von name22


    Joriktos Das ist aber eine unsaubere Lösung...

    Und warum? Sie sollte doch in fast allen Fällen funktionieren, oder?

    Da es hier doch einige falsch machen:

    Zitat von einem User dieses Forums

    Die Standard-Standart eines Flamingos ist einbeinig. ;)

  • Joriktos
    Wenn du schon sagst das es auch "viiiiiel kürzer" geht hättest du dann aber auch die 1-Zeilenlösung mit ProcessExists() anbieten sollen statt mit ProcessList.
    Der Unterschied deiner Lösung zu _singleton() besteht darin dass man bei dir einfach die exe umbenennen muss und schon laufen 2 Skripte wieder parallel.
    Bei Singleton wird auch dies verhindert - egal wie die exe heißt.

    WhiteLion
    Ich schließe mich name22 an.
    Das Skript macht bei mir unter Win 7 64 exakt das was es soll. Egal ob als x86 oder x64 kompiliert.
    Wird das Skript ein zweites mal gestartet kommt die Meldung und das zweite Skript beendet sich.

  • ProcessExist() funktioniert nicht, da der Prozess ja immer existiert, sobald du das Programm startest.
    Aber okay, damit hast du Recht, das kann man besser lösen.

    Da es hier doch einige falsch machen:

    Zitat von einem User dieses Forums

    Die Standard-Standart eines Flamingos ist einbeinig. ;)

  • Warum nicht mit einem einfachen Zweizeiler?

    [autoit]


    If WinExists(StringTrimRight(@ScriptName, 4) & "1") Then Exit ;Allow only one instance of this script!
    AutoItWinSetTitle(StringTrimRight(@ScriptName, 4) & "1")

    [/autoit]

    Gruss, Veronesi

  • Du hast Recht. Ich habe in der Eile nicht gesehen, dass du auf " >1" prüfst. Entschuldige bitte.

    Ist schon okay ;) Ich hatte mir selbst auch mal viele Gedanken dazu gemacht, weil ich mehrere Instanzen erlauben wollte, aber die Konsolenfenster, auf die dann im späteren Programmverlauf zugegriffen werden soll natürlich verschiedene Namen gebraucht haben, und dann habe ich so die Instanznummer herausgefunden ;)

    Da es hier doch einige falsch machen:

    Zitat von einem User dieses Forums

    Die Standard-Standart eines Flamingos ist einbeinig. ;)

    • Offizieller Beitrag

    Warum nicht mit einem einfachen Zweizeiler?

    [autoit]


    If WinExists(StringTrimRight(@ScriptName, 4) & "1") Then Exit ;Allow only one instance of this script!
    AutoItWinSetTitle(StringTrimRight(@ScriptName, 4) & "1")

    [/autoit]

    Weil nicht jedes Script auch ein Fenster öffnet. ;)
    Man sollte schon auf den Prozess prüfen. Aber ansonsten schließe ich mich name22 und AspirinJunkie an. _Singleton funktioniert sehr wohl unter Win7 64 Bit.

  • also ich kann nur von mir sprechen und von einigen thread eröffnern die am gleichen "singleton bug" leiden. es funktioniert bei mir nicht (script oben) und auch nicht in meiner Win 8 64bit VM ... genau das gleiche. in anderen threads wurde auch recht vehement behauptet das es unter "Win 7 64" funktionieren muss... nun ja, offensichtlich tut es das bei einigen aber nicht. ich behaupte einfach mal das ist ein bug, da selbst das beispiel, was ja kaum anders ist als mein script bei mir unter beiden OS nicht funktioniert.

  • Es wird vehement "behauptet", dass es auf Win7 x64 funktioniert weil es das nun mal tut ;). Wenn bei uns allen das Script seine gewünschte Funktion erfüllt können wir nicht behaupten es gäbe ein Problem.
    Ich weiß nicht ob man das direkt als Bug bezeichnen kann. Immerhin funktioniert diese Funktion bei so gut wie allen Usern perfekt. Da alle die selbe Version von AutoIt haben müsste es einen Unterschied zwischen den Systemen geben der diese Überprüfung verhindert.
    Aber ohne zu wissen was das verursacht kann man ja leider noch nicht mal nach einem Bug suchen (sofern es einen gibt)...

  • Oscar

    Dann kompiliere mal dieses Script und lasse es zweimal laufen.

    [autoit]


    If WinExists(StringTrimRight(@ScriptName, 4) & "1") Then Exit MsgBox(64, "Hinweis", "Programm läuft schon")
    AutoItWinSetTitle(StringTrimRight(@ScriptName, 4) & "1")
    Sleep(20000)

    [/autoit]

    Auch ohne GUI hat jedes AutoIt Script ein (verstecktes) Fenster.

    Gruss Veronesi

  • Oscar

    Kein Problem:
    1. ich kompiliere den code aus meinem eröffnungspost unter nativem Win7 64
    (code und kompilierte variante hängt an)
    2. ich führe die kompilierte .exe aus und erwarte natürlich beim ersten starten der exe. NICHT die msgbox (

    [autoit]

    Msgbox(16,"Warning", $TileofWin&" is already running.", 10)

    [/autoit]

    )
    dann führe ich sie ein zweites und drittes ... ect. mal aus und alle ausgeführten varianten hängen natürlich in der While schleife und laufen sichtbar im tray.
    und natürlich sollte ja beim zweiten mal ausführen die messagebox erscheinen und beim klick auf "OK" beendet werden, das passiert aber nicht. Weder unter dem Win7 64 noch unter der völlig unberührten Win 8 64 installation die in der VMWare läuft.... ich kann auch gerne ein video davon machen.

    EDIT: ich verweise mal auf den post hier eines leidensgenossen (das zum thema: geht immer) :
    [ offen ] _Singleton funktioniert nicht

  • Hm ...
    Hast du mal ausgewertet was _Singleton in erster Instanz zurückgibt?

    Spoiler anzeigen
    [autoit]


    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _Singleton
    ; Description ...: Enforce a design paradigm where only one instance of the script may be running.
    ; Syntax.........: _Singleton($sOccurenceName[, $iFlag = 0])
    ; Parameters ....: $sOccurenceName - String to identify the occurrence of the script. This string may not contain the \ character unless you are placing the object in a namespace (See Remarks).
    ; $iFlag - Behavior options.
    ; |0 - Exit the script with the exit code -1 if another instance already exists.
    ; |1 - Return from the function without exiting the script.
    ; |2 - Allow the object to be accessed by anybody in the system. This is useful if specifying a "Global\" object in a multi-user environment.
    ; Return values .: Success - The handle to the object used for synchronization (a mutex).
    ; Failure - 0
    ; Author ........: Valik
    ; Modified.......:
    ; Remarks .......: You can place the object in a namespace by prefixing your object name with either "Global\" or "Local\". "Global\" objects combined with the flag 2 are useful in multi-user environments.
    ; Related .......:
    ; Link ..........:
    ; Example .......: Yes
    ; ===============================================================================================================================
    Func _Singleton($sOccurenceName, $iFlag = 0)
    Local Const $ERROR_ALREADY_EXISTS = 183
    Local Const $SECURITY_DESCRIPTOR_REVISION = 1
    Local $tSecurityAttributes = 0

    [/autoit] [autoit][/autoit] [autoit]

    If BitAND($iFlag, 2) Then
    ; The size of SECURITY_DESCRIPTOR is 20 bytes. We just
    ; need a block of memory the right size, we aren't going to
    ; access any members directly so it's not important what
    ; the members are, just that the total size is correct.
    Local $tSecurityDescriptor = DllStructCreate("byte;byte;word;ptr[4]")
    ; Initialize the security descriptor.
    Local $aRet = DllCall("advapi32.dll", "bool", "InitializeSecurityDescriptor", _
    "struct*", $tSecurityDescriptor, "dword", $SECURITY_DESCRIPTOR_REVISION)
    If @error Then Return SetError(@error, @extended, 0)
    If $aRet[0] Then
    ; Add the NULL DACL specifying access to everybody.
    $aRet = DllCall("advapi32.dll", "bool", "SetSecurityDescriptorDacl", _
    "struct*", $tSecurityDescriptor, "bool", 1, "ptr", 0, "bool", 0)
    If @error Then Return SetError(@error, @extended, 0)
    If $aRet[0] Then
    ; Create a SECURITY_ATTRIBUTES structure.
    $tSecurityAttributes = DllStructCreate($tagSECURITY_ATTRIBUTES)
    ; Assign the members.
    DllStructSetData($tSecurityAttributes, 1, DllStructGetSize($tSecurityAttributes))
    DllStructSetData($tSecurityAttributes, 2, DllStructGetPtr($tSecurityDescriptor))
    DllStructSetData($tSecurityAttributes, 3, 0)
    EndIf
    EndIf
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $handle = DllCall("kernel32.dll", "handle", "CreateMutexW", "struct*", $tSecurityAttributes, "bool", 1, "wstr", $sOccurenceName)
    If @error Then Return SetError(@error, @extended, 0)
    Local $lastError = DllCall("kernel32.dll", "dword", "GetLastError")
    If @error Then Return SetError(@error, @extended, 0)
    If $lastError[0] = $ERROR_ALREADY_EXISTS Then
    If BitAND($iFlag, 1) Then
    Return SetError($lastError[0], $lastError[0], 0)
    Else
    Exit -1
    EndIf
    EndIf
    Return $handle[0]
    EndFunc ;==>_Singleton

    [/autoit]


    So wie ich das sehen müsste in @error was drinstehen wenn es nicht funktioniert.

  • also @error ist 0 und wenn ich den rückgabewert von _singelton anzeigen lasse (sollte ja ein handle sein), dann ist dieser z.B. folgender (bei 4 programmstarts):
    1. instanz: 00000B1C
    2. instanz: 00000B1B
    3. instanz: 00000B1C
    4. instanz: 00000B1B

    Gerne dürft ihr die mal per teamviewer/skype selber schauen:
    Skype ID:whitelionatx