CreateFile 函数可以打开仅在 Global 下列出的设备的句柄吗? WinObj 实用程序中的目录?
Can CreateFile function open a handle to the devices that are only listed under Global?? directory in WinObj utility?
您知道 - 在 C++ 中,您可以通过将其路径作为调用 CreateFile 函数的第一个参数传递来获取 I/O 设备的句柄。但是我想知道 CreateFile 是如何通过给定的路径定位和识别设备的。有一天,我使用 WinObj 实用程序发现了有关此主题的一些信息,这可能是真的。
在WinObj中,在根目录下有一个名为Global??的目录,可以在左窗格中看到。此目录包含许多 "SymbolicLink".
类型的项目
当您将 I/O 设备的路径(例如“\.\C:”或“\.\Changer0”)作为调用 CreateFile
函数的第一个参数传递时,CreateFile 函数解析出路径并从中删除“\.\”以找到路径的一部分。然后它在 Global?? 目录中搜索与该部分同名的 SymbolicLink。然后它找到符号 link 引用的地址,这是主要的 Physical Device Object Name(例如,“\Device\CdRom0”)。
那么,我的发现是真的吗? Global?? 目录中包含的设备是否是 CreateFile
函数可以打开的唯一设备?只是提一下:我猜 Global?? 目录中的所有项目并非都指设备。
我的问题的第二部分
有一天,我想通过向我的显示器发送 IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS
控制代码,以编程方式降低显示器的屏幕亮度。问题是我不知道要为 CreateFile
函数的第一个参数指定什么。所以我做了以下事情:
- 我打开了设备管理器,在列表中找到了我的监控设备。该设备的名称是 "Generic Non-PnP Monitor".
- 我右键单击该列表项并单击 属性。
- 在 属性 window 中,我单击了 详细信息 选项卡。然后我从 属性 下拉列表中选择 Physical Device Object name。
- 在值部分,我找到了文本“\Device[=73=]00006f”。
- 在 WinObj 中,我在 Global?? 目录中搜索了一个指向“\Device[=73=]00006f”的 SymbolicLink。该 SymbolicLink 的名称很长:
DISPLAY#Default_Monitor#5&1193a8c7&0&UID100663553#{866519b5-3f07-4c97-b7df-24c5d8a8ccb8}
- 然后我在前面提到的 SymbolicLink 名称和
将其指定为
CreateFile
函数的第一个参数。
关于如何以编程方式执行所有这些操作有什么想法吗?我的意思是,我希望我的程序本身获得 lpFileName
参数的值。不是 我把这个字符串直接放在我程序的源代码中。
首先在 CreateFile
中,我们可以使用 NT 命名空间中的任何名称,如果前缀为 \?\globalroot
甚至更好 \?\global\globalroot
前缀。假设我们想要打开 \Device[=14=]00006f
我们可以使用 \?\globalroot\Device[=15=]00006f
或 \?\global\globalroot\Device[=16=]00006f
名称。将 win32 路径转换为 NT 路径时的 win32 sybsystem - 如果查看 '\?` 前缀 - 只需将其转换为 \??\
。所以 nt 路径看起来像 \??\[global\]globalroot\Device[=18=]00006f
。当视图 \??\
时,\??
是 virtual directory - it not exist really. object manager look in Local and Global MS-DOS Device Names。首先在本地(看起来像 \Sessions[=21=]\DosDevices\<luid>
),如果在全局中找不到 - \GLOBAL??
。然而在任何本地 dos 设备目录中存在符号 link Global
指向 \Global??
。作为解析 \??\global
后的结果,我们将被重定向到 \Global??
。然后在 \Global??
文件夹中存在空的符号 link GLOBALROOT
- 指向 NT 命名空间的根。
作为解析后的结果
\?\global\globalroot\Device[=16=]00006f
也将被重新解析为 \Device[=14=]00006f
和 \?\globalroot\Device[=15=]00006f
,如果本地设备命名空间中没有 globalroot
对象(通常不存在,但突然有人创建了它)。
现在介绍如何打开监控设备。我们不得硬编码任何设备名称。相反,我们需要搜索支持 GUID_DEVINTERFACE_MONITOR
by call 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;
}
}
}
您知道 - 在 C++ 中,您可以通过将其路径作为调用 CreateFile 函数的第一个参数传递来获取 I/O 设备的句柄。但是我想知道 CreateFile 是如何通过给定的路径定位和识别设备的。有一天,我使用 WinObj 实用程序发现了有关此主题的一些信息,这可能是真的。
在WinObj中,在根目录下有一个名为Global??的目录,可以在左窗格中看到。此目录包含许多 "SymbolicLink".
类型的项目
当您将 I/O 设备的路径(例如“\.\C:”或“\.\Changer0”)作为调用 CreateFile
函数的第一个参数传递时,CreateFile 函数解析出路径并从中删除“\.\”以找到路径的一部分。然后它在 Global?? 目录中搜索与该部分同名的 SymbolicLink。然后它找到符号 link 引用的地址,这是主要的 Physical Device Object Name(例如,“\Device\CdRom0”)。
那么,我的发现是真的吗? Global?? 目录中包含的设备是否是 CreateFile
函数可以打开的唯一设备?只是提一下:我猜 Global?? 目录中的所有项目并非都指设备。
我的问题的第二部分
有一天,我想通过向我的显示器发送 IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS
控制代码,以编程方式降低显示器的屏幕亮度。问题是我不知道要为 CreateFile
函数的第一个参数指定什么。所以我做了以下事情:
- 我打开了设备管理器,在列表中找到了我的监控设备。该设备的名称是 "Generic Non-PnP Monitor".
- 我右键单击该列表项并单击 属性。
- 在 属性 window 中,我单击了 详细信息 选项卡。然后我从 属性 下拉列表中选择 Physical Device Object name。
- 在值部分,我找到了文本“\Device[=73=]00006f”。
- 在 WinObj 中,我在 Global?? 目录中搜索了一个指向“\Device[=73=]00006f”的 SymbolicLink。该 SymbolicLink 的名称很长:
DISPLAY#Default_Monitor#5&1193a8c7&0&UID100663553#{866519b5-3f07-4c97-b7df-24c5d8a8ccb8}
- 然后我在前面提到的 SymbolicLink 名称和
将其指定为
CreateFile
函数的第一个参数。
关于如何以编程方式执行所有这些操作有什么想法吗?我的意思是,我希望我的程序本身获得 lpFileName
参数的值。不是 我把这个字符串直接放在我程序的源代码中。
首先在 CreateFile
中,我们可以使用 NT 命名空间中的任何名称,如果前缀为 \?\globalroot
甚至更好 \?\global\globalroot
前缀。假设我们想要打开 \Device[=14=]00006f
我们可以使用 \?\globalroot\Device[=15=]00006f
或 \?\global\globalroot\Device[=16=]00006f
名称。将 win32 路径转换为 NT 路径时的 win32 sybsystem - 如果查看 '\?` 前缀 - 只需将其转换为 \??\
。所以 nt 路径看起来像 \??\[global\]globalroot\Device[=18=]00006f
。当视图 \??\
时,\??
是 virtual directory - it not exist really. object manager look in Local and Global MS-DOS Device Names。首先在本地(看起来像 \Sessions[=21=]\DosDevices\<luid>
),如果在全局中找不到 - \GLOBAL??
。然而在任何本地 dos 设备目录中存在符号 link Global
指向 \Global??
。作为解析 \??\global
后的结果,我们将被重定向到 \Global??
。然后在 \Global??
文件夹中存在空的符号 link GLOBALROOT
- 指向 NT 命名空间的根。
作为解析后的结果
\?\global\globalroot\Device[=16=]00006f
也将被重新解析为 \Device[=14=]00006f
和 \?\globalroot\Device[=15=]00006f
,如果本地设备命名空间中没有 globalroot
对象(通常不存在,但突然有人创建了它)。
现在介绍如何打开监控设备。我们不得硬编码任何设备名称。相反,我们需要搜索支持 GUID_DEVINTERFACE_MONITOR
by call 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;
}
}
}