[PATCH v2 2/3] comctl32/taskdialog: Add support for radio buttons.

Zhiyi Zhang zzhang at codeweavers.com
Mon Jun 25 22:36:37 CDT 2018


Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/comctl32/taskdialog.c       | 139 ++++++++++++++++++++++++-
 dlls/comctl32/tests/taskdialog.c | 172 +++++++++++++++++++++++++++----
 2 files changed, 290 insertions(+), 21 deletions(-)

diff --git a/dlls/comctl32/taskdialog.c b/dlls/comctl32/taskdialog.c
index 5625f2bc24..207f77b012 100644
--- a/dlls/comctl32/taskdialog.c
+++ b/dlls/comctl32/taskdialog.c
@@ -58,6 +58,8 @@ struct taskdialog_info
     HWND main_instruction;
     HWND content;
     HWND progress_bar;
+    HWND *radio_buttons;
+    INT radio_button_count;
     HWND *buttons;
     INT button_count;
     HWND default_button;
@@ -69,6 +71,7 @@ struct taskdialog_info
         LONG h_spacing;
         LONG v_spacing;
     } m;
+    INT selected_radio_id;
 };
 
 struct button_layout_info
@@ -185,6 +188,18 @@ static void taskdialog_enable_button(const struct taskdialog_info *dialog_info,
     if (hwnd) EnableWindow(hwnd, enable);
 }
 
+static void taskdialog_enable_radio_button(const struct taskdialog_info *dialog_info, INT id, BOOL enable)
+{
+    HWND hwnd = taskdialog_find_button(dialog_info->radio_buttons, dialog_info->radio_button_count, id);
+    if (hwnd) EnableWindow(hwnd, enable);
+}
+
+static void taskdialog_click_radio_button(const struct taskdialog_info *dialog_info, INT id)
+{
+    HWND hwnd = taskdialog_find_button(dialog_info->radio_buttons, dialog_info->radio_button_count, id);
+    if (hwnd) SendMessageW(hwnd, BM_CLICK, 0, 0);
+}
+
 static HRESULT taskdialog_notify(struct taskdialog_info *dialog_info, UINT notification, WPARAM wparam, LPARAM lparam)
 {
     const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
@@ -193,8 +208,18 @@ static HRESULT taskdialog_notify(struct taskdialog_info *dialog_info, UINT notif
                : S_OK;
 }
 
-static void taskdialog_on_button_click(struct taskdialog_info *dialog_info, WORD command_id)
+static void taskdialog_on_button_click(struct taskdialog_info *dialog_info, INT command_id)
 {
+    HWND radio_button;
+
+    radio_button = taskdialog_find_button(dialog_info->radio_buttons, dialog_info->radio_button_count, command_id);
+    if (radio_button)
+    {
+        dialog_info->selected_radio_id = command_id;
+        taskdialog_notify(dialog_info, TDN_RADIO_BUTTON_CLICKED, command_id, 0);
+        return;
+    }
+
     if (taskdialog_notify(dialog_info, TDN_BUTTON_CLICKED, command_id, 0) == S_OK)
         EndDialog(dialog_info->hwnd, command_id);
 }
@@ -269,6 +294,49 @@ static void taskdialog_get_label_size(struct taskdialog_info *dialog_info, HWND
     Free(text);
 }
 
+static void taskdialog_get_radio_button_size(struct taskdialog_info *dialog_info, HWND hwnd, LONG max_width, SIZE *size)
+{
+    DWORD style = DT_EXPANDTABS | DT_CALCRECT | DT_WORDBREAK;
+    HFONT hfont, old_hfont;
+    HDC hdc;
+    RECT rect = {0};
+    INT text_length;
+    WCHAR *text;
+    INT text_offset, radio_box_width, radio_box_height;
+
+    hdc = GetDC(hwnd);
+    hfont = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0);
+    old_hfont = SelectObject(hdc, hfont);
+
+    radio_box_width = 12 * GetDeviceCaps(hdc, LOGPIXELSX) / 96 + 1;
+    radio_box_height = 12 * GetDeviceCaps(hdc, LOGPIXELSY) / 96 + 1;
+    GetCharWidthW(hdc, '0', '0', &text_offset);
+    text_offset /= 2;
+
+    if (dialog_info->taskconfig->dwFlags & TDF_RTL_LAYOUT)
+        style |= DT_RIGHT | DT_RTLREADING;
+    else
+        style |= DT_LEFT;
+
+    rect.right = max_width - radio_box_width - text_offset;
+    text_length = GetWindowTextLengthW(hwnd);
+    text = Alloc((text_length + 1) * sizeof(WCHAR));
+    if (!text)
+    {
+        size->cx = 0;
+        size->cy = 0;
+        return;
+    }
+    GetWindowTextW(hwnd, text, text_length + 1);
+    size->cy = DrawTextW(hdc, text, text_length, &rect, style);
+    size->cx = min(max_width - radio_box_width - text_offset, rect.right - rect.left);
+    size->cx += radio_box_width + text_offset;
+    size->cy = max(size->cy, radio_box_height);
+    if (old_hfont) SelectObject(hdc, old_hfont);
+    Free(text);
+    ReleaseDC(hwnd, hdc);
+}
+
 static ULONG_PTR taskdialog_get_standard_icon(LPCWSTR icon)
 {
     if (icon == TD_WARNING_ICON)
@@ -309,6 +377,28 @@ static void taskdialog_set_icon(struct taskdialog_info *dialog_info, INT element
     }
 }
 
+static void taskdialog_check_default_radio_buttons(struct taskdialog_info *dialog_info)
+{
+    const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+    HWND default_button;
+    INT id;
+
+    if (!dialog_info->radio_button_count) return;
+
+    default_button = taskdialog_find_button(dialog_info->radio_buttons, dialog_info->radio_button_count,
+                                            taskconfig->nDefaultRadioButton);
+
+    if (!default_button && !(taskconfig->dwFlags & TDF_NO_DEFAULT_RADIO_BUTTON))
+        default_button = dialog_info->radio_buttons[0];
+
+    if (default_button)
+    {
+        SendMessageW(default_button, BM_SETCHECK, BST_CHECKED, 0);
+        id = GetWindowLongW(default_button, GWLP_ID);
+        taskdialog_on_button_click(dialog_info, id);
+    }
+}
+
 static void taskdialog_add_main_icon(struct taskdialog_info *dialog_info)
 {
     if (!dialog_info->taskconfig->u.hMainIcon) return;
@@ -372,6 +462,30 @@ static void taskdialog_add_progress_bar(struct taskdialog_info *dialog_info)
         CreateWindowW(PROGRESS_CLASSW, NULL, style, 0, 0, 0, 0, dialog_info->hwnd, NULL, 0, NULL);
 }
 
+static void taskdialog_add_radio_buttons(struct taskdialog_info *dialog_info)
+{
+    const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+    static const DWORD style = BS_AUTORADIOBUTTON | BS_MULTILINE | BS_TOP | WS_CHILD | WS_VISIBLE | WS_TABSTOP;
+    WCHAR *textW;
+    INT i;
+
+    if (!taskconfig->cRadioButtons || !taskconfig->pRadioButtons) return;
+
+    dialog_info->radio_buttons = Alloc(taskconfig->cRadioButtons * sizeof(*dialog_info->radio_buttons));
+    if (!dialog_info->radio_buttons) return;
+
+    dialog_info->radio_button_count = taskconfig->cRadioButtons;
+    for (i = 0; i < dialog_info->radio_button_count; i++)
+    {
+        textW = taskdialog_gettext(dialog_info, TRUE, taskconfig->pRadioButtons[i].pszButtonText);
+        dialog_info->radio_buttons[i] =
+            CreateWindowW(WC_BUTTONW, textW, i == 0 ? style | WS_GROUP : style, 0, 0, 0, 0, dialog_info->hwnd,
+                          (HMENU)taskconfig->pRadioButtons[i].nButtonID, 0, NULL);
+        SendMessageW(dialog_info->radio_buttons[i], WM_SETFONT, (WPARAM)dialog_info->font, 0);
+        Free(textW);
+    }
+}
+
 static void taskdialog_add_button(struct taskdialog_info *dialog_info, HWND *button, INT_PTR id, const WCHAR *text,
                                   BOOL custom_button)
 {
@@ -496,6 +610,17 @@ static void taskdialog_layout(struct taskdialog_info *dialog_info)
         dialog_height = y + size.cy;
     }
 
+    /* Radio buttons */
+    for (i = 0; i < dialog_info->radio_button_count; i++)
+    {
+        x = main_icon_right + h_spacing;
+        y = dialog_height;
+        taskdialog_get_radio_button_size(dialog_info, dialog_info->radio_buttons[i], dialog_width - x - h_spacing, &size);
+        size.cx = dialog_width - x - h_spacing;
+        SetWindowPos(dialog_info->radio_buttons[i], 0, x, y, size.cx, size.cy, SWP_NOZORDER);
+        dialog_height = y + size.cy;
+    }
+
     dialog_height = max(dialog_height, main_icon_bottom);
 
     /* Common and custom buttons */
@@ -630,6 +755,7 @@ static void taskdialog_init(struct taskdialog_info *dialog_info, HWND hwnd)
     taskdialog_add_main_instruction(dialog_info);
     taskdialog_add_content(dialog_info);
     taskdialog_add_progress_bar(dialog_info);
+    taskdialog_add_radio_buttons(dialog_info);
     taskdialog_add_buttons(dialog_info);
 
     /* Set default button */
@@ -647,6 +773,7 @@ static void taskdialog_destroy(struct taskdialog_info *dialog_info)
     if (dialog_info->font) DeleteObject(dialog_info->font);
     if (dialog_info->main_instruction_font) DeleteObject(dialog_info->main_instruction_font);
     if (dialog_info->buttons) Free(dialog_info->buttons);
+    if (dialog_info->radio_buttons) Free(dialog_info->radio_buttons);
 }
 
 static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
@@ -698,6 +825,12 @@ static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPAR
         case TDM_SET_PROGRESS_BAR_MARQUEE:
             SendMessageW(dialog_info->progress_bar, PBM_SETMARQUEE, wParam, lParam);
             break;
+        case TDM_CLICK_RADIO_BUTTON:
+            taskdialog_click_radio_button(dialog_info, wParam);
+            break;
+        case TDM_ENABLE_RADIO_BUTTON:
+            taskdialog_enable_radio_button(dialog_info, wParam, lParam);
+            break;
         case WM_INITDIALOG:
             dialog_info = (struct taskdialog_info *)lParam;
 
@@ -706,6 +839,8 @@ static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPAR
             SetPropW(hwnd, taskdialog_info_propnameW, dialog_info);
             taskdialog_notify(dialog_info, TDN_DIALOG_CONSTRUCTED, 0, 0);
             taskdialog_notify(dialog_info, TDN_CREATED, 0, 0);
+            /* Default radio button click notification sent after TDN_CREATED */
+            taskdialog_check_default_radio_buttons(dialog_info);
             return FALSE;
         case WM_COMMAND:
             if (HIWORD(wParam) == BN_CLICKED)
@@ -771,7 +906,7 @@ HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *taskconfig, int *butto
     Free(template);
 
     if (button) *button = ret;
-    if (radio_button) *radio_button = taskconfig->nDefaultButton;
+    if (radio_button) *radio_button = dialog_info.selected_radio_id;
     if (verification_flag_checked) *verification_flag_checked = TRUE;
 
     return S_OK;
diff --git a/dlls/comctl32/tests/taskdialog.c b/dlls/comctl32/tests/taskdialog.c
index e91a878876..2cda04081f 100644
--- a/dlls/comctl32/tests/taskdialog.c
+++ b/dlls/comctl32/tests/taskdialog.c
@@ -35,9 +35,11 @@
 #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 *,
@@ -141,6 +143,78 @@ static const struct message_info msg_got_tdn_help[] =
     { 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 void init_test_message(UINT message, WPARAM wParam, LPARAM lParam, struct message *msg)
 {
     msg->message = WM_TD_CALLBACK;
@@ -151,11 +225,13 @@ static void init_test_message(UINT message, WPARAM wParam, LPARAM lParam, struct
     msg->stage = 0;
 }
 
-#define run_test(info, expect_button, seq, context) \
-        run_test_(info, expect_button, seq, context, ARRAY_SIZE(seq) - 1, __FILE__, __LINE__)
+#define run_test(info, expect_button, expect_radio_button, seq, context) \
+        run_test_(info, expect_button, expect_radio_button, seq, context, \
+                  ARRAY_SIZE(seq) - 1, __FILE__, __LINE__)
 
-static void run_test_(TASKDIALOGCONFIG *info, int expect_button, const struct message_info *test_messages,
-    const char *context, int test_messages_len, const char *file, int line)
+static void run_test_(TASKDIALOGCONFIG *info, int expect_button, int expect_radio_button,
+                      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;
@@ -182,6 +258,8 @@ static void run_test_(TASKDIALOGCONFIG *info, int expect_button, const struct me
     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);
 }
@@ -239,16 +317,17 @@ static void test_callback(void)
     info.pfCallback = taskdialog_callback_proc;
     info.lpCallbackData = test_ref_data;
 
-    run_test(&info, IDOK, msg_return_press_ok, "Press VK_RETURN.");
+    run_test(&info, IDOK, 0, msg_return_press_ok, "Press VK_RETURN.");
 }
 
 static void test_buttons(void)
 {
     TASKDIALOGCONFIG info = {0};
 
-    TASKDIALOG_BUTTON custom_buttons[TEST_NUM_BUTTONS];
+    TASKDIALOG_BUTTON custom_buttons[TEST_NUM_BUTTONS], radio_buttons[TEST_NUM_RADIO_BUTTONS];
     const WCHAR button_format[] = {'%','0','2','d',0};
-    WCHAR button_titles[TEST_NUM_BUTTONS * 3]; /* Each button has two digits as title, plus null-terminator */
+    /* 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);
@@ -266,48 +345,103 @@ static void test_buttons(void)
     }
     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, msg_return_press_ok, "default button: unset default");
+    run_test(&info, IDOK, 0, 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, msg_return_press_yes, "default button: unset default");
+    run_test(&info, IDYES, 0, 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, msg_return_press_no, "default button: unset default");
+    run_test(&info, IDNO, 0, msg_return_press_no, "default button: unset default");
     info.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
-    run_test(&info, IDRETRY, msg_return_press_retry, "default button: unset default");
+    run_test(&info, IDRETRY, 0, msg_return_press_retry, "default button: unset default");
     info.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_CLOSE_BUTTON;
-    run_test(&info, IDCANCEL, msg_return_press_cancel, "default button: unset default");
+    run_test(&info, IDCANCEL, 0, msg_return_press_cancel, "default button: unset default");
 
     /* 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, msg_return_press_custom1, "default button: invalid default, with common buttons - 1");
+    run_test(&info, ID_START_BUTTON, 0, 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, msg_return_press_custom10, "default button: invalid default, with common buttons - 2");
+    run_test(&info, -1, 0, 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, msg_return_press_custom1, "default button: invalid default, with common buttons - 3");
+    run_test(&info, ID_START_BUTTON, 0, 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, msg_return_press_custom1, "default button: invalid default, no common buttons");
+    run_test(&info, ID_START_BUTTON, 0, 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, msg_return_press_retry, "default button: valid default - 1");
+    run_test(&info, IDRETRY, 0, 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, msg_return_press_custom4, "default button: valid default - 2");
+    run_test(&info, ID_START_BUTTON + 3, 0, 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, 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, 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, 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, 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, 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, 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, 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, msg_return_no_default_radio_button_id_and_flag, "default radio button: no default flag, invalid id");
 }
 
 static void test_help(void)
@@ -319,7 +453,7 @@ static void test_help(void)
     info.lpCallbackData = test_ref_data;
     info.dwCommonButtons = TDCBF_OK_BUTTON;
 
-    run_test(&info, IDOK, msg_got_tdn_help, "send f1");
+    run_test(&info, IDOK, 0, msg_got_tdn_help, "send f1");
 }
 
 struct timer_notification_data
-- 
2.17.1





More information about the wine-devel mailing list