2

I have a WinApi function with a CancelEvent parameter but I don't know what I have to pass there?

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

I'm working with python 3.6 on Windows 10. The function is working properly, the progress dialog too. I used QProgressDialog widget to display progress state, I only have to implement the CancelEvent. The reDefinition:

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()

And the pyqt part:

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())

I tried to pass the handle of the qtWindow but I get an error message ..can't convert parameter 3... What does the function expect? A windows handle? I really have no idea and I'm not familar with C++.

Btw: The QProgressdialog is a window with a QProgress and a QButton. When I click on the Cancel button, my def canceled(self): method is emitted and the window will be closed for a second and then the progress continues.

EDIT:
After zett42 suggestions I came up with this:

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

And:

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)

I get this error message: ctypes.ArgumentError: argument 3: <class 'TypeError'>: Don't know how to convert parameter 3

Do you have any idea, what I am missing?

EDIT2:
I got it:

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)

The only problem I have: The cancelevent needs round about 2 seconds to be performed so that meanwhile the dism_progress_callback forces the window to popup again, although i called self.progdialog.cancel() which closes the window...hope you can follow me. Do you have any suggestions how i can control this?


Solved:
I got a final solution: I called self.progdialog.canceled.disconnect() before self.progdialog.canceled.connect(self.dism_cancel_event) to overwrite the canceled() signal and prevent the call of cancel().

Cœur
  • 37,241
  • 25
  • 195
  • 267
FalloutBoy
  • 964
  • 1
  • 9
  • 22

1 Answers1

0

The function expects the handle of an event object which can be created using the CreateEvent() C API. In Python you may call win32event.CreateEvent().

In your function def canceled(self) you should call win32event.SetEvent(hEvent) passing the handle of the event object you created for the hEvent parameter. This will request a cancellation of UnmountImage().

zett42
  • 25,437
  • 3
  • 35
  • 72
  • Thanks a lot for your answer. I did follow your instructions and edited my post, but it seems that the `CancelEvent` parameter is still invalid. Maybe you habe any ideas? – FalloutBoy Jul 14 '17 at 01:09
  • @FalloutBoy I see you found a solution, but now you have a memory leak because `Detach()` releases ownership so the handle will no longer be closed. Instead you should use `DISM_CANCEl_EVENT.handle`. – zett42 Jul 14 '17 at 06:27
  • Unfortunately `DISM_CANCEl_EVENT.handle` has the same effect. When I click on Cancel the window is closed, at this time my console is empty. After 2 seconds the window pops up again and the progress continues. After another 2 seconds the window closes again and in my console I get the notification message `...Progress get canceled...`. Do you have an idea how to keep the progress window be closed? ...I could do a video if this helps? – FalloutBoy Jul 14 '17 at 14:54
  • @FalloutBoy Why do you call `self.progdialog.cancel()`? If the cancellation takes 2 seconds, then the progress dialog should still be visible so the user can see that the program is still busy. I would just disable the cancel button. Close the progress dialog only when `dism_manager.UnmountImage()` returns, then you don't have these problems. – zett42 Jul 14 '17 at 15:47
  • sorry you are right, but I currently found this: `void QProgressDialog::canceled() [signal] -> This signal is emitted when the cancel button is clicked. It is connected to the cancel() slot by default`...so when i click cancel button, `self.progdialog.cancel()` will be run automatically. I have to overwrite the `Cancel` behaviour or add a QPushbutton which looks like the cancel button but doesn't react like it. I tested `self.progdialog.setCancelButton(cancel_btn)` but it obviously has the same effect. Any ideas? – FalloutBoy Jul 14 '17 at 18:01
  • @FalloutBoy Sorry, I don't know much about PyQt. Other frameworks normally have a way to suppress default behaviour when handling an event. As your original question has been answered, I suggest to make this a new question with a MCVE that concentrates on `QProgressDialog` only. – zett42 Jul 14 '17 at 18:11