Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917/* Unit tests for the task dialog control. * * Copyright 2017 Fabian Maurer for the Wine project * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
#include <stdarg.h>
#include "windef.h"#include "winbase.h"#include "winuser.h"#include "commctrl.h"
#include "wine/heap.h"#include "wine/test.h"#include "v6util.h"#include "msg.h"
#ifdef __REACTOS__#undef WM_KEYF1#define WM_KEYF1 0x004d#endif
#define WM_TD_CALLBACK (WM_APP) /* Custom dummy message to wrap callback notifications */
#define NUM_MSG_SEQUENCES 1#define TASKDIALOG_SEQ_INDEX 0
#define TEST_NUM_BUTTONS 10 /* Number of custom buttons to test with */#define TEST_NUM_RADIO_BUTTONS 3
#define ID_START 20 /* Lower IDs might be used by the system */#define ID_START_BUTTON (ID_START + 0)#define ID_START_RADIO_BUTTON (ID_START + 20)
static HRESULT (WINAPI *pTaskDialogIndirect)(const TASKDIALOGCONFIG *, int *, int *, BOOL *);static HRESULT (WINAPI *pTaskDialog)(HWND, HINSTANCE, const WCHAR *, const WCHAR *, const WCHAR *, TASKDIALOG_COMMON_BUTTON_FLAGS, const WCHAR *, int *);
static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
struct message_info{ UINT message; WPARAM wparam; LPARAM lparam;
HRESULT callback_retval; const struct message_info *send; /* Message to send to trigger the next callback message */};
static const struct message_info *current_message_info;
/* Messages to send */static const struct message_info msg_send_return[] ={ { WM_KEYDOWN, VK_RETURN, 0 }, { 0 }};
/* Messages to test against */static const struct message_info msg_return_press_ok[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_return }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_return_press_yes[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_return }, { TDN_BUTTON_CLICKED, IDYES, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_return_press_no[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_return }, { TDN_BUTTON_CLICKED, IDNO, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_return_press_cancel[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_return }, { TDN_BUTTON_CLICKED, IDCANCEL, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_return_press_retry[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_return }, { TDN_BUTTON_CLICKED, IDRETRY, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_return_press_custom1[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_return }, { TDN_BUTTON_CLICKED, ID_START_BUTTON, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_return_press_custom4[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_return }, { TDN_BUTTON_CLICKED, ID_START_BUTTON + 3, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_return_press_custom10[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_return }, { TDN_BUTTON_CLICKED, -1, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_send_click_ok[] ={ { TDM_CLICK_BUTTON, IDOK, 0 }, { 0 }};
static const struct message_info msg_send_f1[] ={ { WM_KEYF1, 0, 0, 0}, { 0 }};
static const struct message_info msg_got_tdn_help[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_f1 }, { TDN_HELP, 0, 0, S_OK, msg_send_click_ok }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
/* Three radio buttons */static const struct message_info msg_return_default_radio_button_1[] ={ { TDN_CREATED, 0, 0, S_OK, NULL }, { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, msg_send_click_ok }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_return_default_radio_button_2[] ={ { TDN_CREATED, 0, 0, S_OK, NULL }, { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON + 1, 0, S_OK, msg_send_click_ok }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_return_default_radio_button_3[] ={ { TDN_CREATED, 0, 0, S_OK, NULL }, { TDN_RADIO_BUTTON_CLICKED, -2, 0, S_OK, msg_send_click_ok }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_select_first_radio_button[] ={ { TDM_CLICK_RADIO_BUTTON, ID_START_RADIO_BUTTON, 0 }, { 0 }};
static const struct message_info msg_return_first_radio_button[] ={ { TDN_CREATED, 0, 0, S_OK, NULL }, { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON + 1, 0, S_OK, msg_select_first_radio_button }, { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, msg_send_click_ok }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_select_first_disabled_radio_button_and_press_ok[] ={ { TDM_ENABLE_RADIO_BUTTON, ID_START_RADIO_BUTTON, 0 }, { TDM_CLICK_RADIO_BUTTON, ID_START_RADIO_BUTTON, 0 }, { TDM_CLICK_BUTTON, IDOK, 0 }, { 0 }};
static const struct message_info msg_return_default_radio_button_clicking_disabled[] ={ { TDN_CREATED, 0, 0, S_OK, NULL }, { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON + 1, 0, S_OK, msg_select_first_disabled_radio_button_and_press_ok }, { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, NULL }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_return_no_default_radio_button_flag[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_click_ok }, { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, NULL }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_return_no_default_radio_button_id_and_flag[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_click_ok }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_select_negative_id_radio_button[] ={ { TDM_CLICK_RADIO_BUTTON, -2, 0 }, { 0 }};
static const struct message_info msg_return_press_negative_id_radio_button[] ={ { TDN_CREATED, 0, 0, S_OK, msg_select_negative_id_radio_button }, { TDN_RADIO_BUTTON_CLICKED, -2, 0, S_OK, msg_send_click_ok }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_send_all_common_button_click[] ={ { TDM_CLICK_BUTTON, IDOK, 0 }, { TDM_CLICK_BUTTON, IDYES, 0 }, { TDM_CLICK_BUTTON, IDNO, 0 }, { TDM_CLICK_BUTTON, IDCANCEL, 0 }, { TDM_CLICK_BUTTON, IDRETRY, 0 }, { TDM_CLICK_BUTTON, IDCLOSE, 0 }, { TDM_CLICK_BUTTON, ID_START_BUTTON + 99, 0 }, { 0 }};
static const struct message_info msg_press_nonexistent_buttons[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_all_common_button_click }, { TDN_BUTTON_CLICKED, IDOK, 0, S_FALSE, NULL }, { TDN_BUTTON_CLICKED, IDYES, 0, S_FALSE, NULL }, { TDN_BUTTON_CLICKED, IDNO, 0, S_FALSE, NULL }, { TDN_BUTTON_CLICKED, IDCANCEL, 0, S_FALSE, NULL }, { TDN_BUTTON_CLICKED, IDRETRY, 0, S_FALSE, NULL }, { TDN_BUTTON_CLICKED, IDCLOSE, 0, S_FALSE, NULL }, { TDN_BUTTON_CLICKED, ID_START_BUTTON + 99, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_send_all_common_button_click_with_command[] ={ { WM_COMMAND, MAKEWORD(IDOK, BN_CLICKED), 0 }, { WM_COMMAND, MAKEWORD(IDYES, BN_CLICKED), 0 }, { WM_COMMAND, MAKEWORD(IDNO, BN_CLICKED), 0 }, { WM_COMMAND, MAKEWORD(IDCANCEL, BN_CLICKED), 0 }, { WM_COMMAND, MAKEWORD(IDRETRY, BN_CLICKED), 0 }, { WM_COMMAND, MAKEWORD(IDCLOSE, BN_CLICKED), 0 }, { WM_COMMAND, MAKEWORD(ID_START_BUTTON + 99, BN_CLICKED), 0 }, { WM_COMMAND, MAKEWORD(IDOK, BN_CLICKED), 0 }, { 0 }};
static const struct message_info msg_press_nonexistent_buttons_with_command[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_all_common_button_click_with_command }, { TDN_BUTTON_CLICKED, ID_START_BUTTON, 0, S_FALSE, NULL }, { TDN_BUTTON_CLICKED, ID_START_BUTTON, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_send_nonexistent_radio_button_click[] ={ { TDM_CLICK_RADIO_BUTTON, ID_START_RADIO_BUTTON + 99, 0 }, { TDM_CLICK_BUTTON, IDOK, 0 }, { 0 }};
static const struct message_info msg_press_nonexistent_radio_button[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_nonexistent_radio_button_click }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_return_default_verification_unchecked[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_click_ok }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_return_default_verification_checked[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_click_ok }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_uncheck_verification[] ={ { TDM_CLICK_VERIFICATION, FALSE, 0 }, { 0 }};
static const struct message_info msg_return_verification_unchecked[] ={ { TDN_CREATED, 0, 0, S_OK, msg_uncheck_verification }, { TDN_VERIFICATION_CLICKED, FALSE, 0, S_OK, msg_send_click_ok }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_check_verification[] ={ { TDM_CLICK_VERIFICATION, TRUE, 0 }, { 0 }};
static const struct message_info msg_return_verification_checked[] ={ { TDN_CREATED, 0, 0, S_OK, msg_check_verification }, { TDN_VERIFICATION_CLICKED, TRUE, 0, S_OK, msg_send_click_ok }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static TASKDIALOGCONFIG navigated_info = {0};
static const struct message_info msg_send_navigate[] ={ { TDM_NAVIGATE_PAGE, 0, (LPARAM)&navigated_info, 0}, { 0 }};
static const struct message_info msg_return_navigated_page[] ={ { TDN_CREATED, 0, 0, S_OK, NULL }, { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, msg_send_navigate }, { TDN_DIALOG_CONSTRUCTED, 0, 0, S_OK, NULL }, { TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, NULL }, { TDN_NAVIGATED, 0, 0, S_OK, msg_send_click_ok }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_send_close[] ={ { WM_CLOSE, 0, 0, 0}, { 0 }};
static const struct message_info msg_handle_wm_close[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_close }, { TDN_BUTTON_CLICKED, IDCANCEL, 0, S_FALSE, msg_send_close }, { TDN_BUTTON_CLICKED, IDCANCEL, 0, S_OK, NULL }, { 0 }};
static const struct message_info msg_send_close_then_ok[] ={ { WM_CLOSE, 0, 0, 0}, { TDM_CLICK_BUTTON, IDOK, 0 }, { 0 }};
static const struct message_info msg_handle_wm_close_without_cancel_button[] ={ { TDN_CREATED, 0, 0, S_OK, msg_send_close_then_ok }, { TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL }, { 0 }};
static void init_test_message(UINT message, WPARAM wParam, LPARAM lParam, struct message *msg){ msg->message = WM_TD_CALLBACK; msg->flags = sent|wparam|lparam|id; msg->wParam = wParam; msg->lParam = lParam; msg->id = message; msg->stage = 0;}
#define run_test(info, expect_button, expect_radio_button, verification_checked, seq, context) \ run_test_(info, expect_button, expect_radio_button, verification_checked, seq, context, \ ARRAY_SIZE(seq) - 1, __FILE__, __LINE__)
static void run_test_(TASKDIALOGCONFIG *info, int expect_button, int expect_radio_button, BOOL verification_checked, const struct message_info *test_messages, const char *context, int test_messages_len, const char *file, int line){ struct message *msg, *msg_start; int ret_button = 0; int ret_radio = 0; BOOL ret_verification = FALSE; HRESULT hr; int i;
/* Allocate messages to test against, plus 2 implicit and 1 empty */ msg_start = msg = heap_alloc_zero(sizeof(*msg) * (test_messages_len + 3));
/* Always needed, thus made implicit */ init_test_message(TDN_DIALOG_CONSTRUCTED, 0, 0, msg++); for (i = 0; i < test_messages_len; i++) init_test_message(test_messages[i].message, test_messages[i].wparam, test_messages[i].lparam, msg++); /* Always needed, thus made implicit */ init_test_message(TDN_DESTROYED, 0, 0, msg++);
current_message_info = test_messages; flush_sequences(sequences, NUM_MSG_SEQUENCES);
hr = pTaskDialogIndirect(info, &ret_button, &ret_radio, &ret_verification); ok_(file, line)(hr == S_OK, "TaskDialogIndirect() failed, got %#x.\n", hr);
ok_sequence_(sequences, TASKDIALOG_SEQ_INDEX, msg_start, context, FALSE, file, line); ok_(file, line)(ret_button == expect_button, "Wrong button. Expected %d, got %d\n", expect_button, ret_button); ok_(file, line)(ret_radio == expect_radio_button, "Wrong radio button. Expected %d, got %d\n", expect_radio_button, ret_radio);
heap_free(msg_start);}
static const LONG_PTR test_ref_data = 123456;
static HRESULT CALLBACK taskdialog_callback_proc(HWND hwnd, UINT notification, WPARAM wParam, LPARAM lParam, LONG_PTR ref_data){ int msg_pos = sequences[TASKDIALOG_SEQ_INDEX]->count - 1; /* Skip implicit message */ const struct message_info *msg_send; struct message msg;
ok(test_ref_data == ref_data, "Unexpected ref data %lu.\n", ref_data);
init_test_message(notification, (short)wParam, lParam, &msg); add_message(sequences, TASKDIALOG_SEQ_INDEX, &msg);
if (notification == TDN_DIALOG_CONSTRUCTED || notification == TDN_DESTROYED) /* Skip implicit messages */ return S_OK;
msg_send = current_message_info[msg_pos].send; for(; msg_send && msg_send->message; msg_send++) PostMessageW(hwnd, msg_send->message, msg_send->wparam, msg_send->lparam);
return current_message_info[msg_pos].callback_retval;}
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);}
static void test_callback(void){ TASKDIALOGCONFIG info = {0};
info.cbSize = sizeof(TASKDIALOGCONFIG); info.pfCallback = taskdialog_callback_proc; info.lpCallbackData = test_ref_data;
run_test(&info, IDOK, 0, FALSE, msg_return_press_ok, "Press VK_RETURN.");}
static void test_buttons(void){ TASKDIALOGCONFIG info = {0}; static const DWORD command_link_flags[] = {0, TDF_USE_COMMAND_LINKS, TDF_USE_COMMAND_LINKS_NO_ICON}; TASKDIALOG_BUTTON custom_buttons[TEST_NUM_BUTTONS], radio_buttons[TEST_NUM_RADIO_BUTTONS]; const WCHAR button_format[] = {'%','0','2','d',0}; /* Each button has two digits as title, plus null-terminator */ WCHAR button_titles[TEST_NUM_BUTTONS * 3], radio_button_titles[TEST_NUM_BUTTONS * 3]; int i;
info.cbSize = sizeof(TASKDIALOGCONFIG); info.pfCallback = taskdialog_callback_proc; info.lpCallbackData = test_ref_data;
/* Init custom buttons */ for (i = 0; i < TEST_NUM_BUTTONS; i++) { WCHAR *text = &button_titles[i * 3]; wsprintfW(text, button_format, i);
custom_buttons[i].pszButtonText = text; custom_buttons[i].nButtonID = ID_START_BUTTON + i; } custom_buttons[TEST_NUM_BUTTONS - 1].nButtonID = -1;
/* Init radio buttons */ for (i = 0; i < TEST_NUM_RADIO_BUTTONS; i++) { WCHAR *text = &radio_button_titles[i * 3]; wsprintfW(text, button_format, i);
radio_buttons[i].pszButtonText = text; radio_buttons[i].nButtonID = ID_START_RADIO_BUTTON + i; } radio_buttons[TEST_NUM_RADIO_BUTTONS - 1].nButtonID = -2;
/* Test nDefaultButton */
/* Test common buttons with invalid default ID */ info.nDefaultButton = 0; /* Should default to first created button */ info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_YES_BUTTON | TDCBF_NO_BUTTON | TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON; run_test(&info, IDOK, 0, FALSE, msg_return_press_ok, "default button: unset default"); info.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON | TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON; run_test(&info, IDYES, 0, FALSE, msg_return_press_yes, "default button: unset default"); info.dwCommonButtons = TDCBF_NO_BUTTON | TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON; run_test(&info, IDNO, 0, FALSE, msg_return_press_no, "default button: unset default"); info.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON; run_test(&info, IDRETRY, 0, FALSE, msg_return_press_retry, "default button: unset default"); info.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_CLOSE_BUTTON; run_test(&info, IDCANCEL, 0, FALSE, msg_return_press_cancel, "default button: unset default");
/* Custom buttons could be command links */ for (i = 0; i < ARRAY_SIZE(command_link_flags); i++) { info.dwFlags = command_link_flags[i];
/* Test with all common and custom buttons and invalid default ID */ info.nDefaultButton = 0xff; /* Random ID, should also default to first created button */ info.cButtons = TEST_NUM_BUTTONS; info.pButtons = custom_buttons; run_test(&info, ID_START_BUTTON, 0, FALSE, msg_return_press_custom1, "default button: invalid default, with common buttons - 1");
info.nDefaultButton = -1; /* Should work despite button ID -1 */ run_test(&info, -1, 0, FALSE, msg_return_press_custom10, "default button: invalid default, with common buttons - 2");
info.nDefaultButton = -2; /* Should also default to first created button */ run_test(&info, ID_START_BUTTON, 0, FALSE, msg_return_press_custom1, "default button: invalid default, with common buttons - 3");
/* Test with only custom buttons and invalid default ID */ info.dwCommonButtons = 0; run_test(&info, ID_START_BUTTON, 0, FALSE, msg_return_press_custom1, "default button: invalid default, no common buttons");
/* Test with common and custom buttons and valid default ID */ info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_YES_BUTTON | TDCBF_NO_BUTTON | TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON; info.nDefaultButton = IDRETRY; run_test(&info, IDRETRY, 0, FALSE, msg_return_press_retry, "default button: valid default - 1");
/* Test with common and custom buttons and valid default ID */ info.nDefaultButton = ID_START_BUTTON + 3; run_test(&info, ID_START_BUTTON + 3, 0, FALSE, msg_return_press_custom4, "default button: valid default - 2"); }
/* Test radio buttons */ info.nDefaultButton = 0; info.cButtons = 0; info.pButtons = 0; info.dwCommonButtons = TDCBF_OK_BUTTON; info.cRadioButtons = TEST_NUM_RADIO_BUTTONS; info.pRadioButtons = radio_buttons;
/* Test default first radio button */ run_test(&info, IDOK, ID_START_RADIO_BUTTON, FALSE, msg_return_default_radio_button_1, "default radio button: default first radio button");
/* Test default radio button */ info.nDefaultRadioButton = ID_START_RADIO_BUTTON + 1; run_test(&info, IDOK, info.nDefaultRadioButton, FALSE, msg_return_default_radio_button_2, "default radio button: default radio button");
/* Test default radio button with -2 */ info.nDefaultRadioButton = -2; run_test(&info, IDOK, info.nDefaultRadioButton, FALSE, msg_return_default_radio_button_3, "default radio button: default radio button with id -2");
/* Test default radio button after clicking the first, messages still work even radio button is disabled */ info.nDefaultRadioButton = ID_START_RADIO_BUTTON + 1; run_test(&info, IDOK, ID_START_RADIO_BUTTON, FALSE, msg_return_first_radio_button, "default radio button: radio button after clicking");
/* Test radio button after disabling and clicking the first */ info.nDefaultRadioButton = ID_START_RADIO_BUTTON + 1; run_test(&info, IDOK, ID_START_RADIO_BUTTON, FALSE, msg_return_default_radio_button_clicking_disabled, "default radio button: disable radio button before clicking");
/* Test no default radio button, TDF_NO_DEFAULT_RADIO_BUTTON is set, TDN_RADIO_BUTTON_CLICKED will still be received, just radio button not selected */ info.nDefaultRadioButton = ID_START_RADIO_BUTTON; info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON; run_test(&info, IDOK, info.nDefaultRadioButton, FALSE, msg_return_no_default_radio_button_flag, "default radio button: no default radio flag");
/* Test no default radio button, TDF_NO_DEFAULT_RADIO_BUTTON is set and nDefaultRadioButton is 0. * TDN_RADIO_BUTTON_CLICKED will not be sent, and just radio button not selected */ info.nDefaultRadioButton = 0; info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON; run_test(&info, IDOK, 0, FALSE, msg_return_no_default_radio_button_id_and_flag, "default radio button: no default radio id and flag");
/* Test no default radio button, TDF_NO_DEFAULT_RADIO_BUTTON is set and nDefaultRadioButton is invalid. * TDN_RADIO_BUTTON_CLICKED will not be sent, and just radio button not selected */ info.nDefaultRadioButton = 0xff; info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON; run_test(&info, IDOK, 0, FALSE, msg_return_no_default_radio_button_id_and_flag, "default radio button: no default flag, invalid id");
info.nDefaultRadioButton = 0; info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON; run_test(&info, IDOK, -2, FALSE, msg_return_press_negative_id_radio_button, "radio button: manually click radio button with negative id");
/* Test sending clicks to non-existent buttons. Notification of non-existent buttons will be sent */ info.cButtons = TEST_NUM_BUTTONS; info.pButtons = custom_buttons; info.cRadioButtons = TEST_NUM_RADIO_BUTTONS; info.pRadioButtons = radio_buttons; info.dwCommonButtons = 0; info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON; run_test(&info, ID_START_BUTTON + 99, 0, FALSE, msg_press_nonexistent_buttons, "sends click to non-existent buttons");
/* Non-existent button clicks sent by WM_COMMAND won't generate TDN_BUTTON_CLICKED except IDOK. * And will get the first existent button identifier instead of IDOK */ run_test(&info, ID_START_BUTTON, 0, FALSE, msg_press_nonexistent_buttons_with_command, "sends click to non-existent buttons with WM_COMMAND");
/* Non-existent radio button won't get notifications */ run_test(&info, IDOK, 0, FALSE, msg_press_nonexistent_radio_button, "sends click to non-existent radio buttons");}
static void test_help(void){ TASKDIALOGCONFIG info = {0};
info.cbSize = sizeof(TASKDIALOGCONFIG); info.pfCallback = taskdialog_callback_proc; info.lpCallbackData = test_ref_data; info.dwCommonButtons = TDCBF_OK_BUTTON;
run_test(&info, IDOK, 0, FALSE, msg_got_tdn_help, "send f1");}
struct timer_notification_data{ DWORD last_elapsed_ms; DWORD num_fired;};
static HRESULT CALLBACK taskdialog_callback_proc_timer(HWND hwnd, UINT notification, WPARAM wParam, LPARAM lParam, LONG_PTR ref_data){ struct timer_notification_data *data = (struct timer_notification_data *)ref_data;
if (notification == TDN_TIMER) { DWORD elapsed_ms; int delta;
elapsed_ms = (DWORD)wParam;
if (data->num_fired == 3) ok(data->last_elapsed_ms > elapsed_ms, "Expected reference time update.\n"); else { delta = elapsed_ms - data->last_elapsed_ms; ok(delta > 0, "Expected positive time tick difference.\n"); } data->last_elapsed_ms = elapsed_ms;
if (data->num_fired == 3) PostMessageW(hwnd, TDM_CLICK_BUTTON, IDOK, 0);
++data->num_fired; return data->num_fired == 3 ? S_FALSE : S_OK; }
return S_OK;}
static void test_timer(void){ struct timer_notification_data data = { 0 }; TASKDIALOGCONFIG info = { 0 };
info.cbSize = sizeof(TASKDIALOGCONFIG); info.pfCallback = taskdialog_callback_proc_timer; info.lpCallbackData = (LONG_PTR)&data; info.dwFlags = TDF_CALLBACK_TIMER; info.dwCommonButtons = TDCBF_OK_BUTTON;
pTaskDialogIndirect(&info, NULL, NULL, NULL);}
static HRESULT CALLBACK taskdialog_callback_proc_progress_bar(HWND hwnd, UINT notification, WPARAM wParam, LPARAM lParam, LONG_PTR ref_data){ unsigned long ret; LONG flags = (LONG)ref_data; if (notification == TDN_CREATED) { /* TDM_SET_PROGRESS_BAR_STATE */ ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_STATE, PBST_NORMAL, 0); ok(ret == PBST_NORMAL, "Expect state: %d got state: %lx\n", PBST_NORMAL, ret); ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_STATE, PBST_PAUSED, 0); ok(ret == PBST_NORMAL, "Expect state: %d got state: %lx\n", PBST_NORMAL, ret); ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_STATE, PBST_ERROR, 0); /* Progress bar has fixme on handling PBM_SETSTATE message */ todo_wine ok(ret == PBST_PAUSED, "Expect state: %d got state: %lx\n", PBST_PAUSED, ret); ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_STATE, PBST_NORMAL, 0); todo_wine ok(ret == PBST_ERROR, "Expect state: %d got state: %lx\n", PBST_ERROR, ret);
/* TDM_SET_PROGRESS_BAR_RANGE */ ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM(0, 200)); ok(ret == MAKELONG(0, 100), "Expect range:%x got:%lx\n", MAKELONG(0, 100), ret); ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM(0, 200)); ok(ret == MAKELONG(0, 200), "Expect range:%x got:%lx\n", MAKELONG(0, 200), ret);
/* TDM_SET_PROGRESS_BAR_POS */ if (flags & TDF_SHOW_MARQUEE_PROGRESS_BAR) { ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_POS, 1, 0); ok(ret == 0, "Expect position:%x got:%lx\n", 0, ret); ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_POS, 2, 0); ok(ret == 0, "Expect position:%x got:%lx\n", 0, ret); } else { ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_POS, 1, 0); ok(ret == 0, "Expect position:%x got:%lx\n", 0, ret); ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_POS, 2, 0); ok(ret == 1, "Expect position:%x got:%lx\n", 1, ret); }
SendMessageW(hwnd, TDM_CLICK_BUTTON, IDOK, 0); }
return S_OK;}
static void test_progress_bar(void){ TASKDIALOGCONFIG info = {0};
info.cbSize = sizeof(TASKDIALOGCONFIG); info.dwFlags = TDF_SHOW_PROGRESS_BAR; info.pfCallback = taskdialog_callback_proc_progress_bar; info.lpCallbackData = (LONG_PTR)info.dwFlags; info.dwCommonButtons = TDCBF_OK_BUTTON; pTaskDialogIndirect(&info, NULL, NULL, NULL);
info.dwFlags = TDF_SHOW_MARQUEE_PROGRESS_BAR; info.lpCallbackData = (LONG_PTR)info.dwFlags; pTaskDialogIndirect(&info, NULL, NULL, NULL);
info.dwFlags = TDF_SHOW_PROGRESS_BAR | TDF_SHOW_MARQUEE_PROGRESS_BAR; info.lpCallbackData = (LONG_PTR)info.dwFlags; pTaskDialogIndirect(&info, NULL, NULL, NULL);}
static void test_verification_box(void){ TASKDIALOGCONFIG info = {0}; WCHAR textW[] = {'t', 'e', 'x', 't', 0};
info.cbSize = sizeof(TASKDIALOGCONFIG); info.pfCallback = taskdialog_callback_proc; info.lpCallbackData = test_ref_data; info.dwCommonButtons = TDCBF_OK_BUTTON;
/* TDF_VERIFICATION_FLAG_CHECKED works even if pszVerificationText is not set */ run_test(&info, IDOK, 0, FALSE, msg_return_default_verification_unchecked, "default verification box: unchecked");
info.dwFlags = TDF_VERIFICATION_FLAG_CHECKED; run_test(&info, IDOK, 0, FALSE, msg_return_default_verification_checked, "default verification box: checked");
info.pszVerificationText = textW; run_test(&info, IDOK, 0, FALSE, msg_return_default_verification_unchecked, "default verification box: unchecked");
info.dwFlags = TDF_VERIFICATION_FLAG_CHECKED; run_test(&info, IDOK, 0, FALSE, msg_return_default_verification_checked, "default verification box: checked");
run_test(&info, IDOK, 0, FALSE, msg_return_verification_unchecked, "default verification box: default checked and then unchecked");
info.dwFlags = 0; run_test(&info, IDOK, 0, FALSE, msg_return_verification_checked, "default verification box: default unchecked and then checked");}
static void test_navigate_page(void){ TASKDIALOGCONFIG info = {0}; static const WCHAR textW[] = {'t', 'e', 'x', 't', 0}; static const WCHAR button_format[] = {'%', '0', '2', 'd', 0}; TASKDIALOG_BUTTON radio_buttons[TEST_NUM_RADIO_BUTTONS]; WCHAR radio_button_titles[TEST_NUM_BUTTONS * 3]; int i;
/* Init radio buttons */ for (i = 0; i < TEST_NUM_RADIO_BUTTONS; i++) { WCHAR *text = &radio_button_titles[i * 3]; wsprintfW(text, button_format, i);
radio_buttons[i].pszButtonText = text; radio_buttons[i].nButtonID = ID_START_RADIO_BUTTON + i; }
info.cbSize = sizeof(TASKDIALOGCONFIG); info.pfCallback = taskdialog_callback_proc; info.lpCallbackData = test_ref_data; info.dwCommonButtons = TDCBF_OK_BUTTON; info.cRadioButtons = TEST_NUM_RADIO_BUTTONS; info.pRadioButtons = radio_buttons;
navigated_info = info; navigated_info.pszVerificationText = textW; navigated_info.dwFlags = TDF_VERIFICATION_FLAG_CHECKED;
run_test(&info, IDOK, ID_START_RADIO_BUTTON, TRUE, msg_return_navigated_page, "navigate page: default");
/* TDM_NAVIGATE_PAGE doesn't check cbSize. * And null taskconfig pointer crash applicatioin, thus doesn't check pointer either */ navigated_info.cbSize = 0; run_test(&info, IDOK, ID_START_RADIO_BUTTON, TRUE, msg_return_navigated_page, "navigate page: invalid taskconfig cbSize");}
static void test_wm_close(void){ TASKDIALOGCONFIG info = {0};
info.cbSize = sizeof(TASKDIALOGCONFIG); info.pfCallback = taskdialog_callback_proc; info.lpCallbackData = test_ref_data;
/* WM_CLOSE can end the dialog only when a cancel button is present or dwFlags has TDF_ALLOW_DIALOG_CANCELLATION */ info.dwCommonButtons = TDCBF_OK_BUTTON; run_test(&info, IDOK, 0, FALSE, msg_handle_wm_close_without_cancel_button, "send WM_CLOSE without cancel button");
info.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION; run_test(&info, IDCANCEL, 0, FALSE, msg_handle_wm_close, "send WM_CLOSE with TDF_ALLOW_DIALOG_CANCELLATION");
info.dwFlags = 0; info.dwCommonButtons = TDCBF_CANCEL_BUTTON; run_test(&info, IDCANCEL, 0, FALSE, msg_handle_wm_close, "send WM_CLOSE with a cancel button");}
START_TEST(taskdialog){ ULONG_PTR ctx_cookie; void *ptr_ordinal; HINSTANCE hinst; HANDLE hCtx;
if (!load_v6_module(&ctx_cookie, &hCtx)) return;
/* Check if task dialogs are available */ hinst = LoadLibraryA("comctl32.dll");
pTaskDialogIndirect = (void *)GetProcAddress(hinst, "TaskDialogIndirect"); if (!pTaskDialogIndirect) { win_skip("TaskDialogIndirect not exported by name\n"); unload_v6_module(ctx_cookie, hCtx); return; }
pTaskDialog = (void *)GetProcAddress(hinst, "TaskDialog");
ptr_ordinal = GetProcAddress(hinst, (const char *)344); ok(pTaskDialog == ptr_ordinal, "got wrong pointer for ordinal 344, %p expected %p\n", ptr_ordinal, pTaskDialog);
ptr_ordinal = GetProcAddress(hinst, (const char *)345); ok(pTaskDialogIndirect == ptr_ordinal, "got wrong pointer for ordinal 345, %p expected %p\n", ptr_ordinal, pTaskDialogIndirect);
init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
test_invalid_parameters(); test_callback(); test_buttons(); test_help(); test_timer(); test_progress_bar(); test_verification_box(); test_navigate_page(); test_wm_close();
unload_v6_module(ctx_cookie, hCtx);}