设备句柄的GetFinalPathNameByHandle失败

时间:2017-09-24 00:27:29

标签: windows winapi

如果我使用CreateFile创建一个文件句柄,用于" \\?\ NUL"或" \\?\ pipe \",句柄映射到为" \ Device \ Null"打开的File对象。或" \ Device \ NamedPipe"内核设备对象。由于GetFinalPathNameByHandle函数支持VOLUME_NAME_NT属性,该属性已经返回像" \ Device \ HarddiskVolume1 \"这样的字符串,我以为我能够为设备获取类似的路径处理。但是,调用总是失败,无论是ERROR_INVALID_FUNCTION还是ERROR_INVALID_PARAMETER,都取决于打开文件的访问标记。

事实上,几乎所有对类似函数的调用都失败了 - 比如GetFileInformationByHandleGetFileInformationByHandleEx,甚至调用NT函数,例如NtQueryInformationFile - 返回STATUS_INVALID_PARAMETER。唯一不会失败的功能是GetFileType(能够识别管道),GetVolumeInformationByHandle(能够识别驱动程序)和NtQueryInformationFile FileModeInformation

所有这些功能在任何标准文件上使用时都有效,但设备文件句柄不支持它们。如何从设备句柄获取路径信息?是否有一些NtIo函数可以使用?如果我唯一拥有的是手柄,还有其他方法可以识别设备吗?

1 个答案:

答案 0 :(得分:0)

正如RbMmeryksun指出的那样,实现该对象的驱动程序必须能够处理IRP_MJ_QUERY_INFORMATION,但如果没有,则该对象的名称可以是通过 NtQueryObject 获取,将 ObjectNameInformation (1)传递给它,它将获得带有对象名称的OBJECT_NAME_INFORMATION结构。

因为我打算用C#调用它,所以这里是它的P / Invoke代码:

static class Ntdll
{
    [DllImport("ntdll.dll")]
    static extern int NtQueryObject(
        IntPtr Handle, int ObjectInformationClass,
        IntPtr ObjectInformation, int ObjectInformationLength,
        out int ReturnLength
    );

    public static int NtQueryObject(IntPtr Handle, int ObjectInformationClass, IntPtr ObjectInformation, int ObjectInformationLength)
    {
        int length;
        int status = NtQueryObject(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, out length);
        if(status != 0) throw new Win32Exception(RtlNtStatusToDosError(status));
        return length;
    }

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
    public struct OBJECT_NAME_INFORMATION
    {
        public ushort Length;
        public ushort MaximumLength;
        public string Buffer;
    }

    [DebuggerStepThrough]
    public static void NtQueryObject(IntPtr Handle, out OBJECT_NAME_INFORMATION ObjectNameInformation)
    {
        IntPtr buffer = Marshal.AllocHGlobal(1024);
        try{
            Ntdll.NtQueryObject(Handle, 1, buffer, 1024);
            ObjectNameInformation = Marshal.PtrToStructure<Ntdll.OBJECT_NAME_INFORMATION>(buffer);
        }finally{
            Marshal.FreeHGlobal(buffer);
        }
    }
}

然后可以通过将"\\?\GlobalRoot"添加到 Buffer 成员来构建路径。