Page 1 of 1

Get File Path from Window Handle

Posted: Sat Jul 16, 2011 12:35 pm
by CalamityJames
All I wanted to do was to get the path of the file which launched a window. In Windows 2000 and before it's easy - you use GetModuleFileName, and in Vista and after it's also easy - you use QueryFullProcessImageName. But for Windows Xp you need this:

Code: Select all

;References:  http://msdn.microsoft.com/en-us/library/ms683217 (GetProcessImageFileName Function)
;             http://msdn.microsoft.com/en-us/library/aa364975%28VS.85%29.aspx (GetLogicalDriveStrings Function)
;             http://msdn.microsoft.com/en-us/library/aa365461%28VS.85%29.aspx (QueryDosDevice Function)

EnableExplicit

Procedure.s GetPathFromHwnd(theHwnd)
Protected ProcessId.l, ReturnValue.l, hProcess.l, ImageName.s, Dim AllDriveStringsArray.b(512)
Protected Nsize.l, Inc.l, AllDriveStrings.s, DeviceStr.s
Protected TargetPath.s, Lib.l, *pAfunc.l, DriveStringsLen.l, Counter.l
Nsize = 512
ReturnValue = GetWindowThreadProcessId_(theHwnd, @ProcessId)
If ProcessId <> 0
  hProcess = OpenProcess_(#PROCESS_QUERY_INFORMATION, #False, ProcessId)
    If hProcess <> 0
     Lib = LoadLibrary_("psapi.dll")
      If Lib
        ImageName = Space(Nsize)
        *pAfunc = GetProcAddress_(Lib, "GetProcessImageFileNameA")
        Returnvalue = CallFunctionFast(*pAfunc,hProcess, @ImageName, Nsize) ; returns the path in device format
        FreeLibrary_(Lib)
      EndIf
      If ReturnValue <> 0
        DriveStringsLen = GetLogicalDriveStrings_(Nsize, @AllDriveStringsArray(0))
        If ReturnValue <> 0
          Repeat
            DeviceStr = ""
            Repeat
              If AllDriveStringsArray(Counter) <> 0
                DeviceStr = DeviceStr + Chr(AllDriveStringsArray(Counter))
                Counter = Counter + 1
              Else
                Break
              EndIf
             ForEver
             Counter = Counter + 1
             If Right(DeviceStr, 1) = "\"
                DeviceStr = Left(DeviceStr, Len(DeviceStr) - 1)
              EndIf
              TargetPath = Space(Nsize)
              ReturnValue = QueryDosDevice_(@DeviceStr, @TargetPath, Nsize)
              If Left(ImageName, Len(TargetPath)) = TargetPath
                ProcedureReturn ReplaceString(ImageName, TargetPath, DeviceStr)
             EndIf  
         Until Counter >= DriveStringsLen
        EndIf
      EndIf
    CloseHandle_(hProcess)
  EndIf
EndIf
EndProcedure
 
 RunProgram("C:\WINDOWS\system32\calc.exe") 
 Delay(1000)
 Debug GetPathFromHwnd(FindWindow_("SciCalc", "Calculator"))
There are two things I would be interested in knowing the answer to
(1) Does it also run under Windows 7?
(2) The call to GetProcessImageFileNameA returns more data than you want (ReturnValue gives the length). Because the date you do want is null-terminated the ImageName variable gives the correct string. However, does the bit after the null get "Lost in Space"?

Re: Get File Path from Window Handle

Posted: Sat Jul 16, 2011 3:46 pm
by luis
CalamityJames wrote: (1) Does it also run under Windows 7?
Yes (ASCII), for the test to work you have to change the calc.exe class though:

Code: Select all

Debug GetPathFromHwnd(FindWindow_("CalcFrame", "Calculator"))
CalamityJames wrote: (2) The call to GetProcessImageFileNameA returns more data than you want (ReturnValue gives the length). Because the date you do want is null-terminated the ImageName variable gives the correct string. However, does the bit after the null get "Lost in Space"?
The buffer is filled for the part needed, the rest is untouched, the data is null terminated as you said.
The space allocated for the string is still 512 spaces wide, you can test this by poking a valid ascii char in place of the null and do a len() on the string.

Re: Get File Path from Window Handle

Posted: Sat Jul 16, 2011 5:38 pm
by netmaestro
So are you saying this won't work under XP?

Code: Select all

Import "c:\program files\microsoft platform sdk\lib\psapi.lib"
  GetModuleFileNameExA(a,b,c,d)
EndImport

Procedure$ PathFromHwnd(hwnd)
  GetWindowThreadProcessId_(hwnd, @pid.i)
  pHandle = OpenProcess_(#PROCESS_ALL_ACCESS,#False, pid)
  fn$=Space(#MAX_PATH+SizeOf(Character))
  GetModuleFileNameExA(phandle, 0, @fn$, #MAX_PATH)
  ProcedureReturn fn$
EndProcedure


RunProgram("calc.exe")
Delay(500)
calc=FindWindow_(0,"Calculator")

Debug PathFromHwnd(calc)

Re: Get File Path from Window Handle

Posted: Sun Jul 17, 2011 12:24 pm
by CalamityJames
According to Microsoft (http://msdn.microsoft.com/en-us/library ... %29.aspx#2) theGetModuleFileNameEx function is primarily for debuggers and GetProcessImageFileName is to be preferred as being more efficient and reliable. Having said that, it did work under XP! I used (#PROCESS_QUERY_INFORMATION | #PROCESS_VM_READ) for the Openprocess function as #PROCESS_ALL_ACCESS may not always be granted.