【问题标题】:(WinApi) ChangeDisplaySettingsEx does not work(WinApi) ChangeDisplaySettingsEx 不起作用
【发布时间】:2016-03-05 12:47:59
【问题描述】:

我正在尝试编写一个 python 脚本来切换主监视器。 我有 3 台显示器(一台插入 i5 的图形芯片,两台插入 ATI HD7870)

我写了以下脚本:

import win32api as w
import win32con as c

i = 0
workingDevices = []

def setPrimary(id):
    global workingDevices
    return w.ChangeDisplaySettingsEx(
        workingDevices[id].DeviceName,
        w.EnumDisplaySettings(
            workingDevices[id].DeviceName,
            c.ENUM_CURRENT_SETTINGS
            ),
        c.CDS_SET_PRIMARY | c.CDS_UPDATEREGISTRY | c.CDS_RESET) \
        == c.DISP_CHANGE_SUCCESSFUL

while True:
    try:
        Device = w.EnumDisplayDevices(None, i, 1)
        if Device.StateFlags & c.DISPLAY_DEVICE_ATTACHED_TO_DESKTOP: #Attached to desktop
            workingDevices.append(Device)

        i += 1
    except:
        break

print("Num Devices: ", len(workingDevices))

for dev in workingDevices:
    print("Name: ", dev.DeviceName)

调用它会导致:

In [192]: %run test.py
Num Devices:  3
Name:  \\.\DISPLAY1
Name:  \\.\DISPLAY2
Name:  \\.\DISPLAY7

In [193]: setPrimary(0)
Out[193]: True

In [194]: setPrimary(1)
Out[194]: True

In [195]: setPrimary(2)
Out[195]: True

到目前为止,它看起来不错,但问题是:没有任何变化。由于 CDS_RESET,我的显示器很快闪烁,但主屏幕没有改变,尽管 ChangeDisplaySettingsEx 返回 DISP_CHANGE_SUCCESSFUL

有人知道为什么吗? (我使用 Python 3.5.1 和 PyWin32 build 220)

PS 我使用 1 作为 EnumDisplayDevices 的第三个参数,因为 msdn 声明它应该设置为 1,尽管 PyWin 帮助说它应该设置为 0。 但是脚本的行为不会独立于这个值是一或零而改变

【问题讨论】:

    标签: python-3.x winapi pywin32


    【解决方案1】:

    好的,我找到了解决方案。 显然,主监视器必须始终位于位置 (0, 0)。 因此,当我尝试将另一台显示器设置为主显示器时,它的位置设置为 (0, 0),这导致它与旧的主显示器相交。 似乎要走的路是更新所有监视器的位置,并将这些更改写入注册表,然后一旦完成,通过使用默认参数调用 ChangeDisplaySettingsEx() 来应用更改。 这是我的新(正在使用)代码:

    import win32api as w
    import win32con as c
    
    def load_device_list():
        """loads all Monitor which are plugged into the pc
        The list is needed to use setPrimary
        """
        workingDevices = []
        i = 0
        while True:
            try:
                Device = w.EnumDisplayDevices(None, i, 0)
                if Device.StateFlags & c.DISPLAY_DEVICE_ATTACHED_TO_DESKTOP: #Attached to desktop
                    workingDevices.append(Device)
    
                i += 1
            except:
                return workingDevices
    
    
    def setPrimary(id, workingDevices, MonitorPositions):
        """
        param id: index in the workingDevices list.
                  Designates which display should be the new primary one
    
        param workingDevices: List of Monitors returned by load_device_list()
    
        param MonitorPositions: dictionary of form {id: (x_position, y_position)}
                                specifies the monitor positions
    
        """
    
        FlagForPrimary = c.CDS_SET_PRIMARY | c.CDS_UPDATEREGISTRY | c.CDS_NORESET
        FlagForSec = c.CDS_UPDATEREGISTRY | c.CDS_NORESET
        offset_X = - MonitorPositions[id][0]
        offset_Y = - MonitorPositions[id][1]
        numDevs = len(workingDevices)
    
        #get devmodes, correct positions, and update registry
        for i in range(numDevs):
            devmode = w.EnumDisplaySettings(workingDevices[i].DeviceName, c.ENUM_CURRENT_SETTINGS)
            devmode.Position_x = MonitorPositions[i][0] + offset_X
            devmode.Position_y = MonitorPositions[i][1] + offset_Y
            if(w.ChangeDisplaySettingsEx(workingDevices[i].DeviceName, devmode, 
                FlagForSec if i != id else FlagForPrimary) \
                != c.DISP_CHANGE_SUCCESSFUL): return False
    
        #apply Registry updates once all settings are complete
        return w.ChangeDisplaySettingsEx() == c.DISP_CHANGE_SUCCESSFUL;
    
    if(__name__ == "__main__"):
        devices = load_device_list()
        for dev in devices:
            print("Name: ", dev.DeviceName)
    
        MonitorPositions = {
            0: (0, -1080),
            1: (0, 0),
            2: (1920, 0)
        }
    
        setPrimary(0, devices, MonitorPositions)
    

    【讨论】:

    • 非常感谢!!我想知道为什么我不能改变所有的显示。正如您所说,诀窍是首先使用 NORESET 更改所有显示,然后在所有参数上使用 NULL 结束调用
    猜你喜欢
    • 2015-02-04
    • 2014-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-26
    相关资源
    最近更新 更多