c++ - CreateFile 函数能否打开仅在 Global 下列出的设备的句柄?WinObj 实用程序中的目录?
问题描述
您知道 - 在 C++ 中,您可以通过在调用 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
函数的第一个参数指定什么。所以我做了以下事情:
- 我打开设备管理器,在列表中找到了我的监控设备。该设备的名称是“通用非即插即用监视器”。
- 我右键单击该列表项并单击Properties。
- 在“属性”窗口中,我单击了“详细信息”选项卡。然后我从属性下拉列表中选择物理设备对象名称。
- 在值部分,我找到了文本“\Device\0000006f”。
- 在 WinObj 中,我搜索了Global?? 引用“\Device\0000006f”的 SymbolicLink 目录。该 SymbolicLink 的名称很长:
DISPLAY#Default_Monitor#5&1193a8c7&0&UID100663553#{866519b5-3f07-4c97-b7df-24c5d8a8ccb8}
- 然后我在前面提到的 SymbolicLink 名称前放了一个“\.\”,并将其指定为
CreateFile
函数的第一个参数。
关于如何以编程方式完成所有这些操作的任何想法?我的意思是,我希望我的程序本身能够获取lpFileName
参数的值。不是我把这个字符串直接放在我程序的源代码中。
解决方案
首先,CreateFile
我们可以使用 NT 命名空间中的任何名称,如果使用前缀\\?\globalroot
甚至更好的\\?\global\globalroot
前缀。说如果我们想打开\Device\0000006f
我们可以使用\\?\globalroot\Device\0000006f
或\\?\global\globalroot\Device\0000006f
命名。将 win32 路径转换为 NT 路径时的 win32 sybsystem - 如果查看 '\?` 前缀 - 只需将其转换为\??\
. 所以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;
}
}
}
推荐阅读
- angular - 从源访问 XMLHttpRequest
- karate - 将 Json 响应导出到空手道框架中的文件
- python - 有没有更好的方法来围绕列表编写这个循环,这样它就不会出现内存错误?
- git - 在 git 远程之间更改提交用户
- elasticsearch - 使用两个文件时同义词规则无效
- angular - 单击列表上具有相似 ngcontent 类名但具有跨度唯一文本的特定项目,使用 Protractor 打字稿
- tensorflow - CNN图像分类:准确率值大幅波动
- c# - ToggleSwitch 未调用 IsEnabledChanged
- swift - 如果 AVAsset 包含延时视频,为什么 AV Export 会话会导出黑色视频?如何解决问题?
- php - crontab 打印脚本而不是执行它