Wie kann ich den PID eines mit ShellExcute gestarteten Programms herausfinden?
Gibt es auch andere Möglichkeiten an den Pid zu kommen?
PS: Das Programm hat kein Fenster.
Wie kann ich den PID eines mit ShellExcute gestarteten Programms herausfinden?
Gibt es auch andere Möglichkeiten an den Pid zu kommen?
PS: Das Programm hat kein Fenster.
$pid= processexists("prozess.exe")
[/autoit]Hier ist finde ich ein gutes Beispiel.
Dort kannst du sogar prüfen welchen State das Fenster hat.
Die PID wird oben ausgelesen
;~ 1 = Fenster existiert.
;~ 2 = Fenster ist sichtbar.
;~ 4 = Fenster ist freigegeben.
;~ 8 = Fenster ist aktiv.
;~ 16 = Fenster ist minimiert.
;~ 32 = Fenster ist maximiert.
#include <array.au3>
#include <Process.au3>
Global $list = ProcessList()
For $i = 1 To $list[0][0]
$state = WinGetState(_WinGetByPID($list[$i][1]), "")
$processString = "ProcessName: " & $list[$i][0] & @CRLF
$processString &= "ProcessID: " & $list[$i][1] & @CRLF
$processString &= "ProcessPath: " & _GetProcessPath($list[$i][1]) & @CRLF
If BitAND($state, 16) Then ; Fenster Modus siehe oben (minimiert)
MsgBox(0, $list[$i][0], "Fenster ist minimiert" & @CRLF & @CRLF & $processString)
EndIf
If BitAND($state,
Then ; Fenster Modus siehe oben (aktiviert)
MsgBox(0, $list[$i][0], "Fenster ist Aktiviert" & @CRLF & @CRLF & $processString)
EndIf
If BitAND($state, 32) Then ; Fenster Modus siehe oben (maximiert)
MsgBox(0, $list[$i][0], "Fenster ist Maximiert" & @CRLF & @CRLF & $processString)
EndIf
Next
Func _GetProcessPath($GPPpid)
$colItems = ""
$strComputer = "localhost"
$objWMIService = ObjGet("winmgmts:\\localhost\root\CIMV2")
$colItems = $objWMIService.ExecQuery('SELECT * FROM Win32_Process WHERE processid = ' & $GPPpid, "WQL", 0x10 + 0x20)
If IsObj($colItems) Then
For $objItem In $colItems
Return $objItem.ExecutablePath
Next
Else
Return ""
EndIf
EndFunc ;==>_GetProcessPath
Func _WinGetByPID($iPID, $nArray = 1)
If IsString($iPID) Then $iPID = ProcessExists($iPID)
Local $aWList = WinList(), $sHold
For $iCC = 1 To $aWList[0][0]
If WinGetProcess($aWList[$iCC][1]) = $iPID And _
BitAND(WinGetState($aWList[$iCC][1]), 2) Then
If $nArray Then Return $aWList[$iCC][0]
$sHold &= $aWList[$iCC][0] & Chr(1)
EndIf
Next
If $sHold Then Return StringSplit(StringTrimRight($sHold, 1), Chr(1))
Return SetError(1, 0, 0)
EndFunc ;==>_WinGetByPID
http://www.autoit.de/index.php?page=Thread&threadID=25652&highlight=
@tuttifrutti:
PS: Das Programm hat kein Fenster.
@MasterOfTime: warum verwendest du nicht einfach
[autoit]run
[/autoit]da bekommst du die PID zurück,
mfg autoBert
Mein Problem ist nicht das einfache herausfinden eines Pids, sondern den eines startenden Prozesses, weil dieser den selben Namen hat wie ein bereits bestehender Prozess, was aber nicht die selben Programme sind.
Wenn ihr eine Lösung perat habt, lasst es mich wissen.
€: AutoBerts Vorschlag geht, wieso bin ich da nicht drauf gekommen ![]()
@tuttifrutti:
@MasterOfTime: warum verwendest du nicht einfach
[autoit]run
[/autoit]da bekommst du die PID zurück,
mfg autoBert
autoBert: Ein bisschen umändern zeigt auch alle Programme mit PID's an !
;~ 1 = Fenster existiert.
;~ 2 = Fenster ist sichtbar.
;~ 4 = Fenster ist freigegeben.
;~ 8 = Fenster ist aktiv.
;~ 16 = Fenster ist minimiert.
;~ 32 = Fenster ist maximiert.
#include <Array.au3>
#include <Process.au3>
Global $list = ProcessList()
_ArrayDisplay($list,"test")
[/autoit] [autoit][/autoit] [autoit]For $i = 1 To $list[0][0]
$state = WinGetState(_WinGetByPID($list[$i][1]), "")
$processString = "ProcessName: " & $list[$i][0] & @CRLF
$processString &= "ProcessID: " & $list[$i][1] & @CRLF
$processString &= "ProcessPath: " & _GetProcessPath($list[$i][1]) & @CRLF
;~ If BitAND($state, 16) Then ; Fenster Modus siehe oben (minimiert)
;~ MsgBox(0, $list[$i][0], "Fenster ist minimiert" & @CRLF & @CRLF & $processString)
;~ EndIf
;~ If BitAND($state,
Then ; Fenster Modus siehe oben (aktiviert)
;~ MsgBox(0, $list[$i][0], "Fenster ist Aktiviert" & @CRLF & @CRLF & $processString)
;~ EndIf
;~ If BitAND($state, 32) Then ; Fenster Modus siehe oben (maximiert)
;~ MsgBox(0, $list[$i][0], "Fenster ist Maximiert" & @CRLF & @CRLF & $processString)
;~ EndIf
Next
Func _GetProcessPath($GPPpid)
$colItems = ""
$strComputer = "localhost"
$objWMIService = ObjGet("winmgmts:\\localhost\root\CIMV2")
$colItems = $objWMIService.ExecQuery('SELECT * FROM Win32_Process WHERE processid = ' & $GPPpid, "WQL", 0x10 + 0x20)
If IsObj($colItems) Then
For $objItem In $colItems
Return $objItem.ExecutablePath
Next
Else
Return ""
EndIf
EndFunc ;==>_GetProcessPath
Func _WinGetByPID($iPID, $nArray = 1)
If IsString($iPID) Then $iPID = ProcessExists($iPID)
Local $aWList = WinList(), $sHold
For $iCC = 1 To $aWList[0][0]
If WinGetProcess($aWList[$iCC][1]) = $iPID And _
BitAND(WinGetState($aWList[$iCC][1]), 2) Then
If $nArray Then Return $aWList[$iCC][0]
$sHold &= $aWList[$iCC][0] & Chr(1)
EndIf
Next
If $sHold Then Return StringSplit(StringTrimRight($sHold, 1), Chr(1))
Return SetError(1, 0, 0)
EndFunc ;==>_WinGetByPID
Das ist wie Twodollarbillie's Script nur komplizierter und länger...
€: AutoBerts Vorschlag geht, wieso bin ich da nicht drauf gekommen
schön, dann ist dein Problem ja gelöst, schön wäre es allerdings auch wenn du den Thread auf gelöst setzt. Einfach 1. Beitrag bearbeiten, Präfix (nähe Überschrift) ändern und speichern (absenden)
mfg autoBert
Ich benutze folgende Funktion:
; =================================================================================================
; Func _ShellExecuteEx($sCmd, $sParams = "", $sFolder = "", $sVerb = "", $iState = @SW_SHOWNORMAL,$bCloseProcessHandle=True)
;
; Parameters are the same as ShellExecute(), except for the addition of:
;
; $bCloseProcessHandle = If True (recommended unless planning on using Process Handles),
; then the Process Handle (if received) is closed
; If False, the Process Handle (if received) is returned - this can be used to do additional work with Processes
; Usage is mostly recommended for the _ShellExecuteExWait() function and/or getting exit code.
;
; Return is different from ShellExecute() in the following way:
; Success: @error = 0, and either the process ID (if $bCloseProcessHandle is True, and process ID received) is returned,
; or a 2-element array (if $bCloseProcessHandle is False):
; $array[0]=Process ID if new process started (and process handle+ID received),
; $array[1]=Process Handle if new process started (and process handle received)
; Failure: @error set and 0 is returned
; @error = 1 = parameters error
; @error = 2 = call failed (probably due to parameter error. can use _WinAPI_GetLastError())
;
; NOTE: Recommended to run on Windows 2000 or higher because:
; According to Microsoft at http://msdn2.microsoft.com/en-us/library/bb762154.aspx,
; Windows 95/98/Me: ShellExecuteEx is supported by the Microsoft Layer for Unicode (MSLU).
; To use this, you must add certain files to your application,
; as outlined in Microsoft Layer for Unicode on Windows Me/98/95 Systems.
; So it appears it will break on those machines without MSLU(?)
;
; Initial Code from MrCreatoR on AutoIt Forum Topic:: http://www.autoitscript.com/forum/index.php?showtopic=69868
; Enhancements/Modifications by: Ascend4nt
; (including process handle/ID extract & close-handle code, plus Unicode/path enhancements, & CoInitializeEx call)
; =================================================================================================
Func _ShellExecuteEx($sCmd, $sParams = "", $sFolder = "", $sVerb = "", $iState = @SW_SHOWNORMAL,$bCloseProcessHandle=True)
Local $stINFO,$stVerb,$stPath,$stArgs,$stWDir,$aRet,$hWnd=0,$aProcessArray[2]=[0,0]
Local $iParamLen,$iCmdLen,$iFolderLen
$iParamLen=StringLen($sParams)
; Verify string lengths are less than maximum.
; Through testing, 1997 (1996+1 NULL-term) is the maximum parameter length for this call (Unicode)
If $iParamLen>1996 Then Return SetError(1,0,0)
$iCmdLen=StringLen($sCmd)
; Verify string lengths are less than maximum. [MAX_PATH is 260, but Unicode allows exceptions]
; 32767 max length for Unicode strings if prefixed with '\\?\'
If $iCmdLen>259 Then
; 32767-NULL=32766 - 4 (\\?\) = 32762
If $iCmdLen>(32766-4) Then Return SetError(1,0,0)
$sCmd='\\?\' & $sCmd
EndIf
$iFolderLen=StringLen($sFolder)
; Verify string lengths are less than maximum. [MAX_PATH is 260, but Unicode allows exceptions]
; 32767 max length for Unicode strings if prefixed with '\\?\'
If $iFolderLen>259 Then
; 32767-NULL=32766 - 4 (\\?\) = 32762
If $iFolderLen>(32766-4) Then Return SetError(1,0,0)
$sFolder='\\?\' & $sFolder
EndIf
; Setup string structures
$stVerb = DllStructCreate("wchar["&(StringLen($sVerb)+1)&"]")
$stPath = DllStructCreate("wchar[" &($iCmdLen+1)& "];wchar")
$stArgs = DllStructCreate("wchar[" &($iParamLen+1)& "];wchar")
$stWDir = DllStructCreate("wchar[" &($iFolderLen+1)& "];wchar")
; Initialize string structures (which are then used by pointer in the larger SHELLEXECUTEINFO structure)
DllStructSetData($stVerb, 1, $sVerb)
DllStructSetData($stPath, 1, $sCmd)
DllStructSetData($stWDir, 1, $sFolder)
DllStructSetData($stArgs, 1, $sParams)
; SHELLEXECUTEINFO structure
$stINFO = DllStructCreate("ulong;ulong;long;ptr;ptr;ptr;ptr;long;long;ptr;ptr;long;ulong;long;long")
; SHELLEXECUTEINFO structure initialize
DllStructSetData($stINFO, 1, DllStructGetSize($stINFO)) ; cbSize, size (in bytes) of structure
; ------------------------------------------------------------------------------------------------------
; fMask Options:
; 0x40 = SEE_MASK_NOCLOSEPROCESS. The 15th element in structure (hProcess) will be set with the Process handle
; NOTE: per MSDN, this handle *must* be closed by the caller. (similar to how "OpenProcess" must use "CloseProcess")
; 0x400 = SEE_MASK_FLAG_NO_UI = Do not display an error message box if an error occurs.
; This is not default ShellExecute() behavior, which will display the error message box
; ------------------------------------------------------------------------------------------------------
DllStructSetData($stINFO, 2, BitOR(0x40,0x400)) ; fMask
; HWND - MSDN: A window handle to any message boxes that the system might produce while executing this function.
DllStructSetData($stINFO, 3, $hWnd) ; Is this supposed to *receive* instead of send? I have yet to get clarity on this.
DllStructSetData($stINFO, 4, DllStructGetPtr($stVerb)) ; lpVerb: pointer to the verb string
DllStructSetData($stINFO, 5, DllStructGetPtr($stPath)) ; lpFile: pointer to the $cmd string
DllStructSetData($stINFO, 6, DllStructGetPtr($stArgs)) ; lpParameters: pointer to the parameters/arguments string
DllStructSetData($stINFO, 7, DllStructGetPtr($stWDir)) ; lpDirectory: pointer to working directory string
DllStructSetData($stINFO, 8, $iState) ; nShow = state to show window as
#cs
; ------------------------------------------------------------------------------------------------------
; Per MSDN Documentation, the following call should be done prior to calling ShellExecuteEx:
; CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE) ; COINIT_APARTMENTTHREADED = 0x2,COINIT_DISABLE_OLE1DDE = 0x4
; Reason:
; "Because ShellExecuteEx can delegate execution to Shell extensions (data sources, context menu handlers, verb implementations)
; that are activated using Component Object Model (COM), COM should be initialized before ShellExecuteEx is called.
; Some Shell extensions require the COM single-threaded apartment (STA) type. In that case, COM should be initialized as shown here.
; There are certainly instances where ShellExecuteEx does not use one of these types of Shell extension and those instances would not
; require COM to be initialized at all. Nonetheless, it is good practice to always initalize COM before using this function."
; ------------------------------------------------------------------------------------------------------
#ce
DllCall("ole32.dll", "int", "CoInitializeEx", "ptr", Chr(0), "dword", BitOR(2,4))
; I don't care if it succeeds. Doesn't seem to make much difference even to call it.
$aRet=DllCall("shell32.dll", "int", "ShellExecuteExW", "ptr", DllStructGetPtr($stINFO))
If @error Or Not $aRet[0] Then
; DLLStructDelete()'s:
$stINFO=0
$stVerb=0
$stPath=0
$stArgs=0
$stWDir=0
Return SetError(2,@error,0)
EndIf
; Get Process Handle, if one exists (non-NULL if new process started, otherwise
; NULL if app that performs 'verb' is already running, or is perhaps a 'properties' dialog etc)
$aProcessArray[1]=DllStructGetData($stINFO,15)
; Get Process ID from Handle
If ($aProcessArray[1]) Then
$aRet=DllCall("Kernel32.dll","dword","GetProcessId","long",$aProcessArray[1])
If IsArray($aRet) Then $aProcessArray[0]=$aRet[0]
EndIf
;ConsoleWrite("Handle passed to function:" & Number($hWnd) & ", Handle AFTER call:" & Number(DllStructGetData($stINFO,3)) & @CRLF)
;ConsoleWrite("Process Handle:" & Number($hProcess) & ", Process ID:" & Number($vProcessID) & @CRLF)
; Close Handle
If $bCloseProcessHandle And $aProcessArray[1] Then DllCall('kernel32.dll','ptr', 'CloseHandle','ptr', $aProcessArray[1])
; DLLStructDelete()'s:
$stINFO=0
$stVerb=0
$stPath=0
$stArgs=0
$stWDir=0
If ($bCloseProcessHandle) Then Return SetError(0,0,$aProcessArray[0])
SetError(0,0)
Return $aProcessArray
EndFunc