[18/18] comctl32: TaskDialog - Add ability to cancel dialog

Fabian Maurer dark.shadow4 at web.de
Fri Feb 24 14:04:12 CST 2017


Signed-off-by: Fabian Maurer <dark.shadow4 at web.de>
---
 dlls/comctl32/taskdialog.c       | 28 ++++++++++++--
 dlls/comctl32/tests/taskdialog.c | 81 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+), 4 deletions(-)

diff --git a/dlls/comctl32/taskdialog.c b/dlls/comctl32/taskdialog.c
index 829102a07d..6057468793 100644
--- a/dlls/comctl32/taskdialog.c
+++ b/dlls/comctl32/taskdialog.c
@@ -76,6 +76,7 @@ typedef struct
     HFONT font_default;
     HFONT font_main;
     HWND hwnd;
+    BOOL has_cancel;
 }taskdialog_info;
 
 struct list taskdialogs = LIST_INIT(taskdialogs);
@@ -259,6 +260,10 @@ static void taskdialog_info_init(taskdialog_info **taskdialog, const TASKDIALOGC
     dialog->font_main = CreateFontW (19, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE,
                                 DEFAULT_CHARSET, 0, 0, CLEARTYPE_QUALITY,  FF_DONTCARE, font_name);
 
+    dialog->has_cancel = (pTaskConfig->dwFlags & TDF_ALLOW_DIALOG_CANCELLATION)
+                      || (pTaskConfig->dwFlags & TDF_CAN_BE_MINIMIZED)
+                      || (pTaskConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON);
+
     *taskdialog = dialog;
 }
 
@@ -316,12 +321,15 @@ static HRESULT callback(taskdialog_info *dialog, UINT uNotification, WPARAM wPar
 
 static void click_button(HWND hwndDlg, taskdialog_info *dialog, WORD command_id)
 {
-    HRESULT ret_callback = callback(dialog, TDN_BUTTON_CLICKED, command_id, 0);
+    HRESULT ret_callback;
+
+    if(command_id == IDCANCEL && !dialog->has_cancel)
+        return TRUE;
+
+    ret_callback = callback(dialog, TDN_BUTTON_CLICKED, command_id, 0);
     if(ret_callback == S_OK)
     {
         EndDialog(hwndDlg, command_id);
-
-        callback(dialog, TDN_DESTROYED, 0, 0);
     }
 }
 
@@ -398,6 +406,12 @@ static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARA
         case WM_HELP:
             callback(dialog, TDN_HELP, 0, 0);
             return TRUE;
+        case WM_DESTROY:
+            callback(dialog, TDN_DESTROYED, 0, 0);
+            return FALSE;
+        case WM_CLOSE:
+            click_button(hwndDlg, dialog, IDCANCEL);
+            return FALSE;
 
         /* Custom messages*/
 
@@ -613,7 +627,12 @@ HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *pTaskConfig, int *pnBu
         header.title = empty_string; /* FIXME: Set to exe path instead */
     header.titleSize = STR_SIZE(header.title);
 
-    header.template.style = DS_MODALFRAME | WS_CAPTION | WS_VISIBLE;
+    header.template.style = DS_MODALFRAME | WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE;
+    if(dialog->has_cancel)
+        header.template.style |= WS_SYSMENU;
+    if(pTaskConfig->dwFlags & TDF_CAN_BE_MINIMIZED)
+        header.template.style |= WS_SYSMENU | WS_MINIMIZEBOX;
+
     header.template.cdit = list_count(controls);
 
     /* TaskDialogs are always desktop centered */
@@ -622,6 +641,7 @@ HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *pTaskConfig, int *pnBu
     header.template.x = (desktop.right - dialog_width)/2;
     header.template.y = (desktop.bottom - dialog_height)/2;
 
+
     /* Turn template information into a dialog template to display it */
     template_data = dialog_template_create(header, controls);
 
diff --git a/dlls/comctl32/tests/taskdialog.c b/dlls/comctl32/tests/taskdialog.c
index 7d6429c9c6..95ffe50eea 100644
--- a/dlls/comctl32/tests/taskdialog.c
+++ b/dlls/comctl32/tests/taskdialog.c
@@ -137,6 +137,15 @@ static const message_data mes_help[] = {
     { TDN_NO_MORE_MESSAGES }
 };
 
+static const message_data mes_cancel_ok_button_press[] = {
+    { TDN_DIALOG_CONSTRUCTED, 0, 0 },
+    { TDN_CREATED, 0, 0 },
+    { TDN_BUTTON_CLICKED, IDCANCEL, 0, S_FALSE, 1 },
+    { TDN_BUTTON_CLICKED, IDOK, 0, S_OK },
+    { TDN_DESTROYED, 0, 0 },
+    { TDN_NO_MORE_MESSAGES }
+};
+
 /* Message lists to send */
 
 static const message_send_data mes_send_return[] = {
@@ -201,6 +210,40 @@ static const message_send_data mes_send_F1[] = {
     { 0 }
 };
 
+static const message_send_data mes_send_esc[] = {
+    { WM_KEYDOWN, VK_ESCAPE, 0 },
+    { 0 }
+};
+
+static const message_send_data mes_send_close[] = {
+    { WM_CLOSE, 0, 0 },
+    { 0 }
+};
+
+static const message_send_data mes_send_esc_return[] = {
+    { WM_KEYDOWN, VK_ESCAPE, 0 },
+    { WM_KEYDOWN, VK_RETURN, 0 },
+    { 0 }
+};
+
+static const message_send_data mes_send_close_return[] = {
+    { WM_CLOSE, 0, 0 },
+    { WM_KEYDOWN, VK_RETURN, 0 },
+    { 0 }
+};
+
+static const message_send_data mes_send_esc_ok_cancel[] = {
+    { WM_KEYDOWN, VK_ESCAPE, 0, NULL, SEND_SYNCRONIZED },
+    { TDM_CLICK_BUTTON, IDOK, 0 },
+    { 0 }
+};
+
+static const message_send_data mes_send_close_ok_cancel[] = {
+    { WM_CLOSE, 0, 0, NULL, SEND_SYNCRONIZED },
+    { TDM_CLICK_BUTTON, IDOK, 0 },
+    { 0 }
+};
+
 /* Our only way to get a button handle, since GetDlgItem and FindWindowEx don't work for the official taskdialog */
 
 static HWND taskdialog_child;
@@ -531,6 +574,44 @@ static void test_TaskDialogIndirect(void)
     /* Test TDM_HELP */
 
     run_test(&info, IDOK, 0, 0, mes_help, mes_send_F1);
+
+    /* Test ability to cancel dialog */
+
+    /* Test with TDF_ALLOW_DIALOG_CANCELLATION and without cancel button */
+    info.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION;
+    info.dwCommonButtons = TDCBF_OK_BUTTON;
+    run_test(&info, IDCANCEL, 0, 0, mes_button_clicked_cancel, mes_send_esc);
+    run_test(&info, IDCANCEL, 0, 0, mes_button_clicked_cancel, mes_send_close);
+
+    /* Test with TDF_ALLOW_DIALOG_CANCELLATION and without cancel button */
+    info.dwFlags = TDF_CAN_BE_MINIMIZED;
+    info.dwCommonButtons = TDCBF_OK_BUTTON;
+    run_test(&info, IDCANCEL, 0, 0, mes_button_clicked_cancel, mes_send_esc);
+    run_test(&info, IDCANCEL, 0, 0, mes_button_clicked_cancel, mes_send_close);
+
+    /* Test without allow-cancel flag and with cancel button */
+    info.dwFlags = 0;
+    info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON;
+    run_test(&info, IDCANCEL, 0, 0, mes_button_clicked_cancel, mes_send_esc);
+    run_test(&info, IDCANCEL, 0, 0, mes_button_clicked_cancel, mes_send_close);
+
+    /* Test without allow-cancel flag and without cancel button */
+    info.dwFlags = 0;
+    info.dwCommonButtons = TDCBF_OK_BUTTON;
+    run_test(&info, IDOK, 0, 0, mes_button_clicked_ok, mes_send_esc_return);
+    run_test(&info, IDOK, 0, 0, mes_button_clicked_ok, mes_send_close_return);
+
+    /* Test if the callback can disable the cancellation with cancel button */
+    info.dwFlags = 0;
+    info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON;
+    run_test(&info, IDOK, 0, 0, mes_cancel_ok_button_press, mes_send_esc_ok_cancel);
+    run_test(&info, IDOK, 0, 0, mes_cancel_ok_button_press, mes_send_close_ok_cancel);
+
+    /* Test if the callback can disable the cancellation without cancel button */
+    info.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION;
+    info.dwCommonButtons = TDCBF_OK_BUTTON;
+    run_test(&info, IDOK, 0, 0, mes_cancel_ok_button_press, mes_send_esc_ok_cancel);
+    run_test(&info, IDOK, 0, 0, mes_cancel_ok_button_press, mes_send_close_ok_cancel);
 }
 
 START_TEST(taskdialog)
-- 
2.11.1




More information about the wine-patches mailing list