Applikation mehrfach mit Parametern öffnen

  • Hallo liebe Community,

    ich habe mal wieder ein interessantes Problemchen. Ich baue gerade einen kleinen "Filemanager", der über das Windows Kontext-Menü gestartet werden soll. Das heißt man klickt mit Rechtsklick auf eine Datei und klickt im Menü "Filemanager..." an. Danach kann ich diese Datei hochladen und mir wird automatisch eine Mail generiert. So weit so gut zur Funktionalität.

    Mein Problem ist nun: Wenn ich mehrere Dateien auswähle und den Kontextmenüeintrag von Windows nutze, öffnet mir Windows pro Datei eine Instanz der in der Registry verknüpften Applikation. Wie kann ich nun alle markierten Files erkennen? Ich möchte ja nicht jedes File einzeln hochladen lassen, sondern mehrere Files am Besten zippen lassen und dann erst hochladen.

    Hat jemand eine Idee?

    Hier die relevanten Skriptteile (wenn es funktioniert und ich fertig bin, stelle ich gerne den kompletten Filemanager zur Verfügung):

    Spoiler anzeigen
    [autoit]


    global $installpath = "C:\Filemanager"
    global $contextEntry = "Upload to Filemanager..."

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

    RegWrite("HKEY_CLASSES_ROOT\*\shell\"&$contextEntry, "", "REG_SZ", "")
    RegWrite("HKEY_CLASSES_ROOT\*\shell\"&$contextEntry, "Icon", "REG_EXPAND_SZ", $installpath&"\Filer.ico")
    RegWrite("HKEY_CLASSES_ROOT\*\shell\"&$contextEntry&"\command", "", "REG_SZ", $installpath&'\Filer.exe "%1"')

    [/autoit]

    Wenn ich jetzt "Upload to Filemanager..." im Kontextmenü von mehreren markierten Files klicke, öffnet es mir die Filer.exe mehrmals mit dem jeweiligen Dateipfad als Parameter.

    Als Lösung hatte ich folgende Ansätze, die aber meiner Meinung nach noch etwas hinken:
    1. FilerContext.exe => Diese Datei dann in der Registry eintragen. Diese Datei erstellt eine XML-Datei oder Text-datei mit den jeweiligen Dateipfaden, die übergeben wurden. Diese Datei kann dann von der Filer.exe ausgelesen werden. hmm.. Ihr merkt beim Lesen vermutlich schon woran es hakt. ;)
    2. FilerContext.exe => Diesmal übergibt die FilerContext.exe den an sie übergebenen Parameter an die Filer.exe, sofern der Prozess existiert. Da ist allerdings meine Frage: geht das!? Wenn ja wie?

    Ich freue mich auf eure Unterstützung und kreativen Lösungsansätze! :)

    Benni

    Einmal editiert, zuletzt von bennithebrain (10. April 2013 um 08:45)

  • Idee habe ich direkt zu deinem Problem nicht, allerdings ist meiner Meinung nach dein Registrypfad falsch. Das gehört nach "shellex" und nicht nach "shell".

    Andy hat mir ein Schnitzel gebacken aber da war ein Raupi drauf und bevor Oscar das Bugfixen konnte kam Alina und gab mir ein AspirinJunkie.

    • Offizieller Beitrag

    Ich hatte mir für selbiges Problem einen Launcher geschrieben, der beim Menüaufruf die markierte(n) Dateien ausliest und dann anch Bedarf weiterverarbeitet.

    Hier die Funktion zum Auslesen des Explorers:

    Spoiler anzeigen
    [autoit]

    ;===============================================================================
    ; Function Name....: _ActiveExplorer_GetFilesSelected
    ; Description......: Erstellt ein Array mit
    ; - Anzahl der markierten Dateien
    ; - dem Pfad des aktiven Explorerfensters und
    ; - dem/den Pfad/en der markiert/en Datei/en
    ; Parameter(s).....: keine
    ; Requirement(s)...: offenes Explorerfenster
    ; Return Value(s)..: Array mit den Daten, $a[0] = Anzahl, $a[1] = Ordnerpfad, $a[2..] = Dateiname
    ; Author(s)........: BugFix ( [email='bugfix@autoit.de'][/email] )
    ;===============================================================================
    Func _ActiveExplorer_GetFilesSelected()
    Local $oShell = ObjCreate("Shell.Application")
    Local $oExplorer, $sPath, $oFolderView, $iCount = 0, $sSelectedFiles = '', $n = 2
    For $i = 0 To $oShell.Windows.Count - 1
    $oExplorer = $oShell.Windows($i)
    $sPath = StringReplace(StringReplace(StringTrimLeft($oExplorer.LocationURL, 8), '%20', ' '), '/', '\')
    If WinGetTitle('[ACTIVE]') = $sPath Then ExitLoop
    Next
    $oFolderView = $oExplorer.Document.SelectedItems()
    $iCount = $oFolderView.Count
    Local $aOut[$iCount +2]
    $aOut[0] = $iCount
    $aOut[1] = $sPath
    If $iCount = 0 Then
    ReDim $aOut[3]
    $aOut[2] = 'NO FILE SELECT'
    Else
    For $oFolderItem In $oFolderView
    $aOut[$n] = $oFolderItem.Name
    $n += 1
    Next
    EndIf
    Return $aOut
    EndFunc ; ==>_ActiveExplorer_GetFilesSelected

    [/autoit]

    Edit:
    Hier mal das ganze Skript, ich hatte Menüpunkte im Kontextmenü eingefügt um Werte(Dateinamen / Pfade) in die Zwischenablage zu kopieren.

    Spoiler anzeigen
    [autoit]


    ; ===============================================================
    ; == Registrieren im Kontextmenü des Explorers für alle Dateien
    ; == Schlüssel: HKEY_CLASSES_ROOT\*\shell\CMD
    ; == Wert: (Standard) = "Name_des_Menüeintrages"
    ; == Schlüssel: HKEY_CLASSES_ROOT\*\shell\CMD\COMMAND
    ; == Wert: (Standard) = "Pfad_zum_kompilierten_Skript"
    ; ===============================================================

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

    #Region - TimeStamp
    ; 2011-09-11 13:37:20 v 1.0
    #EndRegion - TimeStamp
    #include <GUIConstantsEx.au3>
    #include <GuiListView.au3>
    #include <ListViewConstants.au3>
    #include <WindowsConstants.au3>
    #Include <Misc.au3>

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

    _Singleton(@ScriptName) ; == sonst erfolgt Skriptaufruf für jede markierte Datei

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

    Opt('GUIOnEventMode', 1)
    Local $aDeskSize[2] = [@DesktopWidth,@DesktopHeight]
    Local $aMPos = MouseGetPos()
    Local $x = $aMPos[0], $y = $aMPos[1]
    Local $iWGUI = 120, $iHGUI = 85
    If $x + $iWGUI > $aDeskSize[0] Then
    $x = $aDeskSize[0] - $iWGUI
    EndIf
    If $y + $iHGUI > $aDeskSize[1] Then
    $y = $aDeskSize[1] - $iHGUI
    EndIf
    Local $GUI = GUICreate('', $iWGUI, $iHGUI, $x, $y, BitOR($WS_POPUP,$WS_BORDER))
    GUISetOnEvent($GUI_EVENT_CLOSE, '_close')
    Local $cLV = GuiCtrlCreateListView('LV', 0, 0, $iWGUI, $iHGUI, BitOR($LVS_NOCOLUMNHEADER,$LVS_SINGLESEL), BitOR($LVS_EX_GRIDLINES,$LVS_EX_FULLROWSELECT))
    _GUICtrlListView_SetColumnWidth(GUICtrlGetHandle($cLV), 0, $LVSCW_AUTOSIZE_USEHEADER)
    Local $cFull = GUICtrlCreateListViewItem('kpl. Dateipfade', $cLV)
    GUICtrlSetOnEvent(-1, '_OnClick')
    Local $cFile = GUICtrlCreateListViewItem('Dateinamen', $cLV)
    GUICtrlSetOnEvent(-1, '_OnClick')
    Local $cPath = GUICtrlCreateListViewItem('Pfadname', $cLV)
    GUICtrlSetOnEvent(-1, '_OnClick')
    Local $cSize = GUICtrlCreateListViewItem('Dateigrößen', $cLV)
    GUICtrlSetOnEvent(-1, '_OnClick')

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

    ; == Markierte Datei(en) auslesen
    Global $aSelected = _ActiveExplorer_GetFilesSelected()
    Switch $aSelected[0]
    Case 0
    Exit MsgBox(0, 'Achtung', 'Keine Datei ausgewählt im Ordner' & @CRLF & $aSelected[1])
    Case 1
    GUICtrlSetData($cFull, 'kpl. Dateipfad')
    GUICtrlSetData($cFile, 'Dateiname')
    GUICtrlSetData($cSize, 'Dateigröße')
    EndSwitch

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

    GUISetState()

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

    While 1
    Sleep(50)
    WEnd

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

    Func _close()
    Exit
    EndFunc

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

    Func _OnClick()
    Local $sRet = ''
    Switch @GUI_CtrlId
    Case $cFull
    For $i = 2 To $aSelected[0]+1
    $sRet &= $aSelected[1] & '\' & $aSelected[$i] & @CRLF
    Next
    Case $cFile
    For $i = 2 To $aSelected[0]+1
    $sRet &= $aSelected[$i] & @CRLF
    Next
    Case $cPath
    $sRet = $aSelected[1]
    Case $cSize
    For $i = 2 To $aSelected[0]+1
    Local $iSize = FileGetSize($aSelected[1] & '\' & $aSelected[$i])
    $sRet &= $aSelected[$i] & @TAB & $iSize & @CRLF
    Next
    EndSwitch
    ClipPut($sRet)
    _close()
    EndFunc

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

    ;===============================================================================
    ; Function Name....: _ActiveExplorer_GetFilesSelected
    ; Description......: Erstellt ein Array mit
    ; - Anzahl der markierten Dateien
    ; - dem Pfad des aktiven Explorerfensters und
    ; - dem/den Pfad/en der markiert/en Datei/en
    ; Parameter(s).....: keine
    ; Requirement(s)...: offenes Explorerfenster
    ; Return Value(s)..: Array mit den Daten, $a[0] = Anzahl, $a[1] = Ordnerpfad, $a[2..] = Dateiname
    ; Author(s)........: BugFix ( [email='bugfix@autoit.de'][/email] )
    ;===============================================================================
    Func _ActiveExplorer_GetFilesSelected()
    Local $oShell = ObjCreate("Shell.Application")
    Local $oExplorer, $sPath, $oFolderView, $iCount = 0, $sSelectedFiles = '', $n = 2
    For $i = 0 To $oShell.Windows.Count - 1
    $oExplorer = $oShell.Windows($i)
    $sPath = StringReplace(StringReplace(StringTrimLeft($oExplorer.LocationURL, 8), '%20', ' '), '/', '\')
    If WinGetTitle('[ACTIVE]') = $sPath Then ExitLoop
    Next
    $oFolderView = $oExplorer.Document.SelectedItems()
    $iCount = $oFolderView.Count
    Local $aOut[$iCount +2]
    $aOut[0] = $iCount
    $aOut[1] = $sPath
    If $iCount = 0 Then
    ReDim $aOut[3]
    $aOut[2] = 'NO FILE SELECT'
    Else
    For $oFolderItem In $oFolderView
    $aOut[$n] = $oFolderItem.Name
    $n += 1
    Next
    EndIf
    Return $aOut
    EndFunc ; ==>_ActiveExplorer_GetFilesSelected

    [/autoit]
  • Ich würde einfach nur mit singleton arbeiten und zusätzlich eine Möglichkeit schaffen um Daten der 2. "nicht erlaubten" Instanz des Programmes an die erste Instanz zu übertragen (siehe dazu die unzähligen Beispiele im Forum bezüglich Kommunikation zweier Scripte). Nach der Weitergabe des empfangene Parameters wird die 2. Instanz dann dank der singleton Bedingung beendet. Da du die nach und nach in der 1. Instanz eintrudelnden Dateipfade sammeln wolltest um sie zu zippen benötigst du wohl noch eine zeitbasierte Warteschlange, die erst dann abgearbeitet wird, wenn seit x (Mili)Sekunden keine neuen Daten hinzugefügt wurden. Dazu brauchts prinzipiel nur einen Timer und ein Array.

  • Super! Vielen Dank für die schnellen und hilfreichen Antworten!

    chip: Dachte ich zunächst auch, allerdings trägt sich beispielsweise auch der VLC Player in shell und nicht in shellex ein. Andererseits steht winrar und 7-zip unter shellex. Hier ist beides beschrieben, aber für mich kein relevanter Unterschied zu erkennen: http://www.brighthub.com/computing/wind…cles/59355.aspx

    BugFix : Ich bekomme bei deinem Skript leider einen Fehler in Zeile 16 bzw. 103, also der Funktion.

    misterspeed: Das war ein sehr guter Hinweis. Dadurch bin ich auf folgendes gestoßen: http://www.autoit.de/index.php?page=Thread&postID=160909#post160909

    Die Exchange Variables UDF ist perfekt für meine Idee. Dadurch würde ich ein Skript für das Hinzufügen einer Datei schreiben, in dem ich überprüfe, ob die Filer.exe schon läuft und ggf. starte. Die Übergabe der Variablen funktioniert dann problemlos über die UDF:

    Hier das Skript für die Weitergabe der Variable an das "Hauptprogramm":

    Spoiler anzeigen
    [autoit]


    #include <ExchangeVariables.au3>
    if(IsArray($cmdline)) Then
    if($cmdline[0]>0) then
    _ExchangeVariables_Startup(1, 'SendVariableToAnotherProg')
    sleep(100)
    _ExchangeVariables_SetVariable(2, "AddFileVariable", $cmdline[1])
    EndIf
    EndIf
    Exit

    [/autoit]

    Und hier das Programm, das die Variable entsprechend entgegen nimmt. Also

    Spoiler anzeigen
    [autoit]


    #include <ExchangeVariables.au3>
    Global $AddFileVariable
    _ExchangeVariables_Startup(2, 'SendVariableToAnotherProg' , '_AddFileVariableFunc')
    While 1
    Sleep(100)
    WEnd

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

    Func _AddFileVariableFunc($hWnd, $iMsg, $wParam, $lparam)
    MsgBox(-1, "title", $AddFileVariable)
    EndFunc

    [/autoit]

    Somit kann man auch nachträglich noch Dateien hinzufügen und sozusagen sammeln. Ich werde den Filemanager fertig programmieren und dann hier veröffentlichen.

    Vielen herzlichen Dank :thumbup: ,
    Benni