Prog übergibt Parameter an seine 1 Instanz (mehrere Dateien via Kontext-Menü)

  • Ich erstelle einen Eintrag im Explorer Kontext-Menü; die ausgewählte Datei wird dann via Commandline-Parameter an das Programm übergeben.
    Wen man nun mehrere Dateien ausgewählt hat, dann werden dementsprechend viele Instanzen des Programms gestartet, jede mit einem anderen Dateinamen als Commandline-Parameter.
    Ich will aber, dass mein Programm nur einmal läuft und alle ausgewählten Dateinamen bekommt bzw. auch später ausgewählte Dateien sollen im bereits gestarteten Prog landen.

    (Mit dem fertigen Programm will ich im Explorer Mp3-Dateien markieren und via Rechtsklick auf einen Server laden...)

    Meine Lösung:
    Instanz 1 erzeugt eine GUI und alle weiteren Instanzen senden "ihre" Commandline-Parameter an das GUI der 1 Instanz.

    Wenn man zu viele Dateien auf einmal "startet", dann würden die einzelnen Instanzen fast zeitgleich senden.
    Darum warten diese, bis sie an der Reihe sind.


    Spoiler anzeigen
    [autoit]

    If $CmdLine[0]=0 And @Compiled Then RegWrite("HKEY_CLASSES_ROOT\*\shell\TestContext\command","","REG_SZ",'"' & @AutoItExe & '" "%1"')
    ;RegDelete("HKEY_CLASSES_ROOT\*\shell\TestContext")

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

    #include <Misc.au3>
    #include <WindowsConstants.au3>
    #include <GUIConstantsEx.au3>

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

    Opt("GUIOnEventMode", 1)

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

    If $CmdLine[0]<>1 Then Exit

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

    Global $WinTitle="Window Title"

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

    If _Singleton($WinTitle,1)=0 Then ;wenn nicht 1 Instanz
    #NoTrayIcon
    WinWait($WinTitle)
    $Send_handle = WinGetHandle($WinTitle)
    Do
    $ProcList=ProcessList(@ScriptName)
    Sleep(100)
    Until $ProcList[2][1]=@AutoItPID ;wartet bis aktuelle Instanz an der Reihe ist - also [2][0], [1][0] ist ja die 1 Instanz mit GUI
    _SendCopyDataString(0,$Send_handle,$CmdLine[1]);sendet den Commandline-Parameter an das GUI der 1 Instanz
    Exit
    EndIf

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

    GUICreate($WinTitle,320,640)
    GUIRegisterMsg($WM_COPYDATA, 'MY_WM_COPYDATA');empfängt die Daten
    GUISetOnEvent($GUI_EVENT_CLOSE,"_EXIT")
    $Liste=GUICtrlCreateLabel($CmdLine[1],0,0,320,640)
    GUISetState()

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

    While 1
    Sleep(100)
    WEnd

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

    Func _SendCopyDataString($My_Hwnd, $Scite_hwnd, $sCmd)
    Local $CmdStruct = DllStructCreate('Char[' & StringLen($sCmd) + 1 & ']')
    DllStructSetData($CmdStruct, 1, $sCmd)
    Local $COPYDATA = DllStructCreate('Ptr;DWord;Ptr')
    DllStructSetData($COPYDATA, 1, 1)
    DllStructSetData($COPYDATA, 2, StringLen($sCmd) + 1)
    DllStructSetData($COPYDATA, 3, DllStructGetPtr($CmdStruct))
    DllCall('User32.dll', 'None', 'SendMessage', 'HWnd', $Scite_hwnd, _
    'Int', $WM_COPYDATA, 'HWnd', $My_Hwnd, _
    'Ptr', DllStructGetPtr($COPYDATA))
    EndFunc

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

    Func MY_WM_COPYDATA($hWnd, $msg, $wParam, $lParam)
    Local $Temp=""
    Local $COPYDATA = DllStructCreate('Ptr;DWord;Ptr', $lParam)
    Local $COPYDATA_StringLen = DllStructGetData($COPYDATA, 2)
    Local $CmdStruct = DllStructCreate('Char['&$COPYDATA_StringLen&']', DllStructGetData($COPYDATA, 3))
    $COPYDATA_String = StringLeft(DllStructGetData($CmdStruct, 1), $COPYDATA_StringLen)
    $Temp=GUICtrlRead($Liste)
    GUICtrlSetData($Liste,$Temp & @CRLF & $COPYDATA_String)
    EndFunc

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

    Func _EXIT()
    Exit
    EndFunc

    [/autoit]

    wers ausprobieren will:
    als EXE Compilieren
    dann einmal direkt aufrufen, damit der Eintrag ins Kontext-Menü gemacht wird
    danach im Explorer irgendwelche Dateien markieren -> Rechtsklick -> TestKontext

    das GUI listet nun die Dateien der Reihe nach auf.

    Ich hoff, das kann jemand brauchen ;)

    lgE

  • Hi eukalyptus. Erstmal vielen Dank für deinen Code hier! Das ist echt ne super Lösung für das Problem :)
    Und entschuldigt bitte das ich den alten Thread hier wieder ausgrabe, aber mir ist beim Testen ein Problem aufgefallen. Und zwar funktioniert das Programm nur so in ca. 90% aller Fälle. In 10% scheint sich eine der Exe'n aufzuhängen und blockiert somit alle anderen und damit auch das ganze Programm.
    Hast du eine Idee woran das liegen könnte und wie man das verhindern kann? :)

    lg
    Leo

    Edit: mein Workaround:


    Man lässt ein extra programm laufen, welches checkt ob sich eins der Programme aufgehängt hat. Wenn ja, dann wird dieses beendet. Es ist immer die 1. exe im ProcessList Array, die sich aufhängt.

    Aber eine wirkliche Lösung kann das ja auch nicht sein, da so immer ein Element verloren geht ...
    Irgendwie muss da im Hauptprogramm noch etwas angepasst werden, aber ich weiß nicht wirklich was .. :/

    Einmal editiert, zuletzt von Leo.1906 (5. Juli 2016 um 12:12)

  • Mittlerweile würd ich das mit NamedPipes lösen:

    Aus irgendeinem Grund funktioniert der TimeOut-Parameter bei _NamedPipes_CallNamedPipe nicht, deshalb der kleine Workaround mit ErrorCnt..


    Es gibt aber noch eine weitere Möglichkeit:
    Eine Verknüpfung in "Send To" erstellen. (Im Explorer "shell:sendto" eingeben)

    Dann reicht ein ganz simples Script:

    AutoIt
    #include <Array.au3>
    _ArrayDisplay($CmdLine)
  • Hi!
    Wenn man weiß, nach was man suchen muss (sendto), ist alles hganz einfach :D
    Aktion auf markierte Dateien anwenden

  • SendTo ist natürlich eine Option, aber eben auch nicht immer. Wenn man verschiedene Möglichkeiten des Aufrufs seines Programms möchte, dann geht das nicht so einfach.
    In meinem Fall habe ich einen Converter geschrieben und über Context Menü wählt man aus in welches Format konvertiert werden soll.
    Ich habe das ganze mit shared-variablen jetzt zu 100% zuverlässig gelöst bekommen. Das Hauptprog erstelle eine Variable und gibt diese frei. Das Hilfsprogramm (welches uU mehrfach geöffnet wird) schreibt dort die parameter rein. Das Hauptprog überwacht diese ständig. Wenn sich etwas ändert, dann tut es das was es soll :)