Sign in to follow this  
Followers 0
Ármányos Kő

Read full exe path of a known window/program?

6 posts in this topic

Hi,

I have an au3 automation toolbar working with Adobe FrameMaker7.2 and FrameMaker 8.0.

Users may use any of the two, but some things must be automated differently in the two versions.

How can I get the full path to the exe when the user hits one button in one of the version?

The path would tell whether it is 7.2 or 8.0.

Share this post


Link to post
Share on other sites



Hi,

I have an au3 automation toolbar working with Adobe FrameMaker7.2 and FrameMaker 8.0.

Users may use any of the two, but some things must be automated differently in the two versions.

How can I get the full path to the exe when the user hits one button in one of the version?

The path would tell whether it is 7.2 or 8.0.

This should work for most processes, (There may be a few that windows will not allow access to)

It uses GetModuleFileNameEx() from Psapi.dll

#include <WinAPI.au3>
$Process = "lsass.exe" ; This is just an example application 
$FullPath = _GetProcPath($Process)
MsgBox(0, "Process Full Path", "Process = " & $Process & @CRLF _ 
       & "Path = " & $FullPath)

Func _GetProcPath($Process_In)
    Local $iProc, $hModule, $hProc, $stString, $iResult, $sPath

    $iProc = ProcessExists($Process)
    $hModule = 0
    $hProc = _WinAPI_OpenProcess(BitOR(0x0400, 0x0010), False, $iProc)
    $stString = DllStructCreate("char[260]")
    $iResult = DllCall("Psapi.dll", "dword", "GetModuleFileNameEx", _
        "hwnd", $hProc, _ 
        "hwnd", $hModule, _ 
        "ptr", DllStructGetPtr($stString), _ 
        "dword", 260)
    
    $sPath = DllStructGetData($stString, 1)
    Return $sPath
EndFunc   ;==>_GetProcPath

"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to build bigger and better idiots. So far, the universe is winning."- Rick Cook

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

tested with notepad.exe in 2 folder locations

exe path returned for currently active window

Edit: Feb 13 - fixed missing additional close open handle calls, changed error handling slightly

Opt("MustDeclareVars", 1)
;Local $ret = _GetActiveWinEXEPath("FrameMaker.exe", "FrameMaker");Match any substring in the title
Local $ret = _GetActiveWinEXEPath("notepad.exe", "Notepad")
ConsoleWrite('-> ExecutablePath: ' & $ret & @CRLF & "-> Error: " & @error & @CRLF)

Func _GetActiveWinEXEPath($filename, $title = ""); filename and title substring(optional)
    ; Returns the executable path of the active program window
    ; where more than one instance of program with same exe name is running.
    ; Parameters:
    ; $filename = Executable name, i.e "notepad.exe" without path
    ; $title    = substring of window title, i.e. "Notepad" or "Untitled"
    ; Return:
    ; On Success:   Exe path of active window and @error set to 0
    ; On Error:     ""  and @error set to 1
    ; large chunk of code in this script from post by PerryRaptor
    ; code from this post nicely replaces my WMI code in first version
    ; http://www.autoitscript.com/forum/index.php?showtopic=56280
    
    Local $hWnd, $aWinList, $aProcList, $mode, $pid, $hProc, $stHMod, $stCB, $resEnum, $resPath, $err
    If Not ProcessExists($filename) Then
        SetError(1)
        Return ""
    EndIf
    $mode = Opt("WinTitleMatchMode", 2) ; Match any substring in the title
    If $title <> "" Then
        $aWinList = WinList($title, "")
    Else
        $aWinList = WinList()
    EndIf
    Opt("WinTitleMatchMode", $mode)
    $aProcList = ProcessList($filename)
    For $i1 = 1 To $aWinList[0][0]
        If $aWinList[$i1][0] <> "" Then
            For $i2 = 1 To $aProcList[0][0]
                $pid = $aProcList[$i2][1]
                $hProc = DllCall("kernel32.dll", "int", "OpenProcess", "int", _
                        0x0410, "int", False, "int", $pid)
                $err = @error
                If $err Then
                    If $hProc[0] Then DllCall("kernel32.dll", 'int', 'CloseHandle', 'int', $hProc[0])
                    SetError($err, @extended, 0)
                    Return ""
                EndIf
                If $hProc[0] Then
                    $stHMod = DllStructCreate("int hMod")
                    $stCB = DllStructCreate("dword cbNeeded")
                    $resEnum = DllCall("psapi.dll", "int", "EnumProcessModules", _
                            "int", $hProc[0], "ptr", DllStructGetPtr($stHMod), "dword", _
                            DllStructGetSize($stHMod), "ptr", DllStructGetPtr($stCB, 1))
                    $err = @error
                    If $err Then
                        DllCall("kernel32.dll", 'int', 'CloseHandle', 'int', $hProc[0])
                        SetError($err, @extended, 0)
                        Return ""
                    EndIf
                    If $resEnum[0] Then
                        $resPath = DllCall("psapi.dll", "int", "GetModuleFileNameEx", _
                                "int", $hProc[0], "int", DllStructGetData($stHMod, 1), _
                                "str", "", "dword", 32768)
                        $err = @error
                        DllCall("kernel32.dll", 'int', 'CloseHandle', 'int', $hProc[0])
                        If $err Then
                            SetError($err, @extended, 0)
                            Return ""
                        EndIf
                        If WinGetProcess($aWinList[$i1][1]) = $pid Then
                            $hWnd = $aWinList[$i1][1]
                            If BitAND(WinGetState($hWnd, ""), 8) Then
                                If FileExists($resPath[3]) Then
                                    SetError(0)
                                    Return $resPath[3]
                                Else
                                    SetError(1)
                                    Return ""
                                EndIf
                            EndIf
                        EndIf
                    EndIf
                    $stHMod = 0
                    $stCB = 0
                    If $hProc[0] Then DllCall("kernel32.dll", 'int', 'CloseHandle', 'int', $hProc[0])
                    If @error Then
                        SetError(@error, @extended, 0)
                        Return ""
                    EndIf
                EndIf
            Next
        EndIf
    Next
    SetError(1)
    Return ""
EndFunc   ;==>_GetActiveWinEXEPath
Edited by rover

I see fascists...

Share this post


Link to post
Share on other sites

WMI version

; requires WMI service running
; Win32_Process Class Requires Windows Vista, Windows XP,
; Windows 2000 Professional, or Windows NT Workstation 4.0 SP4 and later.

Opt("MustDeclareVars", 1)
Local $ret = _GetActiveWinEXEPath("FrameMaker.exe", "FrameMaker");Match any substring in the title
;Local $ret = _GetActiveWinEXEPath("notepad.exe", "Notepad")
ConsoleWrite('-> ExecutablePath: ' & $ret & @CRLF & "-> Error: " & @error & @CRLF)
Global  $oMyError

Func _GetActiveWinEXEPath($filename, $title = ""); filename and title substring(optional)
    ; Returns the executable path of the currently active window of a program
    ; where one or more versions of program with same exe name are running.
    ; Parameters:
    ; $filename = Executable name, i.e "notepad.exe" without path
    ; $title    = substring of window title, i.e. "Notepad" or "Untitled"
    ; Return:
    ; On Success:   Exe path of active window and @error set to 0
    ; On Error:     ""  and @error set to 1
    
    Local $colItems = "", $hWnd, $objWMIService, $aWinList, $mode
    Local $strComputer = "localhost" ; or "." or @Computername
    Local $strQuery = "SELECT ExecutablePath,ProcessId FROM Win32_Process WHERE Name = '"
    Local $oMyError = ObjEvent("AutoIt.Error","MyErrFunc")
    If Not ProcessExists($filename) Then
        SetError(1)
        Return ""
    EndIf
    
    ;$objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2")
    $objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strComputer & "\root\cimv2")
    
    If Not IsObj($objWMIService) Or @error = 1 Then
        SetError(1) ; Error connecting to WMI
        Return ""
    EndIf
    
    $mode = Opt("WinTitleMatchMode", 2) ; Match any substring in the title
    If $title <> "" Then
        $aWinList = WinList($title, "")
    Else
        $aWinList = WinList()
    EndIf
    Opt("WinTitleMatchMode", $mode)
    
    $colItems = $objWMIService.ExecQuery($strQuery & $filename & "'", "WQL", 0x30)
    
    If IsObj($colItems) Then
        For $objItem In $colItems
            If IsObj($objItem) Then
                For $i = 1 To $aWinList[0][0]
                    If $aWinList[$i][0] <> "" Then
                        If WinGetProcess($aWinList[$i][1]) = $objItem.ProcessId Then
                            $hWnd = $aWinList[$i][1]
                            ExitLoop
                        EndIf
                    EndIf
                Next
                
                If BitAND(WinGetState($hWnd, ""), 8) Then
                    If FileExists($objItem.ExecutablePath) Then
                        SetError(0)
                        Return $objItem.ExecutablePath
                    Else
                        SetError(1)
                        Return ""
                    EndIf
                EndIf
            EndIf
        Next
    EndIf
    SetError(1)
    Return ""
EndFunc   ;==>_GetActiveWinEXEPath

Func MyErrFunc()
   Local $HexNumber = Hex($oMyError.number,8)
   ConsoleWrite("Debug:  Intercepted COM Error:  Number = " & $HexNumber & _
        "  Windescription = " & $oMyError.windescription & @LF)
   SetError(1)
   Return 0
Endfunc

I see fascists...

Share this post


Link to post
Share on other sites

Hi,

I have an au3 automation toolbar working with Adobe FrameMaker7.2 and FrameMaker 8.0.

Users may use any of the two, but some things must be automated differently in the two versions.

How can I get the full path to the exe when the user hits one button in one of the version?

The path would tell whether it is 7.2 or 8.0.

You guys seem unstoppable!

Thanks for the versions.

I will test them and use one.

I now have some rude code, popping the menu and sensing what happens and deciding which version the software is...

Yours seem far better....

Share this post


Link to post
Share on other sites

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0