You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

补充说明

  1. 路径直接可用:通过SetupDiGetDeviceInterfaceDetail获取的DevicePath已经是Win32命名空间下的合法路径,无需手动添加\\.\前缀或查找Global??的符号链接,直接传入CreateFile即可。
  2. 权限与打开方式:打开显示器设备时,需要指定GENERIC_READ | GENERIC_WRITE权限,以及FILE_SHARE_READ | FILE_SHARE_WRITE共享模式,创建方式用OPEN_EXISTING。
  3. 备选方案(如果需要匹配PDO路径):如果你一定要找到Global??下对应某个PDO(如\\Device\0000006f)的符号链接,可以通过枚举Global??目录下的文件,用FSCTL_GET_REPARSE_POINT控制码获取符号链接的目标路径,再与目标PDO路径匹配。不过这种方法不如设备接口路径可靠,因为符号链接名称可能随系统重启或设备变更而改变。

内容的提问来源于stack exchange,提问作者Javad Bayat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:25:48