Jump to content
Sign in to follow this  
VAN0

Using _WinAPI_GetWindowFileName for 64bit processes within 32bit script?

Recommended Posts

VAN0

Hello.

When script is running in 32bit mode _WinAPI_GetWindowFileName fails to retrieve path of a 64bit process.

Does anyone know how to fix this?

Thank you.

[EDIT]

Seems like the problem is in GetModuleFileNameEx

Edited by VAN0

Share this post


Link to post
Share on other sites
guinness

It's how MS works.


UDF List:

 
_AdapterConnections()_AlwaysRun()_AppMon()_AppMonEx()_ArrayFilter/_ArrayReduce_BinaryBin()_CheckMsgBox()_CmdLineRaw()_ContextMenu()_ConvertLHWebColor()/_ConvertSHWebColor()_DesktopDimensions()_DisplayPassword()_DotNet_Load()/_DotNet_Unload()_Fibonacci()_FileCompare()_FileCompareContents()_FileNameByHandle()_FilePrefix/SRE()_FindInFile()_GetBackgroundColor()/_SetBackgroundColor()_GetConrolID()_GetCtrlClass()_GetDirectoryFormat()_GetDriveMediaType()_GetFilename()/_GetFilenameExt()_GetHardwareID()_GetIP()_GetIP_Country()_GetOSLanguage()_GetSavedSource()_GetStringSize()_GetSystemPaths()_GetURLImage()_GIFImage()_GoogleWeather()_GUICtrlCreateGroup()_GUICtrlListBox_CreateArray()_GUICtrlListView_CreateArray()_GUICtrlListView_SaveCSV()_GUICtrlListView_SaveHTML()_GUICtrlListView_SaveTxt()_GUICtrlListView_SaveXML()_GUICtrlMenu_Recent()_GUICtrlMenu_SetItemImage()_GUICtrlTreeView_CreateArray()_GUIDisable()_GUIImageList_SetIconFromHandle()_GUIRegisterMsg()_GUISetIcon()_Icon_Clear()/_Icon_Set()_IdleTime()_InetGet()_InetGetGUI()_InetGetProgress()_IPDetails()_IsFileOlder()_IsGUID()_IsHex()_IsPalindrome()_IsRegKey()_IsStringRegExp()_IsSystemDrive()_IsUPX()_IsValidType()_IsWebColor()_Language()_Log()_MicrosoftInternetConnectivity()_MSDNDataType()_PathFull/GetRelative/Split()_PathSplitEx()_PrintFromArray()_ProgressSetMarquee()_ReDim()_RockPaperScissors()/_RockPaperScissorsLizardSpock()_ScrollingCredits_SelfDelete()_SelfRename()_SelfUpdate()_SendTo()_ShellAll()_ShellFile()_ShellFolder()_SingletonHWID()_SingletonPID()_Startup()_StringCompact()_StringIsValid()_StringRegExpMetaCharacters()_StringReplaceWholeWord()_StringStripChars()_Temperature()_TrialPeriod()_UKToUSDate()/_USToUKDate()_WinAPI_Create_CTL_CODE()_WinAPI_CreateGUID()_WMIDateStringToDate()/_DateToWMIDateString()Au3 script parsingAutoIt SearchAutoIt3 PortableAutoIt3WrapperToPragmaAutoItWinGetTitle()/AutoItWinSetTitle()CodingDirToHTML5FileInstallrFileReadLastChars()GeoIP databaseGUI - Only Close ButtonGUI ExamplesGUICtrlDeleteImage()GUICtrlGetBkColor()GUICtrlGetStyle()GUIEventsGUIGetBkColor()Int_Parse() & Int_TryParse()IsISBN()LockFile()Mapping CtrlIDsOOP in AutoItParseHeadersToSciTE()PasswordValidPasteBinPosts Per DayPreExpandProtect GlobalsQueue()Resource UpdateResourcesExSciTE JumpSettings INISHELLHOOKShunting-YardSignature CreatorStack()Stopwatch()StringAddLF()/StringStripLF()StringEOLToCRLF()VSCROLLWM_COPYDATAMore Examples...

Updated: 22/04/2018

Share this post


Link to post
Share on other sites
funkey

I use QueryFullProcessImageName.

Here a fast example:

#include <WinAPIProc.au3>

Run("calc.exe")
Global $hWnd = WinWait("[CLASS:CalcFrame]")

Global $sProcess = __WinAPI_GetWindowFileName($hWnd)
ConsoleWrite($sProcess & @LF)


Func _WinAPI_QueryFullProcessImageName($hProcess)
    Local Const $PROCESS_NAME_NATIVE = 1
    Local $dwSize = 65535
    Local $aRet = DllCall("kernel32.dll", "BOOL", "QueryFullProcessImageName", "handle", $hProcess, "dword", $PROCESS_NAME_NATIVE, "str", "", "dword*", $dwSize)
    Return $aRet[3]
EndFunc


Func __WinAPI_GetWindowFileName($hWnd)
    Local $PID = 0

    Local $Result = DllCall("user32.dll", "bool", "IsWindow", "hwnd", $hWnd)
    If $Result[0] Then
        $Result = DllCall("user32.dll", "dword", "GetWindowThreadProcessId", "hwnd", $hWnd, "dword*", 0)
        $PID = $Result[2]
    EndIf
    If Not $PID Then Return SetError(1, 0, '')

    $Result = __WinAPI_GetProcessFileName($PID)
    If @error Then Return SetError(@error, @extended, '')

    Return $Result
EndFunc   ;==>_WinAPI_GetWindowFileName

Func __WinAPI_GetProcessFileName($PID = 0)
    If Not $PID Then $PID = @AutoItPID

    Local $hProcess = DllCall('kernel32.dll', 'handle', 'OpenProcess', 'dword', __Iif($__WINVER < 0x0600, 0x00000410, 0x00001010), _
            'bool', 0, 'dword', $PID)
    If @error Or Not $hProcess[0] Then Return SetError(@error + 20, @extended, '')

;~  Local $Path = _WinAPI_GetModuleFileNameEx($hProcess[0])
    Local $Path = _WinAPI_QueryFullProcessImageName($hProcess[0])
    Local $iError = @error

    DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hProcess[0])
    If $iError Then Return SetError(@error, 0, '')

    Return $Path
EndFunc   ;==>_WinAPI_GetProcessFileName
  • Like 2

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

Share this post


Link to post
Share on other sites
VAN0

Thank you very much!

Your code and code from Yashied is exactly what I needed:

#Include <WinAPIEx.au3>

ConsoleWrite(_DosPathNameToPathName('\Device\HarddiskVolume2\Program Files\SomeProgram\exe.exe') & @CR)

Func _DosPathNameToPathName($sPath)

    Local $sName, $aDrive = DriveGetDrive('ALL')

    If Not IsArray($aDrive) Then
        Return SetError(1, 0, $sPath)
    EndIf

    For $i = 1 To $aDrive[0]
        $sName = _WinAPI_QueryDosDevice($aDrive[$i])
        If StringInStr($sPath, $sName) = 1 Then
            Return StringReplace($sPath, $sName, StringUpper($aDrive[$i]), 1)
        EndIf
    Next
    Return SetError(2, 0, $sPath)
EndFunc   ;==>_DosPathNameToPathName
WinAPIEx.au3

Global $sProcess = _DosPathNameToPathName(__WinAPI_GetWindowFileName($hWnd))
ConsoleWrite($sProcess & @LF)
Although it doesn't get drive letters for network drives, but in my case it's irrelevant.

Thanks again

Edited by VAN0

Share this post


Link to post
Share on other sites
funkey

If you use 0 instead of $PROCESS_NAME_NATIVE then you get the Win32 path format  ;)

Func _WinAPI_QueryFullProcessImageName($hProcess)
    Local Const $PROCESS_NAME_NATIVE = 1
    Local $dwSize = 65535
    Local $aRet = DllCall("kernel32.dll", "BOOL", "QueryFullProcessImageName", "handle", $hProcess, "dword", 0, "str", "", "dword*", $dwSize)
    Return $aRet[3]
EndFunc
Edited by funkey
  • Like 1

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

Share this post


Link to post
Share on other sites
VAN0

Hello. What could possibly cause this method not work on games? Specifically War Thunder. It doesn't matter if I run the game in fullscreen or windowed, this script can't get the path of the executable.

Any advice?

Thank you.

Share this post


Link to post
Share on other sites
VAN0

It returns @error = 20

which is these lines:

Local $hProcess = DllCall('kernel32.dll', 'handle', 'OpenProcess', 'dword', __Iif($__WINVER < 0x0600, 0x00000410, 0x00001010), _
            'bool', 0, 'dword', $PID)
    If @error Or Not $hProcess[0] Then Return SetError(@error + 20, @extended, '')

I've checked $PID is correct for the window.

Edited by VAN0

Share this post


Link to post
Share on other sites
JohnOne

Probably need different access to the process, maybe it's protected or is running with administritive right or something.

You can read about access rights here, there are probably constants in the WinAPI includes.


AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Share this post


Link to post
Share on other sites
VAN0

Thank you. This is more then I can chew right now. I'm not fully understanding how this code works in the first place.

For now I use win32_process class. Much slower, but works fine for my use:

Func __WinAPI_GetWindowFileName($hWnd)

    Local $PID = 0

    Local $Result = DllCall("user32.dll", "bool", "IsWindow", "hwnd", $hWnd)
    If $Result[0] Then
        $Result = DllCall("user32.dll", "dword", "GetWindowThreadProcessId", "hwnd", $hWnd, "dword*", 0)
        $PID = $Result[2]
    EndIf
    If Not $PID Then Return SetError(1, 0, '')
    $Result = __WinAPI_GetProcessFileName($PID)
    If @error Then
        Dim $oWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
        $o_ColListOfProcesses = $oWMIService.ExecQuery ("SELECT * FROM Win32_Process WHERE ProcessId = " & $PID)
        $er = @error
        $ex = @extended
        For $o_ObjProcess in $o_ColListOfProcesses
                Return $o_ObjProcess.ExecutablePath
        Next

        Return SetError($er, $ex, '')
    EndIf

    Return $Result
EndFunc   ;==>__WinAPI_GetWindowFileName
Edited by VAN0

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  

×