CreateFile函数可以打开仅在全局下列出的设备的句柄吗?WinObj 实用程序中的目录?

Jav*_*yat 1 c++ winapi device

您知道 - 在 C++ 中,您可以通过将 I/O 设备的路径作为调用 CreateFile 函数的第一个参数传递来获取 I/O 设备的句柄。但我想知道 CreateFile 如何通过给定的路径定位和识别设备。有一天,我使用 WinObj 实用程序发现了一些有关此主题的信息,这可能是真的。
在WinObj中,有一个名为Global??的目录 它位于根目录下,可以在左侧窗格中看到。该目录包含许多“SymbolicLink”类型的项目。
当您将 I/O 设备的路径(例如“\.\C:”或“\.\Changer0”)作为函数调用中的第一个参数传递时CreateFile,CreateFile 函数会解析该路径并删除“\ .\"从中找到路径的一部分。然后它搜索全局?与该部分同名的 SymbolicLink 目录。然后它找到符号链接引用的地址,这是主要的物理设备对象名称(例如,“\Device\CdRom0”)。
那么,我的发现是真的吗?这些设备是否包含在Global 中?目录是唯一该CreateFile功能可以打开的设备吗?只是提一下:不是Global 中的所有项目?我猜目录指的是设备。

我的问题的第二部分

IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS有一天,我想通过向显示器发送控制代码来以编程方式降低显示器的屏幕亮度。问题是我不知道为CreateFile函数的第一个参数指定什么。所以我做了以下事情:

  1. 我打开设备管理器,在列表中找到了我的显示器设备。该设备的名称是“通用非 PnP 监视器”。
  2. 我右键单击该列表项,然后单击“属性”
  3. “属性”窗口中,我单击“详细信息”选项卡。然后我从属性下拉列表中选择物理设备对象名称。
  4. 在值部分,我找到了文本“\Device\0000006f”。
  5. 在WinObj中,我搜索了Global?? 引用“\Device\0000006f”的 SymbolicLink 目录。该 SymbolicLink 的名称很长:

显示#Default_Monitor#5&1193a8c7&0&UID100663553#{866519b5-3f07-4c97-b7df-24c5d8a8ccb8}

  1. 然后我在前面提到的SymbolicLink名称前加上“\.\”,并将其指定为CreateFile函数的第一个参数。

关于如何以编程方式完成所有这些操作有什么想法吗?我的意思是,我希望我的程序本身获取lpFileName参数的值。我不是直接将此字符串放在程序的源代码中。

RbM*_*bMm 5

首先,CreateFile我们可以使用 NT 命名空间中的任何名称,只要加上前缀\\?\globalroot或更好的\\?\global\globalroot前缀即可。如果我们想打开,\Device\0000006f我们可以使用\\?\globalroot\Device\0000006f\\?\global\globalroot\Device\0000006f名称。win32 sybsystem 将 win32 路径转换为 ​​NT 路径时 - 如果查看 '\?` 前缀 - 只需将其转换为\??\. 所以 nt 路径看起来像\??\[global\]globalroot\Device\0000006f。这\??虚拟目录- 它实际上并不存在。对象管理器在查看时查看本地和全局 MS-DOS 设备名称\??\。首先在本地(看起来像\Sessions\0\DosDevices\<luid>),如果在全局中找不到 - \GLOBAL??。然而,在任何本地 dos 设备目录中都存在Global指向\Global??. 作为解析后的结果,\??\global我们将被重定向到\Global??. 然后在\Global??文件夹中存在空的符号链接GLOBALROOT- 指向 NT 命名空间的根。因为解析后的结果 \\?\global\globalroot\Device\0000006f将被重新解析为,\Device\0000006f并且 \\?\globalroot\Device\0000006f如果globalroot本地设备命名空间中没有对象(通常不存在,但突然有人创建它)。

现在介绍如何打开监控设备。我们不能硬编码任何设备名称。相反,我们需要搜索支持GUID_DEVINTERFACE_MONITOR呼叫的设备CM_Get_Device_Interface_ListW并在呼叫中使用返回的名称CreateFile

#include <ntddvdeo.h>

CONFIGRET EnumMonitors()
{
    CONFIGRET err;

    static volatile UCHAR guz;

    PVOID stack = alloca(guz);
    ULONG BufferLen = 0, NeedLen = 128;

    union {
        PVOID buf;
        PWSTR pszDeviceInterface;
    };

    for(;;) 
    {
        if (BufferLen < NeedLen)
        {
            BufferLen = RtlPointerToOffset(buf = alloca((NeedLen - BufferLen) * sizeof(WCHAR)), stack) / sizeof(WCHAR);
        }

        switch (err = CM_Get_Device_Interface_ListW(const_cast<PGUID>(&GUID_DEVINTERFACE_MONITOR), 
            0, pszDeviceInterface, BufferLen, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
        {
        case CR_BUFFER_SMALL:
            if (err = CM_Get_Device_Interface_List_SizeW(&NeedLen, const_cast<PGUID>(&GUID_DEVINTERFACE_MONITOR), 
                0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
            {
        default:
            return err;
            }
            continue;

        case CR_SUCCESS:

            while (*pszDeviceInterface)
            {
                HANDLE hFile = CreateFileW(pszDeviceInterface, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, 0,
                    OPEN_EXISTING, 0, 0);

                if (hFile != INVALID_HANDLE_VALUE)
                {
                    OVERLAPPED ov = {};
                    DISPLAY_BRIGHTNESS db;
                    DeviceIoControl(hFile, IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS, 0, 0,
                        &db, sizeof(db), 0, &ov);
                    CloseHandle(hFile);

                    DbgPrint("(%x,%x,%x) %S\n", db.ucDisplayPolicy, db.ucACBrightness, db.ucDCBrightness, pszDeviceInterface);
                }

                pszDeviceInterface += 1 + wcslen(pszDeviceInterface);
            }
            return 0;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)