<p>What's the easiest way to get the filename associated with an open HANDLE in Win32?</p>

[{'answer_id': 65252, 'author': 'Daniel Papasian', 'author_id': 7548, 'author_profile': 'https://Stackoverflow.com/users/7548', 'pm_score': 0, 'selected': False, 'text': "<p>On unixes there is no real way of reliably doing this.  In unix with the traditional unix filesystem, you can open a file and then unlink it (remove its entry from the directory) and use it, at which point the name isn't stored anywhere.  In addition, because a file may have multiple hardlinks into the filesystem, each of the names are equivalent, so once you've got just the open handle it wouldn't be clear which filename you should map back towards.</p>\n\n<p>So, you may be able to do this on Win32 using the other answers, but should you ever need to port the application to a unix enviornment, you'll be out of luck.  My advice to you is to refactor your program, if possible, so that you don't need the OS to be able to maintain an open resource to filename connection.</p>\n"}, {'answer_id': 65254, 'author': 'Taylor Price', 'author_id': 3805, 'author_profile': 'https://Stackoverflow.com/users/3805', 'pm_score': 2, 'selected': False, 'text': '<p><em>edit</em> Thanks for the comments about this being Vista or Server 2008 only. I missed that in the page. Guess I should have read the <em>whole</em> article ;)</p>\n\n<p>It looks like you can use <a href="http://msdn.microsoft.com/en-us/library/aa364953.aspx" rel="nofollow noreferrer">GetFileInformationByHandleEx()</a> to get this information.</p>\n\n<p>You\'ll likely want to do something like:</p>\n\n<pre><code>GetFileInformationByHandleEx( fileHandle, FILE_NAME_INFO, lpFileInformation, sizeof(FILE_NAME_INFO));\n</code></pre>\n\n<p>Double check the MSDN page to make sure I haven\'t misled you too badly :)</p>\n\n<p>Cheers,</p>\n\n<p>Taylor</p>\n'}, {'answer_id': 65417, 'author': 'Community', 'author_id': -1, 'author_profile': 'https://Stackoverflow.com/users/-1', 'pm_score': 0, 'selected': False, 'text': '<p>If you need to do this on Win32 pre-Vista or Server 2008, look at the <code>GetMappedFileName(...)</code> function, which is one of the best kept secrets in Win32.  WIth a little <code>C/C++-</code><em>fu</em>, you can memory map a small portion of the file in question, and then pass that handle to this function.</p>\n\n<p>Also, on Win32, you cannot really delete a file that is open (the open/unlink issue mentioned on another answer) - you can mark it for deletion on close, but it will still hang around until its last open handle is closed.  Dunno if mapping (via <code>mmap(...)</code>) the file in this case would help, because it has to point back to a physical file...</p>\n\n<p>-=- James.</p>\n'}, {'answer_id': 65775, 'author': 'Max Caceres', 'author_id': 4842, 'author_profile': 'https://Stackoverflow.com/users/4842', 'pm_score': 1, 'selected': False, 'text': '<p>FWIW, here\'s the same solution from the MSDN article suggested by Prakash in Python using the wonderful <a href="http://python.net/crew/theller/ctypes/" rel="nofollow noreferrer">ctypes</a>:</p>\n\n<pre><code>from ctypes import *\n# get handle to  c:\\boot.ini to test\nhandle = windll.kernel32.CreateFileA("c:\\\\boot.ini", 0x80000000, 3, 0, 3, 0x80, 0)\nhfilemap = windll.kernel32.CreateFileMappingA(handle, 0, 2, 0, 1, 0)\npmem = windll.kernel32.MapViewOfFile(hfilemap, 4, 0, 0, 1)\nname = create_string_buffer(1024)\nwindll.psapi.GetMappedFileNameA(windll.kernel32.GetCurrentProcess(), pmem, name, 1024)\nprint "The name for the handle 0x%08x is %s" % (handle, name.value)\n# convert device name to drive letter\nbuf = create_string_buffer(512)\nsize = windll.kernel32.GetLogicalDriveStringsA(511, buf)\nnames = buf.raw[0:size-1].split("\\0")\nfor drive in names:\n    windll.kernel32.QueryDosDeviceA(drive[0:2], buf, 512)\n    if name.value.startswith(buf.value):\n        print "%s%s" % (drive[0:2], name.value[len(buf.value):])\n        break\n</code></pre>\n'}, {'answer_id': 5286888, 'author': 'user541686', 'author_id': 541686, 'author_profile': 'https://Stackoverflow.com/users/541686', 'pm_score': 4, 'selected': False, 'text': '<p>There is a correct (although undocumented) way to do this on Windows XP <strong>which also works with directories</strong> -- the same method <a href="http://msdn.microsoft.com/en-us/library/aa364962.aspx" rel="noreferrer">GetFinalPathNameByHandle</a> uses on Windows Vista and later.</p>\n\n<p>Here are the eneded declarations. Some of these are already in <code>WInternl.h</code> and <code>MountMgr.h</code> but I just put them here anyway:</p>\n\n<pre><code>#include "stdafx.h"\n#include &lt;Windows.h&gt;\n#include &lt;assert.h&gt;\n\nenum OBJECT_INFORMATION_CLASS { ObjectNameInformation = 1 };\nenum FILE_INFORMATION_CLASS { FileNameInformation = 9 };\nstruct FILE_NAME_INFORMATION { ULONG FileNameLength; WCHAR FileName[1]; };\nstruct IO_STATUS_BLOCK { PVOID Dummy; ULONG_PTR Information; };\nstruct UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; };\nstruct MOUNTMGR_TARGET_NAME { USHORT DeviceNameLength; WCHAR DeviceName[1]; };\nstruct MOUNTMGR_VOLUME_PATHS { ULONG MultiSzLength; WCHAR MultiSz[1]; };\n\nextern "C" NTSYSAPI NTSTATUS NTAPI NtQueryObject(IN HANDLE Handle OPTIONAL,\n    IN OBJECT_INFORMATION_CLASS ObjectInformationClass,\n    OUT PVOID ObjectInformation OPTIONAL, IN ULONG ObjectInformationLength,\n    OUT PULONG ReturnLength OPTIONAL);\nextern "C" NTSYSAPI NTSTATUS NTAPI NtQueryInformationFile(IN HANDLE FileHandle,\n    OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation,\n    IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass);\n\n#define MOUNTMGRCONTROLTYPE ((ULONG) \'m\')\n#define IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH \\\n    CTL_CODE(MOUNTMGRCONTROLTYPE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS)\n\nunion ANY_BUFFER {\n    MOUNTMGR_TARGET_NAME TargetName;\n    MOUNTMGR_VOLUME_PATHS TargetPaths;\n    FILE_NAME_INFORMATION NameInfo;\n    UNICODE_STRING UnicodeString;\n    WCHAR Buffer[USHRT_MAX];\n};\n</code></pre>\n\n<p>Here\'s the core function:</p>\n\n<pre><code>LPWSTR GetFilePath(HANDLE hFile)\n{\n    static ANY_BUFFER nameFull, nameRel, nameMnt;\n    ULONG returnedLength; IO_STATUS_BLOCK iosb; NTSTATUS status;\n    status = NtQueryObject(hFile, ObjectNameInformation,\n        nameFull.Buffer, sizeof(nameFull.Buffer), &amp;returnedLength);\n    assert(status == 0);\n    status = NtQueryInformationFile(hFile, &amp;iosb, nameRel.Buffer,\n        sizeof(nameRel.Buffer), FileNameInformation);\n    assert(status == 0);\n    //I\'m not sure how this works with network paths...\n    assert(nameFull.UnicodeString.Length &gt;= nameRel.NameInfo.FileNameLength);\n    nameMnt.TargetName.DeviceNameLength = (USHORT)(\n        nameFull.UnicodeString.Length - nameRel.NameInfo.FileNameLength);\n    wcsncpy(nameMnt.TargetName.DeviceName, nameFull.UnicodeString.Buffer,\n        nameMnt.TargetName.DeviceNameLength / sizeof(WCHAR));\n    HANDLE hMountPointMgr = CreateFile(_T("\\\\\\\\.\\\\MountPointManager"),\n        0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n        NULL, OPEN_EXISTING, 0, NULL);\n    __try\n    {\n        DWORD bytesReturned;\n        BOOL success = DeviceIoControl(hMountPointMgr,\n            IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH, &amp;nameMnt,\n            sizeof(nameMnt), &amp;nameMnt, sizeof(nameMnt),\n            &amp;bytesReturned, NULL);\n        assert(success &amp;&amp; nameMnt.TargetPaths.MultiSzLength &gt; 0);\n        wcsncat(nameMnt.TargetPaths.MultiSz, nameRel.NameInfo.FileName,\n            nameRel.NameInfo.FileNameLength / sizeof(WCHAR));\n        return nameMnt.TargetPaths.MultiSz;\n    }\n    __finally { CloseHandle(hMountPointMgr); }\n}\n</code></pre>\n\n<p>and here\'s an example usage:</p>\n\n<pre><code>int _tmain(int argc, _TCHAR* argv[])\n{\n    HANDLE hFile = CreateFile(_T("\\\\\\\\.\\\\C:\\\\Windows\\\\Notepad.exe"),\n        0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);\n    assert(hFile != NULL &amp;&amp; hFile != INVALID_HANDLE_VALUE);\n    __try\n    {\n        wprintf(L"%s\\n", GetFilePath(hFile));\n        //  Prints:\n        //  C:\\Windows\\notepad.exe\n    }\n    __finally { CloseHandle(hFile); }\n    return 0;\n}\n</code></pre>\n'}, {'answer_id': 18792477, 'author': 'Elmue', 'author_id': 1487529, 'author_profile': 'https://Stackoverflow.com/users/1487529', 'pm_score': 4, 'selected': False, 'text': '<p>I tried the code posted by Mehrdad here. It works, but with limitations:</p>\n\n<ol>\n<li>It should not be used for network shares because the MountPointManager may hang for a very long time.</li>\n<li>It uses undocumented API (IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH) I don\'t like that very much</li>\n<li>It does not support USB devices that create virtual COM ports (I need that in my project)</li>\n</ol>\n\n<p>I also studied other approaches like <code>GetFileInformationByHandleEx()</code> and <code>GetFinalPathNameByHandle()</code>, but these are useless as they return only Path + Filename but without drive. Additionally <code>GetFinalPathNameByHandle()</code> also has the hanging bug.</p>\n\n<p>The <code>GetMappedFileName()</code> approach in the MSDN (posted by Max here) is also very limited:</p>\n\n<ol>\n<li>It works only with real files</li>\n<li>The file size must not be zero bytes</li>\n<li>Directories, Network and COM ports are not supported</li>\n<li>The code is clumsy</li>\n</ol>\n\n<p>So I wrote my own code. I tested it on Win XP and on Win 7, 8, and 10. It works perfectly.</p>\n\n<p>NOTE: You do NOT need any additional LIB file to compile this code!</p>\n\n<p><strong>CPP FILE:</strong></p>\n\n<pre><code>t_NtQueryObject NtQueryObject()\n{\n    static t_NtQueryObject f_NtQueryObject = NULL;\n    if (!f_NtQueryObject)\n    {\n        HMODULE h_NtDll = GetModuleHandle(L"Ntdll.dll"); // Ntdll is loaded into EVERY process!\n        f_NtQueryObject = (t_NtQueryObject)GetProcAddress(h_NtDll, "NtQueryObject");\n    }\n    return f_NtQueryObject;\n}\n\n\n// returns\n// "\\Device\\HarddiskVolume3"                                (Harddisk Drive)\n// "\\Device\\HarddiskVolume3\\Temp"                           (Harddisk Directory)\n// "\\Device\\HarddiskVolume3\\Temp\\transparent.jpeg"          (Harddisk File)\n// "\\Device\\Harddisk1\\DP(1)0-0+6\\foto.jpg"                  (USB stick)\n// "\\Device\\TrueCryptVolumeP\\Data\\Passwords.txt"            (Truecrypt Volume)\n// "\\Device\\Floppy0\\Autoexec.bat"                           (Floppy disk)\n// "\\Device\\CdRom1\\VIDEO_TS\\VTS_01_0.VOB"                   (DVD drive)\n// "\\Device\\Serial1"                                        (real COM port)\n// "\\Device\\USBSER000"                                      (virtual COM port)\n// "\\Device\\Mup\\ComputerName\\C$\\Boot.ini"                   (network drive share,  Windows 7)\n// "\\Device\\LanmanRedirector\\ComputerName\\C$\\Boot.ini"      (network drive share,  Windwos XP)\n// "\\Device\\LanmanRedirector\\ComputerName\\Shares\\Dance.m3u" (network folder share, Windwos XP)\n// "\\Device\\Afd"                                            (internet socket)\n// "\\Device\\Console000F"                                    (unique name for any Console handle)\n// "\\Device\\NamedPipe\\Pipename"                             (named pipe)\n// "\\BaseNamedObjects\\Objectname"                           (named mutex, named event, named semaphore)\n// "\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\.txt"                (HKEY_CLASSES_ROOT\\.txt)\nDWORD GetNtPathFromHandle(HANDLE h_File, CString* ps_NTPath)\n{\n    if (h_File == 0 || h_File == INVALID_HANDLE_VALUE)\n        return ERROR_INVALID_HANDLE;\n\n    // NtQueryObject() returns STATUS_INVALID_HANDLE for Console handles\n    if (IsConsoleHandle(h_File))\n    {\n        ps_NTPath-&gt;Format(L"\\\\Device\\\\Console%04X", (DWORD)(DWORD_PTR)h_File);\n        return 0;\n    }\n\n    BYTE  u8_Buffer[2000];\n    DWORD u32_ReqLength = 0;\n\n    UNICODE_STRING* pk_Info = &amp;((OBJECT_NAME_INFORMATION*)u8_Buffer)-&gt;Name;\n    pk_Info-&gt;Buffer = 0;\n    pk_Info-&gt;Length = 0;\n\n    // IMPORTANT: The return value from NtQueryObject is bullshit! (driver bug?)\n    // - The function may return STATUS_NOT_SUPPORTED although it has successfully written to the buffer.\n    // - The function returns STATUS_SUCCESS although h_File == 0xFFFFFFFF\n    NtQueryObject()(h_File, ObjectNameInformation, u8_Buffer, sizeof(u8_Buffer), &amp;u32_ReqLength);\n\n    // On error pk_Info-&gt;Buffer is NULL\n    if (!pk_Info-&gt;Buffer || !pk_Info-&gt;Length)\n        return ERROR_FILE_NOT_FOUND;\n\n    pk_Info-&gt;Buffer[pk_Info-&gt;Length /2] = 0; // Length in Bytes!\n\n    *ps_NTPath = pk_Info-&gt;Buffer;\n    return 0;\n}\n\n// converts\n// "\\Device\\HarddiskVolume3"                                -&gt; "E:"\n// "\\Device\\HarddiskVolume3\\Temp"                           -&gt; "E:\\Temp"\n// "\\Device\\HarddiskVolume3\\Temp\\transparent.jpeg"          -&gt; "E:\\Temp\\transparent.jpeg"\n// "\\Device\\Harddisk1\\DP(1)0-0+6\\foto.jpg"                  -&gt; "I:\\foto.jpg"\n// "\\Device\\TrueCryptVolumeP\\Data\\Passwords.txt"            -&gt; "P:\\Data\\Passwords.txt"\n// "\\Device\\Floppy0\\Autoexec.bat"                           -&gt; "A:\\Autoexec.bat"\n// "\\Device\\CdRom1\\VIDEO_TS\\VTS_01_0.VOB"                   -&gt; "H:\\VIDEO_TS\\VTS_01_0.VOB"\n// "\\Device\\Serial1"                                        -&gt; "COM1"\n// "\\Device\\USBSER000"                                      -&gt; "COM4"\n// "\\Device\\Mup\\ComputerName\\C$\\Boot.ini"                   -&gt; "\\\\ComputerName\\C$\\Boot.ini"\n// "\\Device\\LanmanRedirector\\ComputerName\\C$\\Boot.ini"      -&gt; "\\\\ComputerName\\C$\\Boot.ini"\n// "\\Device\\LanmanRedirector\\ComputerName\\Shares\\Dance.m3u" -&gt; "\\\\ComputerName\\Shares\\Dance.m3u"\n// returns an error for any other device type\nDWORD GetDosPathFromNtPath(const WCHAR* u16_NTPath, CString* ps_DosPath)\n{\n    DWORD u32_Error;\n\n    if (wcsnicmp(u16_NTPath, L"\\\\Device\\\\Serial", 14) == 0 || // e.g. "Serial1"\n        wcsnicmp(u16_NTPath, L"\\\\Device\\\\UsbSer", 14) == 0)   // e.g. "USBSER000"\n    {\n        HKEY h_Key; \n        if (u32_Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Hardware\\\\DeviceMap\\\\SerialComm", 0, KEY_QUERY_VALUE, &amp;h_Key))\n            return u32_Error;\n\n        WCHAR u16_ComPort[50];\n\n        DWORD u32_Type;\n        DWORD u32_Size = sizeof(u16_ComPort); \n        if (u32_Error = RegQueryValueEx(h_Key, u16_NTPath, 0, &amp;u32_Type, (BYTE*)u16_ComPort, &amp;u32_Size))\n        {\n            RegCloseKey(h_Key);\n            return ERROR_UNKNOWN_PORT;\n        }\n\n        *ps_DosPath = u16_ComPort;\n        RegCloseKey(h_Key);\n        return 0;\n    }\n\n    if (wcsnicmp(u16_NTPath, L"\\\\Device\\\\LanmanRedirector\\\\", 25) == 0) // Win XP\n    {\n        *ps_DosPath  = L"\\\\\\\\";\n        *ps_DosPath += (u16_NTPath + 25);\n        return 0;\n    }\n\n    if (wcsnicmp(u16_NTPath, L"\\\\Device\\\\Mup\\\\", 12) == 0) // Win 7\n    {\n        *ps_DosPath  = L"\\\\\\\\";\n        *ps_DosPath += (u16_NTPath + 12);\n        return 0;\n    }\n\n    WCHAR u16_Drives[300];\n    if (!GetLogicalDriveStrings(300, u16_Drives))\n        return GetLastError();\n\n    WCHAR* u16_Drv = u16_Drives;\n    while (u16_Drv[0])\n    {\n        WCHAR* u16_Next = u16_Drv +wcslen(u16_Drv) +1;\n\n        u16_Drv[2] = 0; // the backslash is not allowed for QueryDosDevice()\n\n        WCHAR u16_NtVolume[1000];\n        u16_NtVolume[0] = 0;\n\n        // may return multiple strings!\n        // returns very weird strings for network shares\n        if (!QueryDosDevice(u16_Drv, u16_NtVolume, sizeof(u16_NtVolume) /2))\n            return GetLastError();\n\n        int s32_Len = (int)wcslen(u16_NtVolume);\n        if (s32_Len &gt; 0 &amp;&amp; wcsnicmp(u16_NTPath, u16_NtVolume, s32_Len) == 0)\n        {\n            *ps_DosPath  =  u16_Drv;\n            *ps_DosPath += (u16_NTPath + s32_Len);\n            return 0;\n        }\n\n        u16_Drv = u16_Next;\n    }\n    return ERROR_BAD_PATHNAME;\n}\n</code></pre>\n\n<p><strong>HEADER FILE:</strong></p>\n\n<pre><code>#pragma warning(disable: 4996) // wcsnicmp deprecated\n#include &lt;winternl.h&gt;\n\n// This makro assures that INVALID_HANDLE_VALUE (0xFFFFFFFF) returns FALSE\n#define IsConsoleHandle(h) (((((ULONG_PTR)h) &amp; 0x10000003) == 0x3) ? TRUE : FALSE)\n\nenum OBJECT_INFORMATION_CLASS \n{\n    ObjectBasicInformation, \n    ObjectNameInformation,\n    ObjectTypeInformation, \n    ObjectAllInformation, \n    ObjectDataInformation\n};\n\nstruct OBJECT_NAME_INFORMATION \n{\n    UNICODE_STRING Name; // defined in winternl.h\n    WCHAR NameBuffer;\n};\n\ntypedef NTSTATUS (NTAPI* t_NtQueryObject)(HANDLE Handle, OBJECT_INFORMATION_CLASS Info, PVOID Buffer, ULONG BufferSize, PULONG ReturnLength);   \n</code></pre>\n'}, {'answer_id': 35863703, 'author': 'Holger', 'author_id': 4727717, 'author_profile': 'https://Stackoverflow.com/users/4727717', 'pm_score': 1, 'selected': False, 'text': '<p>For Windows Vista and later I prefer to use \n<a href="https://msdn.microsoft.com/en-us/library/aa364962.aspx" rel="nofollow noreferrer">GetFinalPathNameByHandle()</a></p>\n\n<pre><code>char buf[MAX_PATH];\nGetFinalPathNameByHandleA(fileHandle, buf, sizeof(buf), VOLUME_NAME_DOS)\n</code></pre>\n\n<p>For Windows XP I prefer the <a href="https://stackoverflow.com/a/5286888/4727717.">solution by Mehrdad</a>.  </p>\n\n<p>So I load GetFinalPathNameByHandle() dynamically via GetProcAddress() and if this fails (because it\'s Windows XP) I go for Mehrdad\'s solution with NtQueryObject()</p>\n'}]
['https://Stackoverflow.com/questions/65170', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/4842/']