【问题标题】:python/pyqt - Pass a CancelEvent to a C++ functionpython/pyqt - 将 CancelEvent 传递给 C++ 函数
【发布时间】:2017-12-17 14:30:15
【问题描述】:

我有一个带有CancelEvent 参数的 WinApi 函数,但我不知道我必须在那里传递什么?

HRESULT WINAPI DismUnmountImage(
  _In_     PCWSTR                 MountPath,
  _In_     DWORD                  Flags,
  _In_opt_ HANDLE                 CancelEvent,
  _In_opt_ DISM_PROGRESS_CALLBACK Progress,
  _In_opt_ PVOID                  UserData
);

https://msdn.microsoft.com/en-us/library/windows/desktop/hh824802(v=vs.85).aspx

我在 Windows 10 上使用 python 3.6。该功能工作正常,进度对话框也是如此。我使用 QProgressDialog 小部件来显示进度状态,我只需要实现 CancelEvent。 重新定义:

from ctypes import *
import win32con, win32api

def UnmountImage(self, MountPath, Flags=DISM_DISCARD_IMAGE, CancelEvent=None, Progress=None, UserData=None):
    self.hDism.DismUnmountImage.restype = HRESULT
    try:
        return self.hDism.DismUnmountImage(MountPath, Flags, CancelEvent, Progress, UserData)
    except OSError as e:
        print("DismUnmountImage failed: %s\nErrorCode: %s" % (e.strerror, e))
        return self.GetLastErrorMessage()

还有 pyqt 部分:

def canceled(self):
    print("canceled")

@pyqtSlot(QVariant)
def unmount_image(self, json_data):
    dism_progress_callback = dism_manager.DISM_PROGRESS_CALLBACK(self.dism_progress_callback)
    data = json.loads(json_data)

    self.progdialog = QProgressDialog("", "Cancel", 0, 100, None)
    self.progdialog.setWindowTitle("Unmounting Image...")
    self.progdialog.setModal(True)
    self.progdialog.canceled.connect(self.canceled)
    self.progdialog.show()

    for image in data:
        dism_manager.UnmountImage(MountPath=image['MountPath'], Progress=dism_progress_callback, CancelEvent=self.progdialog.winId())

我尝试传递 qtWindow 的句柄,但收到错误消息 ..can't convert parameter 3..。该功能期望什么?窗户把手?我真的不知道,我对 C++ 也不熟悉。

顺便说一句:QProgressdialog 是一个带有 QProgress 和 QButton 的窗口。当我点击取消按钮时,我的def canceled(self): 方法被发出,窗口将关闭一秒钟,然后继续进行。

编辑:
根据 zett42 的建议,我想出了这个:

DISM_CANCEl_EVENT = CreateEvent(None, False, False, None)

还有:

def canceled(self):
    print("canceled")
    SetEvent(dism_manager.DISM_CANCEl_EVENT)

    ...
for image in data:
    dism_manager.UnmountImage(MountPath=image['MountPath'], Progress=dism_progress_callback, CancelEvent=dism_manager.DISM_CANCEl_EVENT)

我收到以下错误消息: ctypes.ArgumentError: argument 3: <class 'TypeError'>: Don't know how to convert parameter 3

你知道我错过了什么吗?

EDIT2:
我明白了:

def canceled(self):
    self.progdialog.cancel()
    SetEvent(self.cancel_event)

self.cancel_event = dism_manager.DISM_CANCEl_EVENT.Detach()

for image in data:
    dism_manager.UnmountImage(MountPath=image['MountPath'], Progress=dism_progress_callback, CancelEvent=self.cancel_event)

我遇到的唯一问题:cancelevent 需要大约 2 秒的时间才能执行,以便同时 dism_progress_callback 强制窗口再次弹出,尽管我调用了 self.progdialog.cancel() 关闭了窗口...希望你能关注我。你有什么建议我可以控制这个吗?


已解决:
我得到了最终解决方案:我在self.progdialog.canceled.connect(self.dism_cancel_event) 之前调用了self.progdialog.canceled.disconnect() 以覆盖cancel() 信号并阻止cancel() 的调用。

【问题讨论】:

  • 请将您的解决方案作为答案发布在下面,而不是将其包含在您的问题中。

标签: windows winapi events pyqt dism


【解决方案1】:

该函数需要一个事件对象的句柄,该对象可以使用CreateEvent() C API 创建。在 Python 中,您可以调用 win32event.CreateEvent()

在您的函数def canceled(self) 中,您应该调用win32event.SetEvent(hEvent),传递您为hEvent 参数创建的事件对象的句柄。这将请求取消UnmountImage()

【讨论】:

  • 非常感谢您的回答。我确实按照您的指示编辑了我的帖子,但似乎CancelEvent 参数仍然无效。也许你有什么想法?
  • @FalloutBoy 我看到您找到了解决方案,但现在您出现了内存泄漏,因为Detach() 释放了所有权,因此句柄将不再关闭。相反,您应该使用DISM_CANCEl_EVENT.handle
  • 不幸的是DISM_CANCEl_EVENT.handle 具有相同的效果。当我单击取消时,窗口关闭,此时我的控制台为空。 2 秒后,窗口再次弹出并继续进行。再过 2 秒,窗口再次关闭,在我的控制台中我收到通知消息 ...Progress get canceled...。您知道如何关闭进度窗口吗? ...如果有帮助,我可以做一个视频吗?
  • @FalloutBoy 你为什么打电话给self.progdialog.cancel()?如果取消需要 2 秒,那么进度对话框应该仍然可见,因此用户可以看到程序仍然很忙。我只会禁用取消按钮。仅当dism_manager.UnmountImage() 返回时关闭进度对话框,则不存在这些问题。
  • 对不起,你是对的,但我目前发现这个:void QProgressDialog::canceled() [signal] -> This signal is emitted when the cancel button is clicked. It is connected to the cancel() slot by default...所以当我点击取消按钮时,self.progdialog.cancel() 将自动运行。我必须覆盖 Cancel 行为或添加一个 QPushbutton ,它看起来像取消按钮但不会像它那样反应。我测试了self.progdialog.setCancelButton(cancel_btn),但它显然具有相同的效果。有什么想法吗?
猜你喜欢
  • 2013-07-24
  • 2014-02-22
  • 2012-03-16
  • 1970-01-01
  • 1970-01-01
  • 2012-07-29
  • 1970-01-01
  • 2020-02-08
  • 2019-08-30
相关资源
最近更新 更多