python-3.x - (WinApi) ChangeDisplaySettingsEx 不起作用

标签 python-3.x winapi pywin32

我正在尝试编写一个 python 脚本来切换主监视器。
我有 3 个显示器(一个插入 i5 的图形芯片,2 个插入 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。
但是脚本的行为不会独立于这个值是一或零而改变

最佳答案

好的,我找到了解决方案。
显然,主监视器必须始终位于 (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)

关于python-3.x - (WinApi) ChangeDisplaySettingsEx 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35814309/

相关文章:

python - MySQL/Python -- 提交的更改未出现在循环中

python - 确保用户在 Python 中指定两个函数参数之一且仅指定一个的最佳方法

python - Jenkins 管道中的 k8s_api 连接超时

c - 如何将 Windows 消息从一个线程传递到另一个线程?

c# - 在 Windows 8.1 上禁用触摸视觉反馈(以编程方式)[桌面应用程序]

python - 使用 Python 在 Firefox 中自动下载文件

python - 是否可以使用 XGBoost 预测给定输入向量或一系列向量的整个输出向量?

c++ - 识别是否插入了可移动驱动器

python - 使用 python win32 api 的 Windows 打印机对话框

python - 使用 python 修改文件夹的 Exchange ACL