Anwendungspfad anhand der PID ermitteln

    • Offizieller Beitrag

    Hi,
    hier mal eine Möglichkeit mit der PID den Pfad der Anwendung zu ermitteln.
    Wird keine PID übergeben, gibt die Funktion den Pfad für die Anwendung des aktiven Fensters zurück.

    _GetPathByPID()
    [autoit]


    ; Wenn keine PID übergeben, wird der Pfad der aktuellen Anwendung anhand der PID ermittelt
    ConsoleWrite(_GetPathByPID() & @CRLF)

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

    ;===============================================================================
    ; Function Name: _GetPathByPID($PID=-1)
    ; Description:: Get full path of an running application by using PID
    ; Parameter(s): $PID - PID, if not set will used PID from active Window
    ; Requirement(s): #include <WinAPI.au3>
    ; Return Value(s): Success Full ApplicationPath
    ; Failure set @error 1 - process handle failed
    ; 2 - process image failed
    ; 3 - query dosdevice failed
    ; Author(s): BugFix ([email='bugfix@autoit.de'][/email])
    ;===============================================================================
    #include-once
    #include <WinAPI.au3>
    Func _GetPathByPID($PID=-1)
    If $PID = -1 Then $PID = WinGetProcess(WinGetTitle("[active]"))
    $hProcess = _WinAPI_OpenProcess(0x00000400, True, $PID, True)
    If Not $hProcess Then Return SetError(1,0,0)
    Local $ret, $path, $DevicePath, $DeviceLetter, $strPath = DllStructCreate("char path[256]")
    DllCall(@SystemDir & '\Psapi.dll', "uint64", "GetProcessImageFileNameA", _
    "hwnd", $hProcess, "ptr", DllStructGetPtr($strPath), "int", 256)
    If @error Then Return SetError(2,0,0)
    $path = DllStructGetData($strPath, 'path')
    $DevicePath = StringRegExp($path, "\\Device\\\w*\\[\w\d\+\-()]*", 1)
    Local $lpTargetPath, $aDrive = DriveGetDrive("ALL")
    For $i = 1 To UBound($aDrive) -1
    $ret = DllCall("kernel32.dll", "long", "QueryDosDeviceA", "str", $aDrive[$i], "str", $lpTargetPath, "long", 256)
    If @error Then Return SetError(3,0,0)
    If $ret[2] = $DevicePath[0] Then
    $DeviceLetter = $aDrive[$i]
    ExitLoop
    EndIf
    Next
    DllCall("kernel32.dll", "long", "CloseHandle", "long", $hProcess)
    Return StringReplace($path, $DevicePath[0], StringUpper($DeviceLetter))
    EndFunc ;==>_GetPathByPID

    [/autoit]

    Edit: Es gibt ja kaum was, was nicht schon jemand getan hat ;(
    Habe gerade eine ähnliche Lösung (1 Monat alt) im EN-Forum gefunden. Link
    Naja, ich habs als Zweiter getan - der andere als Vorletzter. :rofl:

  • Sehr gut !!!!

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    OuBVU5ebLhHu5QvlnAyQB4A7SzBrvWulwL7RLl2BdH5tI6sIYspeMKeXMSXl

  • Hallo BugFix,

    habe eben leider einen kleinen Bug in deinem Skript gefunden...

    Wenn der Pfad z. B. für die Firefox.exe "C:\Program Files\Mozilla Firefox\firefox.exe" lautet, wird nur "Files\Mozilla Firefox\firefox.exe" zurückgeliefert...

    mfg
    Axel

    There exist 10 different kind of people on earth.
    Those who understand binary, and those who don't.

    • Offizieller Beitrag

    wird nur "Files\Mozilla Firefox\firefox.exe" zurückgeliefert...


    Kann ich nicht bestätigen.
    Habe mal diesen Ordner angelegt (im deutschen Windows gibt es den normalerweise ja nicht :P ) und ein dort hinkopiertes Programm gestartet.
    Ergebnis:

    Code
    C:\Program Files\TEST\PDFReader.exe
  • Komisch,

    ich habe jetzt 'mal eine Message Box für die Ausgabe gemacht und das Skript compiliert (also nicht über SciTE aufgerufen).

    MsgBox(0, "Pfad", _GetPathByPID()) anstelle von ConsoleWrite(_GetPathByPID() & @CRLF)

    Wenn ich jetzt keine PID in _GetPathByPID angebe und die EXE über die Kommandozeile starte erhalte ich die folgende Meldung:
    \system32\cmd.exe

    Gebe ich im Skript eine PID ein, so erhalte ich für FireFox wieder den im vorigen Post angegebenen Pfad.

    Windows XP MUL (englisch + deutsches Sprachpaket)
    SciTE 1.77
    AutoIt v3 Script : 3, 3, 0, 0

    mfg
    Axel

    There exist 10 different kind of people on earth.
    Those who understand binary, and those who don't.

  • Hallo BugFix.

    Da muß ich ihm recht geben. Sehe grade, das ich das gleiche Verzeichnis wie Du angelegt habe und ich dennoch "Program Files" nicht mit angezeigt bekomme.
    Wieso? Kann ich nicht sagen ;)

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    OuBVU5ebLhHu5QvlnAyQB4A7SzBrvWulwL7RLl2BdH5tI6sIYspeMKeXMSXl

  • Oscar .

    Stimmt, so klappt es auch mit dem Nachbarn ;)

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    OuBVU5ebLhHu5QvlnAyQB4A7SzBrvWulwL7RLl2BdH5tI6sIYspeMKeXMSXl

  • Ich hab bei mir folgenden ConsoleWrites eingefügt:

    [autoit]

    $path = DllStructGetData($strPath, 'path')
    ConsoleWrite("!$path: " & $path & @CRLF)
    $DevicePath = StringRegExp($path, "\\Device\\\w*\\[\w\d\+\-()]*", 1)
    ConsoleWrite("!$DevicePath[0]: " & $DevicePath[0] & @CRLF)

    [/autoit]


    Ergebnis:

    Zitat

    !$path: \Device\HarddiskVolume3\Programme\AutoIt3\AutoIt3.exe
    !$DevicePath[0]: \Device\HarddiskVolume3\Programme
    \AutoIt3\AutoIt3.exe


    //Edit: mit dem RegExp funktioniert es:

    [autoit]

    $DevicePath = StringRegExp($path, "\\Device\\\w*", 1)

    [/autoit]
    • Offizieller Beitrag

    Ich kann Dir ja mal die Ausgabe auf meinem Rechner beschreiben:

    Ohne die zusätzlichen Klammern:
    $DevicePath[0] = "\Device\HarddiskVolume3\Programme"
    Das Array $ret liefert in $ret[2] aber nur:
    "\Device\HarddiskVolume3"
    folglich trift die If-Bedingung nie zu und DeviceLetter ist ein Leerstring.

    Mit den zusätzlichen Klammern:
    $DevicePath[0] = "\Device\HarddiskVolume3"
    und der Rest funktioniert. :thumbup:

    • Offizieller Beitrag

    $DevicePath[0] = "\Device\HarddiskVolume3\Programme"


    Also das verwundert mich nun doch sehr. Eigentlich dürfte hier nicht im Klartext das Volume erscheinen (sonst hätte ich auch die Auswertung vereinfachen können).
    Meine Ausgabe sieht so aus:
    \Device\Harddisk0\DP(1)0x7e00-0x950280000+1

    Also scheint die Abfrage von irgendwelchen Windowseinstellungen beeinflußt zu werden. :S

    • Offizieller Beitrag

    Testprogramm:

    [autoit]


    Local $lpTargetPath
    $ret = DllCall("kernel32.dll", "long", "QueryDosDevice", "str", "c:", "str", $lpTargetPath, "long", 256)
    ConsoleWrite($ret[2] & @CR)

    [/autoit]

    Die Ausgabe für meine CF-Karte (im Cardreader, über USB am Mainboard) sieht ähnlich aus:
    "\Device\Harddisk4\DP(1)0-0+a"

    Bei meinen 4 Festplatten kommt aber immer das Volume, z.B.:
    "\Device\HarddiskVolume4"

  • Werden vielleicht über SATA angeschlossene Geräte anders dargestellt als IDE und P-ATA ? Vielleicht macht da Windows einen Unterschied.

  • Ich habe mal das daraus gebastelt:

    Spoiler anzeigen
    [autoit]

    #include-once
    #include <WinAPI.au3>
    #include <Array.au3>

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

    Global $Icon[1]
    $Liste = WinList ()
    #Region ### START Koda GUI section ### Form=
    $Form1 = GUICreate("Form1", 626, 447, 193, 125)
    $X = 2
    $Y = 2
    For $i = 1 to $Liste[0][0]
    If $Liste[$i][0] <> "" AND IsVisible($Liste[$i][1]) Then
    $Pfad = _GetPathByPID (WinGetProcess ($Liste[$i][1]))
    _ArrayAdd ($Icon,GUICtrlCreateIcon($Pfad, 0, $X, $Y, 48, 48))
    If $X +52 >= 624 Then
    $X = 2
    $Y += 52
    Sleep (100)
    Else
    $X += 52
    EndIf
    EndIf
    Next

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

    Func IsVisible($handle)
    If BitAnd( WinGetState($handle), 2 ) Then
    Return 1
    Else
    Return 0
    EndIf

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

    EndFunc
    For $1 = 0 To $Liste[0][0]

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

    Next
    GUISetState(@SW_SHOW)
    #EndRegion ### END Koda GUI section ###

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

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case -3
    Exit

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

    EndSwitch
    WEnd

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

    ;===============================================================================
    ; Function Name: _GetPathByPID($PID=-1)
    ; Description:: Get full path of an running application by using PID
    ; Parameter(s): $PID - PID, if not set will used PID from active Window
    ; Requirement(s): #include <WinAPI.au3>
    ; Return Value(s): Success Full ApplicationPath
    ; Failure set @error 1 - process handle failed
    ; 2 - process image failed
    ; 3 - query dosdevice failed
    ; Author(s): BugFix ([email='bugfix@autoit.de'][/email])
    ;===============================================================================

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

    Func _GetPathByPID($PID=-1)
    If $PID = -1 Then $PID = WinGetProcess(WinGetTitle("[active]"))
    $hProcess = _WinAPI_OpenProcess(0x00000400, True, $PID, True)
    If Not $hProcess Then Return SetError(1,0,0)
    Local $ret, $path, $DevicePath, $DeviceLetter, $strPath = DllStructCreate("char path[256]")
    DllCall(@SystemDir & '\Psapi.dll', "uint64", "GetProcessImageFileNameA", _
    "hwnd", $hProcess, "ptr", DllStructGetPtr($strPath), "int", 256)
    If @error Then Return SetError(2,0,0)
    $path = DllStructGetData($strPath, 'path')
    $DevicePath = StringRegExp($path, "\\Device\\\w*", 1)
    Local $lpTargetPath, $aDrive = DriveGetDrive("ALL")
    For $i = 1 To UBound($aDrive) -1
    $ret = DllCall("kernel32.dll", "long", "QueryDosDeviceA", "str", $aDrive[$i], "str", $lpTargetPath, "long", 256)
    If @error Then Return SetError(3,0,0)
    If $ret[2] = $DevicePath[0] Then
    $DeviceLetter = $aDrive[$i]
    ExitLoop
    EndIf
    Next
    DllCall("kernel32.dll", "long", "CloseHandle", "long", $hProcess)
    Return StringReplace($path, $DevicePath[0], StringUpper($DeviceLetter))
    EndFunc ;==>_GetPathByPID

    [/autoit]

    mfg. Jam00

    • Offizieller Beitrag

    Hm ich verfluche Vista und Konsorten .

    Da hat BugFix so eine schöne Funktion geschrieben und sie funzt nicht richtig auf Vista .
    Bin gerade dabei einen Taskmanager zu progen und könnte die Funk gut gebrauchen .
    Wenn ich anhand der PID , die ich aus der ProcessList habe den Pfad ermitteln möchte klappt das nicht .

    Dieser Teil des Codes:

    [autoit]

    $hProcess = _WinAPI_OpenProcess(0x00000400, True, $PID, True)

    [/autoit]

    liefert mir des öfteren eine WinApi fehlermeldung:

    _WinApi_OpenProcessPriviliged: Zugriff verweigert

    Habe das versucht mit

    [autoit]

    Local $aProc = DllCall('kernel32.dll', 'hwnd', 'OpenProcess', 'int', 0x00000410, 'int', 0, 'int', $PID); Modifiziert
    $hProcess = $aProc[0]

    [/autoit]


    zu umgehen , aber es klappt nur insoweit, das der fehler nicht angezeigt wird und folglich das Script nicht abstürzt .

    Soweit ich das jetzt recherchiert habe liegt es an der UAC von Vista . Die Funktion OpenProcess funktioniert nur mit einschränkungen.
    Hat irgendwer eine Idee wie ich sonst zum Pfad komme ? Hab mir im Englisch Forum schon eine Wolf gesucht ;(

    BugFix habe sogar 3 weiter Funktionen so ähnlich wie deine gefunden . Deine gefällt mir aber am besten , und liefert mir nach meiner mod. die meisten Ergebnisse :D


    Post 1200 :rock:

    Edit: Hier mal die modifizierte Version von _GetPathByPID:

    Spoiler anzeigen
    [autoit]

    ;===============================================================================
    ; Function Name: _GetPathByPID($PID=-1)
    ; Description:: Get full path of an running application by using PID
    ; Parameter(s): $PID - PID, if not set will used PID from active Window
    ; Requirement(s): #include <WinAPI.au3>
    ; Return Value(s): Success Full ApplicationPath
    ; Failure set @error 1 - process handle failed
    ; 2 - process image failed
    ; 3 - query dosdevice failed
    ; Author(s): BugFix ([email='bugfix@autoit.de'][/email])
    ; Modifiziert : Raupi ([email='raupi@autoit.de'][/email])
    ;===============================================================================
    Func _GetPathByPID($PID = -1)
    Local $hProcess, $ret, $path, $DevicePath, $DeviceLetter, $return, $strPath = DllStructCreate("char path[256]")
    If $PID = -1 Then $PID = WinGetProcess(WinGetTitle("[active]"))
    Local $aProc = DllCall('kernel32.dll', 'hwnd', 'OpenProcess', 'int', 0x00000410, 'int', 0, 'int', $PID); Modifiziert
    $hProcess = $aProc[0]
    If $aProc[0] = 0 Then Return SetError(1, 0, 0)
    DllCall(@SystemDir & '\Psapi.dll', "uint64", "GetProcessImageFileNameA", _
    "hwnd", $aProc[0], "ptr", DllStructGetPtr($strPath), "int", 256)
    If @error Then Return SetError(2, 0, 0)
    $path = DllStructGetData($strPath, 'path')
    $DevicePath = StringRegExp($path, "\\Device\\\w*", 1)
    Local $lpTargetPath, $aDrive = DriveGetDrive("ALL")
    For $i = 1 To UBound($aDrive) - 1
    $ret = DllCall("kernel32.dll", "long", "QueryDosDeviceA", "str", $aDrive[$i], "str", $lpTargetPath, "long", 256)
    If @error Then Return SetError(3, 0, 0)
    If $ret[2] = $DevicePath[0] Then
    $DeviceLetter = $aDrive[$i]
    ExitLoop
    EndIf
    Next
    DllCall("kernel32.dll", "long", "CloseHandle", "long", $hProcess)
    Return StringReplace($path, $DevicePath[0], StringUpper($DeviceLetter))
    EndFunc ;==>_GetPathByPID

    [/autoit]
  • Und mit @RequireAdmin?
    Ansonsten versuchs mal mit dieser (ungetestet - hab gerade kein AutoIt zur Hand):

    Spoiler anzeigen
    [autoit]

    Global $hPsAPI = DllOpen("Psapi.dll")
    Global $hKernel = DllOpen("Kernel32.dll")

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

    Func _ProcessGetPath($hPID)
    Local $sPath = DllStructCreate("char[1000]")
    Local $hProcess = DllCall($hKernel,"int", "OpenProcess","dword",0x0400 + 0x0010,"int",0,"dword",$hPID)
    DllCall($hPsAPI,"long","GetModuleFileNameEx","long",$hProcess[0],"int",0,"ptr",DllStructGetPtr($sPath),"long",DllStructGetSize($sPath))
    DllCall($hKernel,"int", "CloseHandle","hwnd",$hProcess[0])
    Return DllStructGetData($sPath,1)
    EndFunc

    [/autoit]

    Ansonsten mal eine Variante ohne OpenProcess (ebenfalls ungetestet):

    Spoiler anzeigen
    [autoit]

    Global $oWMI = ObjGet("winmgmts:\\localhost\root\CIMV2")

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

    Func _GetProcessPath($hPID)
    For $o In $oWMI.ExecQuery("SELECT ExecutablePath FROM Win32_Process WHERE ProcessID=" & $hPID, "WQL", 48)
    Return $o.ExecutablePath
    Next
    EndFunc

    [/autoit]


    Allerdings ist die 2. Funktion logischerweise deutlich langsamer als die 1.

    2 Mal editiert, zuletzt von AspirinJunkie (24. Mai 2009 um 18:59)

    • Offizieller Beitrag

    AspirinJunkie.

    Dein 1. Beispiel ist superschnell und gibt zahlreiche treffer aus . Dein 2. Beispiel ist am besten hat aber den Nachteil , das es absolut langsam ist . Ich werd eventuell beides kombinieren und mal sehen ob ich es damit hinbekomme. Dank dir