Get File Path from Window Handle

Share your advanced PureBasic knowledge/code with the community.
CalamityJames
User
User
Posts: 81
Joined: Sat Mar 13, 2010 4:50 pm

Get File Path from Window Handle

Post 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"?
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Get File Path from Window Handle

Post 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.
"Have you tried turning it off and on again ?"
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Get File Path from Window Handle

Post 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)
BERESHEIT
CalamityJames
User
User
Posts: 81
Joined: Sat Mar 13, 2010 4:50 pm

Re: Get File Path from Window Handle

Post 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.
Post Reply