CreateFile能否打开WinObj中Global??目录设备及程序化获取路径方法
二、程序化获取显示器设备路径的方案
要自动获取可用于CreateFile的显示器设备路径(来发送IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS调节亮度),最可靠的方式是通过Windows设备安装API枚举显示器的设备接口,直接拿到可用路径,无需手动查找Global??的符号链接。具体步骤和代码示例如下:
核心思路
Windows为显示器提供了专门的设备接口类(GUID_DEVINTERFACE_MONITOR),通过枚举该类下的设备接口,可以直接获取到Win32命名空间下的设备路径,这个路径可以直接传入CreateFile使用。
代码实现(简化版)
#include <windows.h> #include <setupapi.h> #include <initguid.h> #include <cstdio> // 定义显示器设备接口的GUID DEFINE_GUID(GUID_DEVINTERFACE_MONITOR, 0x53d29ef7, 0x377c, 0x4d14, 0x86, 0x1e, 0x0a, 0xba, 0x87, 0x6a, 0x70, 0x7b); // 获取所有显示器的设备路径 BOOL GetMonitorDevicePaths(LPWSTR* ppDevicePaths, DWORD* pDeviceCount) { // 获取显示器设备列表句柄 HDEVINFO hDevInfo = SetupDiGetClassDevs( &GUID_DEVINTERFACE_MONITOR, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE // 只枚举当前存在的设备接口 ); if (hDevInfo == INVALID_HANDLE_VALUE) { printf("SetupDiGetClassDevs failed: %lu\n", GetLastError()); return FALSE; } SP_DEVICE_INTERFACE_DATA deviceInterfaceData = {0}; deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); DWORD deviceIndex = 0; *pDeviceCount = 0; // 第一步:先统计显示器设备的数量 while (SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_MONITOR, deviceIndex, &deviceInterfaceData)) { (*pDeviceCount)++; deviceIndex++; } if (*pDeviceCount == 0) { printf("No monitor devices found.\n"); SetupDiDestroyDeviceInfoList(hDevInfo); return FALSE; } // 分配内存存储所有设备路径 *ppDevicePaths = (LPWSTR)LocalAlloc(LPTR, *pDeviceCount * MAX_PATH * sizeof(WCHAR)); if (!*ppDevicePaths) { printf("LocalAlloc failed: %lu\n", GetLastError()); SetupDiDestroyDeviceInfoList(hDevInfo); return FALSE; } // 第二步:遍历每个设备,获取其设备路径 deviceIndex = 0; while (SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_MONITOR, deviceIndex, &deviceInterfaceData)) { DWORD requiredSize = 0; // 先获取所需缓冲区的大小 SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, NULL, 0, &requiredSize, NULL); PSP_DEVICE_INTERFACE_DETAIL_DATA pDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, requiredSize); if (!pDetailData) { printf("LocalAlloc for detail data failed: %lu\n", GetLastError()); deviceIndex++; continue; } pDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, pDetailData, requiredSize, NULL, NULL)) { // 将设备路径复制到结果数组中 wcscpy_s(*ppDevicePaths + deviceIndex * MAX_PATH, MAX_PATH, pDetailData->DevicePath); wprintf(L"Monitor %d path: %s\n", deviceIndex + 1, pDetailData->DevicePath); } else { printf("SetupDiGetDeviceInterfaceDetail failed: %lu\n", GetLastError()); } LocalFree(pDetailData); deviceIndex++; } SetupDiDestroyDeviceInfoList(hDevInfo); return TRUE; } // 示例调用 int main() { LPWSTR pDevicePaths = NULL; DWORD deviceCount = 0; if (GetMonitorDevicePaths(&pDevicePaths, &deviceCount)) { // 这里可以遍历设备路径,调用CreateFile和DeviceIoControl调节亮度 // 示例:打开第一个显示器设备 if (deviceCount > 0) { HANDLE hMonitor = CreateFile( pDevicePaths, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if (hMonitor != INVALID_HANDLE_VALUE) { // 这里可以发送IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS控制码 printf("Successfully opened monitor device.\n"); CloseHandle(hMonitor); } else { printf("CreateFile failed: %lu\n", GetLastError()); } } LocalFree(pDevicePaths); } return 0; }
补充说明
- 路径直接可用:通过
SetupDiGetDeviceInterfaceDetail获取的DevicePath已经是Win32命名空间下的合法路径,无需手动添加\\.\前缀或查找Global??的符号链接,直接传入CreateFile即可。 - 权限与打开方式:打开显示器设备时,需要指定
GENERIC_READ | GENERIC_WRITE权限,以及FILE_SHARE_READ | FILE_SHARE_WRITE共享模式,创建方式用OPEN_EXISTING。 - 备选方案(如果需要匹配PDO路径):如果你一定要找到
Global??下对应某个PDO(如\\Device\0000006f)的符号链接,可以通过枚举Global??目录下的文件,用FSCTL_GET_REPARSE_POINT控制码获取符号链接的目标路径,再与目标PDO路径匹配。不过这种方法不如设备接口路径可靠,因为符号链接名称可能随系统重启或设备变更而改变。
内容的提问来源于stack exchange,提问作者Javad Bayat
相关产品推荐
相关产品推荐

