How to get name associated with open HANDLE

后端 未结 7 597
终归单人心
终归单人心 2020-11-27 06:13

What\'s the easiest way to get the filename associated with an open HANDLE in Win32?

7条回答
  •  情话喂你
    2020-11-27 06:36

    There is a correct (although undocumented) way to do this on Windows XP which also works with directories -- the same method GetFinalPathNameByHandle uses on Windows Vista and later.

    Here are the eneded declarations. Some of these are already in WInternl.h and MountMgr.h but I just put them here anyway:

    #include "stdafx.h"
    #include 
    #include 
    
    enum OBJECT_INFORMATION_CLASS { ObjectNameInformation = 1 };
    enum FILE_INFORMATION_CLASS { FileNameInformation = 9 };
    struct FILE_NAME_INFORMATION { ULONG FileNameLength; WCHAR FileName[1]; };
    struct IO_STATUS_BLOCK { PVOID Dummy; ULONG_PTR Information; };
    struct UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; };
    struct MOUNTMGR_TARGET_NAME { USHORT DeviceNameLength; WCHAR DeviceName[1]; };
    struct MOUNTMGR_VOLUME_PATHS { ULONG MultiSzLength; WCHAR MultiSz[1]; };
    
    extern "C" NTSYSAPI NTSTATUS NTAPI NtQueryObject(IN HANDLE Handle OPTIONAL,
        IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
        OUT PVOID ObjectInformation OPTIONAL, IN ULONG ObjectInformationLength,
        OUT PULONG ReturnLength OPTIONAL);
    extern "C" NTSYSAPI NTSTATUS NTAPI NtQueryInformationFile(IN HANDLE FileHandle,
        OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation,
        IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass);
    
    #define MOUNTMGRCONTROLTYPE ((ULONG) 'm')
    #define IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH \
        CTL_CODE(MOUNTMGRCONTROLTYPE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS)
    
    union ANY_BUFFER {
        MOUNTMGR_TARGET_NAME TargetName;
        MOUNTMGR_VOLUME_PATHS TargetPaths;
        FILE_NAME_INFORMATION NameInfo;
        UNICODE_STRING UnicodeString;
        WCHAR Buffer[USHRT_MAX];
    };
    

    Here's the core function:

    LPWSTR GetFilePath(HANDLE hFile)
    {
        static ANY_BUFFER nameFull, nameRel, nameMnt;
        ULONG returnedLength; IO_STATUS_BLOCK iosb; NTSTATUS status;
        status = NtQueryObject(hFile, ObjectNameInformation,
            nameFull.Buffer, sizeof(nameFull.Buffer), &returnedLength);
        assert(status == 0);
        status = NtQueryInformationFile(hFile, &iosb, nameRel.Buffer,
            sizeof(nameRel.Buffer), FileNameInformation);
        assert(status == 0);
        //I'm not sure how this works with network paths...
        assert(nameFull.UnicodeString.Length >= nameRel.NameInfo.FileNameLength);
        nameMnt.TargetName.DeviceNameLength = (USHORT)(
            nameFull.UnicodeString.Length - nameRel.NameInfo.FileNameLength);
        wcsncpy(nameMnt.TargetName.DeviceName, nameFull.UnicodeString.Buffer,
            nameMnt.TargetName.DeviceNameLength / sizeof(WCHAR));
        HANDLE hMountPointMgr = CreateFile(_T("\\\\.\\MountPointManager"),
            0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
            NULL, OPEN_EXISTING, 0, NULL);
        __try
        {
            DWORD bytesReturned;
            BOOL success = DeviceIoControl(hMountPointMgr,
                IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH, &nameMnt,
                sizeof(nameMnt), &nameMnt, sizeof(nameMnt),
                &bytesReturned, NULL);
            assert(success && nameMnt.TargetPaths.MultiSzLength > 0);
            wcsncat(nameMnt.TargetPaths.MultiSz, nameRel.NameInfo.FileName,
                nameRel.NameInfo.FileNameLength / sizeof(WCHAR));
            return nameMnt.TargetPaths.MultiSz;
        }
        __finally { CloseHandle(hMountPointMgr); }
    }
    

    and here's an example usage:

    int _tmain(int argc, _TCHAR* argv[])
    {
        HANDLE hFile = CreateFile(_T("\\\\.\\C:\\Windows\\Notepad.exe"),
            0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
        assert(hFile != NULL && hFile != INVALID_HANDLE_VALUE);
        __try
        {
            wprintf(L"%s\n", GetFilePath(hFile));
            //  Prints:
            //  C:\Windows\notepad.exe
        }
        __finally { CloseHandle(hFile); }
        return 0;
    }
    

提交回复
热议问题