Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何获取与打开句柄关联的名称_C_Windows_Winapi - Fatal编程技术网

C 如何获取与打开句柄关联的名称

C 如何获取与打开句柄关联的名称,c,windows,winapi,C,Windows,Winapi,在Win32中,获取与打开句柄关联的文件名的最简单方法是什么?在Unix上,没有可靠的方法。在使用传统unix文件系统的unix中,您可以打开一个文件,然后取消链接(从目录中删除其条目)并使用它,此时名称不会存储在任何位置。此外,由于一个文件可能有多个硬链接到文件系统中,因此每个名称都是等效的,因此,一旦只有打开的句柄,就不清楚应该映射回哪个文件名 因此,您可以使用其他答案在Win32上实现这一点,但是如果您需要将应用程序移植到unix环境,那么您就不走运了。我给你的建议是,如果可能的话,重构你

在Win32中,获取与打开句柄关联的文件名的最简单方法是什么?

在Unix上,没有可靠的方法。在使用传统unix文件系统的unix中,您可以打开一个文件,然后取消链接(从目录中删除其条目)并使用它,此时名称不会存储在任何位置。此外,由于一个文件可能有多个硬链接到文件系统中,因此每个名称都是等效的,因此,一旦只有打开的句柄,就不清楚应该映射回哪个文件名

因此,您可以使用其他答案在Win32上实现这一点,但是如果您需要将应用程序移植到unix环境,那么您就不走运了。我给你的建议是,如果可能的话,重构你的程序,这样你就不需要操作系统来维护一个开放的资源到文件名的连接。

编辑谢谢你对Vista或Server 2008的评论。我在页面上没看到。我想我应该读整篇文章;)

看起来您可以使用它来获取此信息

您可能希望执行以下操作:

GetFileInformationByHandleEx( fileHandle, FILE_NAME_INFO, lpFileInformation, sizeof(FILE_NAME_INFO));
仔细检查MSDN页面,确保我没有严重误导您:)

干杯


Taylor

如果您需要在Win32 Vista或Server 2008之前的版本中执行此操作,请查看
GetMappedFileName(…)
函数,它是Win32中保存最好的机密之一。通过使用一点
C/C++-
fu,您可以对所讨论的文件的一小部分进行内存映射,然后将该句柄传递给该函数

此外,在Win32上,您无法真正删除打开的文件(另一个答案中提到的打开/取消链接问题)-您可以在关闭时将其标记为删除,但在关闭最后一个打开句柄之前,它仍将挂起。不知道如果映射(通过
mmap(…)
)本例中的文件会有帮助,因为它必须指向物理文件


-=-James.

FWIW,下面是Prakash在Python中使用奇妙的

在Windows XP上有一种正确的(尽管没有文档记录)方法可以做到这一点,该方法也适用于目录——与在Windows Vista和更高版本上使用的方法相同

以下是未经授权的声明。其中一些已经在
WInternl.h
MountMgr.h
中了,但我还是把它们放在这里:

#include "stdafx.h"
#include <Windows.h>
#include <assert.h>

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];
};
下面是一个示例用法:

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;
}

我试过Mehrdad在这里发布的代码。这是可行的,但有局限性:

  • 它不应用于网络共享,因为MountPointManager可能会挂起很长时间
  • 它使用未记录的API(IOCTL\u MOUNTMGR\u QUERY\u DOS\u VOLUME\u PATH),我不太喜欢这样
  • 它不支持创建虚拟COM端口的USB设备(我的项目中需要它)
  • 我还研究了其他方法,如
    GetFileInformationByHandleEx()
    GetFinalPathNameByHandle()
    ,但这些方法没有用,因为它们只返回路径+文件名,而不返回驱动器。另外,
    GetFinalPathNameByHandle()
    也有挂起的bug

    MSDN中的
    GetMappedFileName()
    方法(由Max在此处发布)也非常有限:

  • 它只适用于真实文件
  • 文件大小不能为零字节
  • 不支持目录、网络和COM端口
  • 代码很笨拙
  • 所以我写了自己的代码。我在WinXP和Win7、8和10上测试了它。它工作得很好

    注意:编译此代码不需要任何附加的LIB文件

    CPP文件:

    t_NtQueryObject NtQueryObject()
    {
        static t_NtQueryObject f_NtQueryObject = NULL;
        if (!f_NtQueryObject)
        {
            HMODULE h_NtDll = GetModuleHandle(L"Ntdll.dll"); // Ntdll is loaded into EVERY process!
            f_NtQueryObject = (t_NtQueryObject)GetProcAddress(h_NtDll, "NtQueryObject");
        }
        return f_NtQueryObject;
    }
    
    
    // returns
    // "\Device\HarddiskVolume3"                                (Harddisk Drive)
    // "\Device\HarddiskVolume3\Temp"                           (Harddisk Directory)
    // "\Device\HarddiskVolume3\Temp\transparent.jpeg"          (Harddisk File)
    // "\Device\Harddisk1\DP(1)0-0+6\foto.jpg"                  (USB stick)
    // "\Device\TrueCryptVolumeP\Data\Passwords.txt"            (Truecrypt Volume)
    // "\Device\Floppy0\Autoexec.bat"                           (Floppy disk)
    // "\Device\CdRom1\VIDEO_TS\VTS_01_0.VOB"                   (DVD drive)
    // "\Device\Serial1"                                        (real COM port)
    // "\Device\USBSER000"                                      (virtual COM port)
    // "\Device\Mup\ComputerName\C$\Boot.ini"                   (network drive share,  Windows 7)
    // "\Device\LanmanRedirector\ComputerName\C$\Boot.ini"      (network drive share,  Windwos XP)
    // "\Device\LanmanRedirector\ComputerName\Shares\Dance.m3u" (network folder share, Windwos XP)
    // "\Device\Afd"                                            (internet socket)
    // "\Device\Console000F"                                    (unique name for any Console handle)
    // "\Device\NamedPipe\Pipename"                             (named pipe)
    // "\BaseNamedObjects\Objectname"                           (named mutex, named event, named semaphore)
    // "\REGISTRY\MACHINE\SOFTWARE\Classes\.txt"                (HKEY_CLASSES_ROOT\.txt)
    DWORD GetNtPathFromHandle(HANDLE h_File, CString* ps_NTPath)
    {
        if (h_File == 0 || h_File == INVALID_HANDLE_VALUE)
            return ERROR_INVALID_HANDLE;
    
        // NtQueryObject() returns STATUS_INVALID_HANDLE for Console handles
        if (IsConsoleHandle(h_File))
        {
            ps_NTPath->Format(L"\\Device\\Console%04X", (DWORD)(DWORD_PTR)h_File);
            return 0;
        }
    
        BYTE  u8_Buffer[2000];
        DWORD u32_ReqLength = 0;
    
        UNICODE_STRING* pk_Info = &((OBJECT_NAME_INFORMATION*)u8_Buffer)->Name;
        pk_Info->Buffer = 0;
        pk_Info->Length = 0;
    
        // IMPORTANT: The return value from NtQueryObject is bullshit! (driver bug?)
        // - The function may return STATUS_NOT_SUPPORTED although it has successfully written to the buffer.
        // - The function returns STATUS_SUCCESS although h_File == 0xFFFFFFFF
        NtQueryObject()(h_File, ObjectNameInformation, u8_Buffer, sizeof(u8_Buffer), &u32_ReqLength);
    
        // On error pk_Info->Buffer is NULL
        if (!pk_Info->Buffer || !pk_Info->Length)
            return ERROR_FILE_NOT_FOUND;
    
        pk_Info->Buffer[pk_Info->Length /2] = 0; // Length in Bytes!
    
        *ps_NTPath = pk_Info->Buffer;
        return 0;
    }
    
    // converts
    // "\Device\HarddiskVolume3"                                -> "E:"
    // "\Device\HarddiskVolume3\Temp"                           -> "E:\Temp"
    // "\Device\HarddiskVolume3\Temp\transparent.jpeg"          -> "E:\Temp\transparent.jpeg"
    // "\Device\Harddisk1\DP(1)0-0+6\foto.jpg"                  -> "I:\foto.jpg"
    // "\Device\TrueCryptVolumeP\Data\Passwords.txt"            -> "P:\Data\Passwords.txt"
    // "\Device\Floppy0\Autoexec.bat"                           -> "A:\Autoexec.bat"
    // "\Device\CdRom1\VIDEO_TS\VTS_01_0.VOB"                   -> "H:\VIDEO_TS\VTS_01_0.VOB"
    // "\Device\Serial1"                                        -> "COM1"
    // "\Device\USBSER000"                                      -> "COM4"
    // "\Device\Mup\ComputerName\C$\Boot.ini"                   -> "\\ComputerName\C$\Boot.ini"
    // "\Device\LanmanRedirector\ComputerName\C$\Boot.ini"      -> "\\ComputerName\C$\Boot.ini"
    // "\Device\LanmanRedirector\ComputerName\Shares\Dance.m3u" -> "\\ComputerName\Shares\Dance.m3u"
    // returns an error for any other device type
    DWORD GetDosPathFromNtPath(const WCHAR* u16_NTPath, CString* ps_DosPath)
    {
        DWORD u32_Error;
    
        if (wcsnicmp(u16_NTPath, L"\\Device\\Serial", 14) == 0 || // e.g. "Serial1"
            wcsnicmp(u16_NTPath, L"\\Device\\UsbSer", 14) == 0)   // e.g. "USBSER000"
        {
            HKEY h_Key; 
            if (u32_Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Hardware\\DeviceMap\\SerialComm", 0, KEY_QUERY_VALUE, &h_Key))
                return u32_Error;
    
            WCHAR u16_ComPort[50];
    
            DWORD u32_Type;
            DWORD u32_Size = sizeof(u16_ComPort); 
            if (u32_Error = RegQueryValueEx(h_Key, u16_NTPath, 0, &u32_Type, (BYTE*)u16_ComPort, &u32_Size))
            {
                RegCloseKey(h_Key);
                return ERROR_UNKNOWN_PORT;
            }
    
            *ps_DosPath = u16_ComPort;
            RegCloseKey(h_Key);
            return 0;
        }
    
        if (wcsnicmp(u16_NTPath, L"\\Device\\LanmanRedirector\\", 25) == 0) // Win XP
        {
            *ps_DosPath  = L"\\\\";
            *ps_DosPath += (u16_NTPath + 25);
            return 0;
        }
    
        if (wcsnicmp(u16_NTPath, L"\\Device\\Mup\\", 12) == 0) // Win 7
        {
            *ps_DosPath  = L"\\\\";
            *ps_DosPath += (u16_NTPath + 12);
            return 0;
        }
    
        WCHAR u16_Drives[300];
        if (!GetLogicalDriveStrings(300, u16_Drives))
            return GetLastError();
    
        WCHAR* u16_Drv = u16_Drives;
        while (u16_Drv[0])
        {
            WCHAR* u16_Next = u16_Drv +wcslen(u16_Drv) +1;
    
            u16_Drv[2] = 0; // the backslash is not allowed for QueryDosDevice()
    
            WCHAR u16_NtVolume[1000];
            u16_NtVolume[0] = 0;
    
            // may return multiple strings!
            // returns very weird strings for network shares
            if (!QueryDosDevice(u16_Drv, u16_NtVolume, sizeof(u16_NtVolume) /2))
                return GetLastError();
    
            int s32_Len = (int)wcslen(u16_NtVolume);
            if (s32_Len > 0 && wcsnicmp(u16_NTPath, u16_NtVolume, s32_Len) == 0)
            {
                *ps_DosPath  =  u16_Drv;
                *ps_DosPath += (u16_NTPath + s32_Len);
                return 0;
            }
    
            u16_Drv = u16_Next;
        }
        return ERROR_BAD_PATHNAME;
    }
    
    #pragma warning(disable: 4996) // wcsnicmp deprecated
    #include <winternl.h>
    
    // This makro assures that INVALID_HANDLE_VALUE (0xFFFFFFFF) returns FALSE
    #define IsConsoleHandle(h) (((((ULONG_PTR)h) & 0x10000003) == 0x3) ? TRUE : FALSE)
    
    enum OBJECT_INFORMATION_CLASS 
    {
        ObjectBasicInformation, 
        ObjectNameInformation,
        ObjectTypeInformation, 
        ObjectAllInformation, 
        ObjectDataInformation
    };
    
    struct OBJECT_NAME_INFORMATION 
    {
        UNICODE_STRING Name; // defined in winternl.h
        WCHAR NameBuffer;
    };
    
    typedef NTSTATUS (NTAPI* t_NtQueryObject)(HANDLE Handle, OBJECT_INFORMATION_CLASS Info, PVOID Buffer, ULONG BufferSize, PULONG ReturnLength);   
    
    头文件:

    t_NtQueryObject NtQueryObject()
    {
        static t_NtQueryObject f_NtQueryObject = NULL;
        if (!f_NtQueryObject)
        {
            HMODULE h_NtDll = GetModuleHandle(L"Ntdll.dll"); // Ntdll is loaded into EVERY process!
            f_NtQueryObject = (t_NtQueryObject)GetProcAddress(h_NtDll, "NtQueryObject");
        }
        return f_NtQueryObject;
    }
    
    
    // returns
    // "\Device\HarddiskVolume3"                                (Harddisk Drive)
    // "\Device\HarddiskVolume3\Temp"                           (Harddisk Directory)
    // "\Device\HarddiskVolume3\Temp\transparent.jpeg"          (Harddisk File)
    // "\Device\Harddisk1\DP(1)0-0+6\foto.jpg"                  (USB stick)
    // "\Device\TrueCryptVolumeP\Data\Passwords.txt"            (Truecrypt Volume)
    // "\Device\Floppy0\Autoexec.bat"                           (Floppy disk)
    // "\Device\CdRom1\VIDEO_TS\VTS_01_0.VOB"                   (DVD drive)
    // "\Device\Serial1"                                        (real COM port)
    // "\Device\USBSER000"                                      (virtual COM port)
    // "\Device\Mup\ComputerName\C$\Boot.ini"                   (network drive share,  Windows 7)
    // "\Device\LanmanRedirector\ComputerName\C$\Boot.ini"      (network drive share,  Windwos XP)
    // "\Device\LanmanRedirector\ComputerName\Shares\Dance.m3u" (network folder share, Windwos XP)
    // "\Device\Afd"                                            (internet socket)
    // "\Device\Console000F"                                    (unique name for any Console handle)
    // "\Device\NamedPipe\Pipename"                             (named pipe)
    // "\BaseNamedObjects\Objectname"                           (named mutex, named event, named semaphore)
    // "\REGISTRY\MACHINE\SOFTWARE\Classes\.txt"                (HKEY_CLASSES_ROOT\.txt)
    DWORD GetNtPathFromHandle(HANDLE h_File, CString* ps_NTPath)
    {
        if (h_File == 0 || h_File == INVALID_HANDLE_VALUE)
            return ERROR_INVALID_HANDLE;
    
        // NtQueryObject() returns STATUS_INVALID_HANDLE for Console handles
        if (IsConsoleHandle(h_File))
        {
            ps_NTPath->Format(L"\\Device\\Console%04X", (DWORD)(DWORD_PTR)h_File);
            return 0;
        }
    
        BYTE  u8_Buffer[2000];
        DWORD u32_ReqLength = 0;
    
        UNICODE_STRING* pk_Info = &((OBJECT_NAME_INFORMATION*)u8_Buffer)->Name;
        pk_Info->Buffer = 0;
        pk_Info->Length = 0;
    
        // IMPORTANT: The return value from NtQueryObject is bullshit! (driver bug?)
        // - The function may return STATUS_NOT_SUPPORTED although it has successfully written to the buffer.
        // - The function returns STATUS_SUCCESS although h_File == 0xFFFFFFFF
        NtQueryObject()(h_File, ObjectNameInformation, u8_Buffer, sizeof(u8_Buffer), &u32_ReqLength);
    
        // On error pk_Info->Buffer is NULL
        if (!pk_Info->Buffer || !pk_Info->Length)
            return ERROR_FILE_NOT_FOUND;
    
        pk_Info->Buffer[pk_Info->Length /2] = 0; // Length in Bytes!
    
        *ps_NTPath = pk_Info->Buffer;
        return 0;
    }
    
    // converts
    // "\Device\HarddiskVolume3"                                -> "E:"
    // "\Device\HarddiskVolume3\Temp"                           -> "E:\Temp"
    // "\Device\HarddiskVolume3\Temp\transparent.jpeg"          -> "E:\Temp\transparent.jpeg"
    // "\Device\Harddisk1\DP(1)0-0+6\foto.jpg"                  -> "I:\foto.jpg"
    // "\Device\TrueCryptVolumeP\Data\Passwords.txt"            -> "P:\Data\Passwords.txt"
    // "\Device\Floppy0\Autoexec.bat"                           -> "A:\Autoexec.bat"
    // "\Device\CdRom1\VIDEO_TS\VTS_01_0.VOB"                   -> "H:\VIDEO_TS\VTS_01_0.VOB"
    // "\Device\Serial1"                                        -> "COM1"
    // "\Device\USBSER000"                                      -> "COM4"
    // "\Device\Mup\ComputerName\C$\Boot.ini"                   -> "\\ComputerName\C$\Boot.ini"
    // "\Device\LanmanRedirector\ComputerName\C$\Boot.ini"      -> "\\ComputerName\C$\Boot.ini"
    // "\Device\LanmanRedirector\ComputerName\Shares\Dance.m3u" -> "\\ComputerName\Shares\Dance.m3u"
    // returns an error for any other device type
    DWORD GetDosPathFromNtPath(const WCHAR* u16_NTPath, CString* ps_DosPath)
    {
        DWORD u32_Error;
    
        if (wcsnicmp(u16_NTPath, L"\\Device\\Serial", 14) == 0 || // e.g. "Serial1"
            wcsnicmp(u16_NTPath, L"\\Device\\UsbSer", 14) == 0)   // e.g. "USBSER000"
        {
            HKEY h_Key; 
            if (u32_Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Hardware\\DeviceMap\\SerialComm", 0, KEY_QUERY_VALUE, &h_Key))
                return u32_Error;
    
            WCHAR u16_ComPort[50];
    
            DWORD u32_Type;
            DWORD u32_Size = sizeof(u16_ComPort); 
            if (u32_Error = RegQueryValueEx(h_Key, u16_NTPath, 0, &u32_Type, (BYTE*)u16_ComPort, &u32_Size))
            {
                RegCloseKey(h_Key);
                return ERROR_UNKNOWN_PORT;
            }
    
            *ps_DosPath = u16_ComPort;
            RegCloseKey(h_Key);
            return 0;
        }
    
        if (wcsnicmp(u16_NTPath, L"\\Device\\LanmanRedirector\\", 25) == 0) // Win XP
        {
            *ps_DosPath  = L"\\\\";
            *ps_DosPath += (u16_NTPath + 25);
            return 0;
        }
    
        if (wcsnicmp(u16_NTPath, L"\\Device\\Mup\\", 12) == 0) // Win 7
        {
            *ps_DosPath  = L"\\\\";
            *ps_DosPath += (u16_NTPath + 12);
            return 0;
        }
    
        WCHAR u16_Drives[300];
        if (!GetLogicalDriveStrings(300, u16_Drives))
            return GetLastError();
    
        WCHAR* u16_Drv = u16_Drives;
        while (u16_Drv[0])
        {
            WCHAR* u16_Next = u16_Drv +wcslen(u16_Drv) +1;
    
            u16_Drv[2] = 0; // the backslash is not allowed for QueryDosDevice()
    
            WCHAR u16_NtVolume[1000];
            u16_NtVolume[0] = 0;
    
            // may return multiple strings!
            // returns very weird strings for network shares
            if (!QueryDosDevice(u16_Drv, u16_NtVolume, sizeof(u16_NtVolume) /2))
                return GetLastError();
    
            int s32_Len = (int)wcslen(u16_NtVolume);
            if (s32_Len > 0 && wcsnicmp(u16_NTPath, u16_NtVolume, s32_Len) == 0)
            {
                *ps_DosPath  =  u16_Drv;
                *ps_DosPath += (u16_NTPath + s32_Len);
                return 0;
            }
    
            u16_Drv = u16_Next;
        }
        return ERROR_BAD_PATHNAME;
    }
    
    #pragma warning(disable: 4996) // wcsnicmp deprecated
    #include <winternl.h>
    
    // This makro assures that INVALID_HANDLE_VALUE (0xFFFFFFFF) returns FALSE
    #define IsConsoleHandle(h) (((((ULONG_PTR)h) & 0x10000003) == 0x3) ? TRUE : FALSE)
    
    enum OBJECT_INFORMATION_CLASS 
    {
        ObjectBasicInformation, 
        ObjectNameInformation,
        ObjectTypeInformation, 
        ObjectAllInformation, 
        ObjectDataInformation
    };
    
    struct OBJECT_NAME_INFORMATION 
    {
        UNICODE_STRING Name; // defined in winternl.h
        WCHAR NameBuffer;
    };
    
    typedef NTSTATUS (NTAPI* t_NtQueryObject)(HANDLE Handle, OBJECT_INFORMATION_CLASS Info, PVOID Buffer, ULONG BufferSize, PULONG ReturnLength);   
    
    #pragma警告(禁用:4996)//wcsnicmp已弃用
    #包括
    //此makro确保无效的\u句柄\u值(0xFFFFFFFF)返回FALSE
    #定义IsConsoleHandle(h)(((((ULONG_PTR)h)&0x10000003)==0x3)?真:假)
    枚举对象信息类
    {
    目标基本信息,
    对象名称信息,
    对象类型信息,
    对象信息,
    对象数据信息
    };
    结构对象名称信息
    {
    UNICODE_字符串名称;//在winternl.h中定义
    WCHAR名称缓冲区;
    };
    typedef NTSTATUS(NTAPI*t_NtQueryObject)(句柄句柄、对象信息、类信息、PVOID缓冲区、ULONG缓冲区大小、PULONG返回长度);
    
    对于Windows Vista和更高版本,我更喜欢使用

    对于windowsxp,我更喜欢它


    因此,我通过GetProcAddress()动态加载GetFinalPathNameByHandle(),如果失败(因为它是Windows XP),我会选择Mehrdad使用NtQueryObject()的解决方案。

    此解决方案唯一的问题是GetFileInformationByHandleEx需要Windows Vista或Server 2008(或更高版本)。我喜欢此解决方案的简单性,但我使用的是XP:-(它看起来很简单,但只返回路径+文件名,但缺少驱动器,因此没有真正的用处。FILE_NAME_INFO是一个可变长度的数据结构,第一个字符只有一个条目。因此,我想您应该将dwBufferSize计算为sizeof(DWORD)+MAX_path*sizeof(WCHAR)而不是sizeof(FILE_NAME_INFO)。很抱歉我之前的评论,因为原始帖子只要求提供文件名。因此GetFileInformationByHandleEx()不报告任何驱动器信息可能没问题。无论如何,我更喜欢使用GetFinalPathNameByHandle()适用于Windows Vista及更高版本。
    大写/小写
    ==比例太大LARGE@pmg:我同意,但我没有选择名称…Windows API已经是这样了,我只是复制/粘贴了我需要的东西。@ybungalobill:你真的需要DDK吗?我想我把SDK之外的所有东西都复制到了这里…不过值得一提GetProcAddress将绕过DDK的需要。此代码可以工作,但有一些限制。有关更多详细信息,请参阅我在此处发布的内容。此代码可以工作,但有一些限制。请参阅我在此处发布的内容首先,此代码至少需要kernel32.lib和advapi32.lib来编译。似乎Elmue“想说”此代码不需要
    char buf[MAX_PATH];
    GetFinalPathNameByHandleA(fileHandle, buf, sizeof(buf), VOLUME_NAME_DOS)