如何查询Windows中主显示器的原生硬件分辨率?

6 投票
1 回答
3723 浏览
提问于 2025-04-16 07:52

我需要在Windows下找到连接的LCD显示器的“最佳”或原生分辨率(之后我会通过编程设置这个分辨率,我知道怎么做)。我再强调一下,我不需要当前Windows的分辨率,也不需要考虑CRT显示器或投影仪。

我见过这个程序能做到,所以我知道这不是不可能的,尽管有些人持怀疑态度: http://www.entechtaiwan.com/util/moninfo.shtm

最好是直接与显示器对话,查询EDID信息。不过,我发现这些信息会缓存到注册表里,我可以从HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY中找到,但我不知道怎么把这些数据和当前的主显示器匹配起来。

我找到一个C语言的程序: http://www.tech-archive.net/Archive/Development/microsoft.public.development.device.drivers/2004-08/0294.html 还有一个类似的Python程序: http://www.koders.com/python/fid7FCCE3C908F376DC62F06CAD9B11C6D7C1CFA78F.aspx

不幸的是,我在把C程序转换成Python时遇到了很多麻烦,因为相关的代码似乎不在win32all模块里。我想尝试编译它,但没有足够的磁盘空间来放一个大的编译器,而且我已经很多年没用C语言了。我对ctypes也有点陌生。

我的备选方案是使用EnumDisplaySettings()来找到最大的分辨率值并设置为这个值。在我尝试的电脑上,它能给出正确的分辨率,但可能还是会有问题。

我更希望能有一个Python的解决方案,但也许有人可以帮我修改C程序,让它输出分辨率并编译它。提前谢谢大家。

更新:

我找到一个潜在的解决方案。我现在在读取WMI来找到一个可用的显示器(不是离线状态),获取它的PNP设备ID,然后从注册表中读取对应ID值的EDID。接着我解析数据中的第38和39个字节并进行计算。虽然这个方法不太干净,但我得到了结果。如果这个方法合理,我就会关闭这个问题,谢谢。

1 个回答

2

决定不再直接和显示器对话,而是解析存储在注册表中的EDID信息。这个代码虽然不完美,但能正常工作:

import win32api as api, win32con as con, pywintypes
import win32com.client
_objWMIService = win32com.client.Dispatch('WbemScripting.SWbemLocator')
_objSWbemServices = _objWMIService.ConnectServer('.', 'root\\cimv2')
wmiquery = _objSWbemServices.ExecQuery

# get_regval(regkey) is simple registry reading function.
def get_monitor_res():
    dtd = 54  # start byte of detailed timing desc.

    try:  # get PNP id to find EDID in registry
        for monitor in wmiquery('Select * from Win32_DesktopMonitor'):
            # http://msdn.microsoft.com/en-us/library/aa394122%28VS.85%29.aspx
            if monitor.Availability in (3, 7, 13, 14, 15, 16): # connected
                curres = (monitor.ScreenWidth, monitor.ScreenHeight)
                print 'DEBUG: Current monitor resolution from WMI: %s' % (curres,)
                regkey = ('HKLM\\SYSTEM\\CurrentControlSet\\Enum\\' +
                    monitor.PNPDeviceID + '\\Device Parameters\\EDID')
                edid = get_regval(regkey)
                if edid:
                    print 'DEBUG: EDID Version: %s.%s' % (edid[18], edid[19])
                    # upper nibble of byte x 2^8 combined with full byte
                    hres = ((edid[dtd+4] >> 4) << 8) | edid[dtd+2]
                    vres = ((edid[dtd+7] >> 4) << 8) | edid[dtd+5]
                    print 'DEBUG: EDID DTD0: ' + str((hres, vres))
                    res = (hres, vres)
                    break  # give up on first success
                else:
                    raise RuntimeError, 'EDID not found in registry'
    except (RuntimeError, Exception) as err:
        print 'ERROR: %s.' % err

    return res

撰写回答