WinBatch® Technical Support Forum

All Things WinBatch => WinBatch => Topic started by: fhammer on January 25, 2019, 08:47:05 PM

Title: get filename using filehandle
Post by: fhammer on January 25, 2019, 08:47:05 PM
Is there a way to retrieve the filename, using only the filehandle of an open file?

Thank you.
Title: Re: get filename using filehandle
Post by: td on January 26, 2019, 09:06:41 AM
Probably an easier way but here is one approach:

Code (winbatch) Select
;; Open a test file.
hDummy = FileOpen('c:\temp\dummy.txt', 'Read')

;; Convert the handle to a win32 file handle.
hFile = Intcontrol(94, hDummy, 0, 0, 0)

;; Get the test file's full cononical name.
nBuffSize = 260 ; MAX_PATH
hBuffer = BinaryAlloc(nBuffSize)
nChars = DllCall('kernel32.dll',long:'GetFinalPathNameByHandleA', long_ptr:hFile, lpbinary:hBuffer, long:nbuffSize, long:0)
BinaryEODSet(hBuffer, nChars)
strFullName = BinaryPeekStr(hBuffer, 0, nChars)

BinaryFree(hBuffer)
FileClose(hDummy)

Message('Test File Name', strFullName)
exit


This the 'GetFinalPathNameByHandleA' function is only available on Windows Vista and newer versions of Windows.
Title: Re: get filename using filehandle
Post by: fhammer on January 26, 2019, 10:44:08 AM
It worked. Thanks for the code sample.

Note: In the DllCall I had to change "long_ptr:hFile" to "long:hFile".

I got error "1378 DllCall: Bad parm code. Only WORD, LONG, LPSTR, LPBINARY or LPNULL" with the original.

Thanks again!!
Title: Re: get filename using filehandle
Post by: td on January 26, 2019, 04:48:17 PM
Quote from: fhammer on January 26, 2019, 10:44:08 AM

Note: In the DllCall I had to change "long_ptr:hFile" to "long:hFile".

I got error "1378 DllCall: Bad parm code. Only WORD, LONG, LPSTR, LPBINARY or LPNULL" with the original.


That must be because you are using an older version of WinBatch. "Long_ptr" was added in 2018B.  "Long_ptr" allows you to use the same script with both 32-bit and 64-bit WinBatch because handles are 64-bits long on 64-bit systems.   Most kernel32 and user32 handles only have 32 bits of significant data on 64-bit Windows systems when used with 64-bit WinBatch but not all 64-bit system handles restrict themselves to only 32 bits of significants.  So using "long_ptr" with 2018b or newer is the best option.
Title: Re: get filename using filehandle
Post by: stanl on January 27, 2019, 04:44:14 AM
Curious.  Tony, your code referenced Intcontrol 94 - which appears to only apply to fileopen() - so you already know the name of the file. This begs the question as to where the OP obtained the file handle in the first place. I bring this up because I saw a reference to NTDll.lib and NTQueryObject() function.

Didn't realize that lib was available on my Win10 laptop under Program Files (x86). It is undocumented here

http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FType%20independed%2FNtQueryObject.html

and looks like it has a lot of usefulness. So, without mudding up this thread, would like to test if that function can be called from WB.
Title: Re: get filename using filehandle
Post by: td on January 27, 2019, 09:37:43 AM
I think you missed the point of the example script.  Fhammer did not state the type of file handle that a file name was needed for.  It could have been either a WIL file handle or a Win32 file handle.  The point of using IntControl 94 was to obtain a Win32 handle to test the DllCall and not to obtain the name of a file opened with FileOpen.  That said I can imagine scenarios where it would be necessary to obtain the name of a file even if you originally opened the file using the name.  The example is intended to demonstrate obtaining the file name no matter the purpose nor the type of file handle.

The Ntdll.dll has been around since Windows NT - hence the name.  The function NTQueryObject() is part of the WDK used for developing Windows device drivers. Many WDK functions have both user-mode and kernel-mode versions.  You can't easily call the kernel-mode version from WIL because WinBatch is a user-mode program.  User-mode (assuming this function because it is listed under system services is user-mode callable) and kernel-mode versions of WDK functions can produce different results so I won't hazard a guess as to the outcome of attempting to call the function using DllCall. 

I do question the notion that it is somehow "hidden".  See the MSFT documentation:

https://docs.microsoft.com/en-us/windows/desktop/api/winternl/nf-winternl-ntqueryobject

Title: Re: get filename using filehandle
Post by: td on January 27, 2019, 09:46:48 AM
For what it's worth the WDK header file has the following comment regarding the NTQueryObject() function,

//
// use the Win32 APIs instead
//     GetFileInformationByHandle
//     GetFileInformationByHandleEx
//     GetProcessInformation
//     GetThreadInformation
//     
Title: Re: get filename using filehandle
Post by: stanl on January 28, 2019, 03:35:03 AM
Point taken. Your initial response mentioned there may be an easier way, then you noted the OP may not have a recent WB distro. I was just curious if NTQueryObject() might be worth looking at and obviously it isn't.