python - pywin32 win32gui.PumpWaitingMessages() 放置

标签 python winapi pywin32

我正在尝试编写一些 python 代码来检测 Windows 中的监视器更改事件;我正在使用 pywin32,主要基于 pywin32 example 中的代码. PumpWaitingMessages 的位置似乎有所不同;下面的代码确实检测到监视器更改(即 OnDeviceChange 运行)但 lp 参数为 0,因此我无法从中获取任何有用的信息(即监视器标识符)。

class Foo(QObject):    
    def OnDeviceChange(self, hwnd, msg, wp, lp):
        info = win32gui_struct.UnpackDEV_BROADCAST(lp)
        print("Device change notification:", wp, str(info))  #
        return True

    def __init__(self):
        wc = win32gui.WNDCLASS()
        wc.lpszClassName = 'test_devicenotify'
        wc.style = win32con.CS_GLOBALCLASS|win32con.CS_VREDRAW | win32con.CS_HREDRAW
        wc.hbrBackground = win32con.COLOR_WINDOW + 1
        wc.lpfnWndProc = {win32con.WM_DEVICECHANGE: self.OnDeviceChange}
        class_atom = win32gui.RegisterClass(wc)
        hwnd = win32gui.CreateWindow(wc.lpszClassName,
            'Waiting for Monitor Change',
            # no need for it to be visible.
            win32con.WS_CAPTION,
            100, 100, 900, 900, 0, 0, 0, None)
        filter = win32gui_struct.PackDEV_BROADCAST_DEVICEINTERFACE(
                                            GUID_DEVINTERFACE_MONITOR)
        hdev = win32gui.RegisterDeviceNotification(hwnd, filter,
                                                   win32con.DEVICE_NOTIFY_WINDOW_HANDLE)


f = Foo()
while True:
    win32gui.PumpWaitingMessages()
    time.sleep(0.01)

但是,如果我将 while True 循环从代码的最后移动到 __init__ 方法的末尾,那么 lp 参数已填充,我可以获得所需的信息。

知道为什么 while 循环的放置会有所不同吗?

最佳答案

虽然它是借用代码的一部分,但我将首先建议将变量 filter 重命名为其他名称,因为它隐藏了 [Python]: filter(function, iterable) (当我编辑帖子时没有改变自己,因为我无法发表评论说明我为什么这样做)。此外,您可能希望添加缺失的部分以获得有效的代码片段:导入、定义(例如 GUID_DEVINTERFACE_MONITOR,我浏览了 Ioevent.h,但找不到既不 USB 也不显示相关的 GUID)

我怀疑有两件事可能对这种行为负责:

  • PyQt(它有自己的窗口处理)与普通的 WinAPI(如我在评论中所写)混合,以及两者之一可能会继续对方的脚趾
  • Python 范围 ( [Python]: Execution model )

我不想安装 PyQt,所以我开始探索其他可能性。我能够使用原始代码(您从中开始)重现相同的行为。问题是在 TestDeviceNotifications 结束时,hdev(由 RegisterDeviceNotification 返回)超出范围。

同样的事情发生在这里:退出__init__后,(当消息将开始发送到窗口时)hdev将是一个无效句柄。要更正此问题,请将其设置为全局:

  • 在模块级别(在 Foo 之前)声明它,例如:hdev = None
  • 指示__init__ 对全局变量进行操作,而不是创建一个具有相同名称的新本地变量。在__init__的某处,之前hdev = win32gui.RegisterDeviceNotification添加global hdev,它会持久化

注意事项:

  • 通常,所有创建的资源都应在不再需要时释放。这就是您应该对 wchwnd 执行的操作。关于hdev[MSDN]: RegisterDeviceNotification function没有提到任何关于调用CloseHandle(或类似的东西)的事情,所以我认为这很好

关于python - pywin32 win32gui.PumpWaitingMessages() 放置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42762309/

相关文章:

c++ - WinAPI EM_STREAMOUT 崩溃

python - 无法使用 python 运行 visio 宏

python - 尝试在 Python 中重用 Windows Notification 类时出错

python - 如何检查 Django 应用程序的性能?

python - 将 Python UDF 应用于 Spark 数据帧时的 java.lang.IllegalArgumentException

c# - 修复 Windows 窗体中的拆分容器控件

Python pywin32 访问被拒绝

python - 使用 cv2.putText() 将文本放置在循环之外

python - 如何简单地导入文件

c++ - 将结构数据类型传递给 C++ 中的命名管道