diff --git a/dlls/comctl32/taskdialog.c b/dlls/comctl32/taskdialog.c index a14a2230a93..2558174fa3f 100644 --- a/dlls/comctl32/taskdialog.c +++ b/dlls/comctl32/taskdialog.c @@ -80,6 +80,13 @@ struct taskdialog_button_desc HINSTANCE hinst; }; +struct taskdialog_info +{ + HWND hwnd; + PFTASKDIALOGCALLBACK callback; + LONG_PTR callback_data; +}; + static void pixels_to_dialogunits(const struct taskdialog_template_desc *desc, LONG *width, LONG *height) { if (width) @@ -482,20 +489,54 @@ static DLGTEMPLATE *create_taskdialog_template(const TASKDIALOGCONFIG *taskconfi return template; } +static HRESULT taskdialog_notify(struct taskdialog_info *dialog_info, UINT notification, WPARAM wparam, LPARAM lparam) +{ + return dialog_info->callback ? dialog_info->callback(dialog_info->hwnd, notification, wparam, lparam, + dialog_info->callback_data) : S_OK; +} + +static void taskdialog_on_button_click(struct taskdialog_info *dialog_info, WORD command_id) +{ + if (taskdialog_notify(dialog_info, TDN_BUTTON_CLICKED, command_id, 0) == S_OK) + EndDialog(dialog_info->hwnd, command_id); +} + static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + static const WCHAR taskdialog_info_propnameW[] = {'T','a','s','k','D','i','a','l','o','g','I','n','f','o',0}; + struct taskdialog_info *dialog_info; + TRACE("hwnd=%p msg=0x%04x wparam=%lx lparam=%lx\n", hwnd, msg, wParam, lParam); + if (msg != WM_INITDIALOG) + dialog_info = GetPropW(hwnd, taskdialog_info_propnameW); + switch (msg) { + case TDM_CLICK_BUTTON: + taskdialog_on_button_click(dialog_info, LOWORD(wParam)); + break; + case WM_INITDIALOG: + dialog_info = (struct taskdialog_info *)lParam; + dialog_info->hwnd = hwnd; + SetPropW(hwnd, taskdialog_info_propnameW, dialog_info); + + taskdialog_notify(dialog_info, TDN_DIALOG_CONSTRUCTED, 0, 0); + break; + case WM_SHOWWINDOW: + taskdialog_notify(dialog_info, TDN_CREATED, 0, 0); + break; case WM_COMMAND: if (HIWORD(wParam) == BN_CLICKED) { - WORD command_id = LOWORD(wParam); - EndDialog(hwnd, command_id); + taskdialog_on_button_click(dialog_info, LOWORD(wParam)); return TRUE; } break; + case WM_DESTROY: + taskdialog_notify(dialog_info, TDN_DESTROYED, 0, 0); + RemovePropW(hwnd, taskdialog_info_propnameW); + break; } return FALSE; } @@ -506,13 +547,21 @@ static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPAR HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *taskconfig, int *button, int *radio_button, BOOL *verification_flag_checked) { + struct taskdialog_info dialog_info; DLGTEMPLATE *template; INT ret; TRACE("%p, %p, %p, %p\n", taskconfig, button, radio_button, verification_flag_checked); + if (!taskconfig || taskconfig->cbSize != sizeof(TASKDIALOGCONFIG)) + return E_INVALIDARG; + + dialog_info.callback = taskconfig->pfCallback; + dialog_info.callback_data = taskconfig->lpCallbackData; + template = create_taskdialog_template(taskconfig); - ret = DialogBoxIndirectParamW(taskconfig->hInstance, template, taskconfig->hwndParent, taskdialog_proc, 0); + ret = DialogBoxIndirectParamW(taskconfig->hInstance, template, taskconfig->hwndParent, + taskdialog_proc, (LPARAM)&dialog_info); Free(template); if (button) *button = ret; diff --git a/dlls/comctl32/tests/taskdialog.c b/dlls/comctl32/tests/taskdialog.c index c9371278977..57f33f38351 100644 --- a/dlls/comctl32/tests/taskdialog.c +++ b/dlls/comctl32/tests/taskdialog.c @@ -31,6 +31,27 @@ static HRESULT (WINAPI *pTaskDialogIndirect)(const TASKDIALOGCONFIG *, int *, in static HRESULT (WINAPI *pTaskDialog)(HWND, HINSTANCE, const WCHAR *, const WCHAR *, const WCHAR *, TASKDIALOG_COMMON_BUTTON_FLAGS, const WCHAR *, int *); +static void test_invalid_parameters(void) +{ + TASKDIALOGCONFIG info = { 0 }; + HRESULT hr; + + hr = pTaskDialogIndirect(NULL, NULL, NULL, NULL); + ok(hr == E_INVALIDARG, "Unexpected return value %#x.\n", hr); + + info.cbSize = 0; + hr = pTaskDialogIndirect(&info, NULL, NULL, NULL); + ok(hr == E_INVALIDARG, "Unexpected return value %#x.\n", hr); + + info.cbSize = sizeof(TASKDIALOGCONFIG) - 1; + hr = pTaskDialogIndirect(&info, NULL, NULL, NULL); + ok(hr == E_INVALIDARG, "Unexpected return value %#x.\n", hr); + + info.cbSize = sizeof(TASKDIALOGCONFIG) + 1; + hr = pTaskDialogIndirect(&info, NULL, NULL, NULL); + ok(hr == E_INVALIDARG, "Unexpected return value %#x.\n", hr); +} + START_TEST(taskdialog) { ULONG_PTR ctx_cookie; @@ -62,5 +83,7 @@ START_TEST(taskdialog) ok(pTaskDialogIndirect == ptr_ordinal, "got wrong pointer for ordinal 345, %p expected %p\n", ptr_ordinal, pTaskDialogIndirect); + test_invalid_parameters(); + unload_v6_module(ctx_cookie, hCtx); }