Determine why a taskdialog was closed in Delphi

360 views Asked by At

A part of my Delphi application accesses information from another program. Because it can take some time to execute, and sometimes the other program may be unresponsive, I run that part of my code in a separate thread.

To keep my users informed of the progress of the background thread, I execute a TaskDialog after I start the thread. I pass a pointer to the TaskDialog to my thread so that the thread can synchronize with the TaskDialog to update it as the thread progresses. When the thread finishes, I send a close message to the TaskDialog using PostMessage(CurrentTaskDialog.Handle, WM_CLOSE, 0, 0);

Everything is working so far, but I want to cancel the process if the user clicks the Cancel button on the TaskDialog (it is the only button on the TaskDialog). I cannot figure-out how to do it. No matter whether the user clicks the button or if the TaskDialog receives the close message, the ModalResult is always mrCancel. I have tried assigning a different ModalResult in the thread, but it still evaluates as mrCancel.

Is there some way to accomplish this?

1

There are 1 answers

2
Remy Lebeau On

What you describe is normal behavior, per the TaskDialogIndirect() documentation:

pnButton

Type: int*

Address of a variable that receives either:

  • one of the button IDs specified in the pButtons member of the pTaskConfig parameter

  • one of the following values:

    • 0: Function call failed. Refer to return value for more information.
    • IDCANCEL: Cancel button was selected, Alt-F4 was pressed, Escape was pressed, or the user clicked on the close window button.
    • IDNO: No button was selected.
    • IDOK: OK button was selected.
    • IDRETRY: Retry button was selected.
    • IDYES: Yes button was selected.

Since you only have a Cancel button, and are simulating a close button press, then TaskDialogIndirect() always reports IDCANCEL, which is why the ModalResult is always mrCancel. There is no way to differentiate the actual cause (short of hooking the dialog window itself).

In any case, you don't actually need to use the ModalResult at all to accomplish what you want.

When the dialog closes for any reason, simply signal the thread to end, and then wait for the thread to fully exit. If the thread had already ended before the dialog was closed, the signal will be ignored, and the wait will be satisfied immediately.

You could then take this a step further. Instead of using tcbCancel in the TaskDialog's CommonButtons property, you could use a custom button in the TaskDialog's Buttons property, and then use the TaskDialog's OnButtonClicked event to signal the thread to exit. Block the dialog from closing automatically (by setting CanClose=False in the event handler) and wait for the thread to close the dialog when finished. This will allow you to continue displaying feedback inside the TaskDialog while waiting for the thread to end, such as displaying a "Waiting" message. Whereas with the other approach, the TaskDialog window is closed when the user clicks on the standard Cancel button, so you can't display feedback anymore even though the thread may still be running.