0

我正在尝试通过 Windows API 的EnumDisplayMonitors枚举可用的显示监视器。但是,我遇到了一些我无法弄清楚的非常奇怪的行为。也就是说,该函数可以正确运行,但前提是它不在函数内部。

如果我像这样将它放在模块级别:

模块代码

def _monitorEnumProc(hMonitor, hdcMonitor, lprcMonitor, dwData):
    print 'call result:', hMonitor, hdcMonitor, lprcMonitor, dwData

if __name__ == '__main__':
    # Callback Factory
    MonitorEnumProc = WINFUNCTYPE(
        ctypes.c_bool, 
        ctypes.wintypes.HMONITOR,
        ctypes.wintypes.HDC,
        ctypes.POINTER(RECT),
        ctypes.wintypes.LPARAM
    )

    # Make the callback function
    enum_callback = MonitorEnumProc(_monitorEnumProc)

    # Enumerate the windows
    print 'return code: %d' % windll.user32.EnumDisplayMonitors(
        None, 
        None,
        enum_callback,
        0
        )

一切都按预期运行。它为我的两个连接的显示器打印出handles和。rects

输出:

>>> call result: 65537 None <__main__.LP_RECT object at 0x02250EE0> 0
>>> call result: 65539 None <__main__.LP_RECT object at 0x02250EE0> 0
[Finished in 0.1s]

一切都很好。该EnumDisplayMonitors函数返回一个非零值,表明一切都按计划进行。

现在,问题来了,如果我将完全相同的代码粘贴到一个函数中,事情就会变得很糟糕。

功能码

def _monitorEnumProc(hMonitor, hdcMonitor, lprcMonitor, dwData):
    print 'call result:', hMonitor, hdcMonitor, lprcMonitor, dwData

def enum_mons():
    # Callback Factory
    MonitorEnumProc = WINFUNCTYPE(
        ctypes.c_bool, 
        ctypes.wintypes.HMONITOR,
        ctypes.wintypes.HDC,
        ctypes.POINTER(RECT),
        ctypes.wintypes.LPARAM
    )

    # Make the callback function
    enum_callback = MonitorEnumProc(_monitorEnumProc)

    # Enumerate the windows
    print 'return code: %d' % windll.user32.EnumDisplayMonitors(
        None, 
        None,
        enum_callback,
        0
        )

if __name__ == '__main__':
    enum_mons()

所以,完全相同的代码,除了现在在函数内部。

输出

call result: 65537 None <__main__.LP_RECT object at 0x02250E90> 0
0

它不会吐出所有连接的监视器和成功代码,而是仅吐出一个监视器和一个 0,根据MSDN 文档,这意味着函数失败。

有谁知道是什么原因造成的?这让我很难过!

4

1 回答 1

1

当你使用一个函数时,enum_callback当 Python 框架enum_mons被垃圾收集时被释放。因此,当 Windows 尝试为每个监视器调用它时,它是否仍然存在是一场竞赛。全局定义回调——或者使用一个类。

此外,您的回调应该返回 True 以继续枚举。

import ctypes
from ctypes import wintypes 

LPRECT = ctypes.POINTER(wintypes.RECT)

# Callback Factory
MonitorEnumProc = ctypes.WINFUNCTYPE(
    ctypes.c_bool, 
    wintypes.HMONITOR,
    wintypes.HDC,
    LPRECT,
    wintypes.LPARAM)

ctypes.windll.user32.EnumDisplayMonitors.restype = wintypes.BOOL
ctypes.windll.user32.EnumDisplayMonitors.argtypes = [
    wintypes.HDC,
    LPRECT,
    MonitorEnumProc,
    wintypes.LPARAM]

def _monitorEnumProc(hMonitor, hdcMonitor, lprcMonitor, dwData):
    print 'call result:', hMonitor, hdcMonitor, lprcMonitor, dwData
    print lprcMonitor[0].right, lprcMonitor[0].bottom
    return True # continue enumeration

# Make the callback function
enum_callback = MonitorEnumProc(_monitorEnumProc)

def enum_mons():   
    '''Enumerate the display monitors.'''
    return ctypes.windll.user32.EnumDisplayMonitors(
        None, 
        None,
        enum_callback,
        0)

if __name__ == '__main__':
    print 'return code: %d' % enum_mons()
于 2013-09-06T18:57:33.093 回答