Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
June 2018
- 68 participants
- 1149 messages
Re: [PATCH 2/2] msvcp120: Add test for Concurrent_vector_swap.
by Piotr Caban
Signed-off-by: Piotr Caban <piotr(a)codeweavers.com>
June 17, 2018
Re: [PATCH 1/2] msvcp120: Add test for Concurrent_vector_assign.
by Piotr Caban
Signed-off-by: Piotr Caban <piotr(a)codeweavers.com>
June 17, 2018
[PATCH 3/3] comctl32/taskdialog: Add support for command links.
by Zhiyi Zhang
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/comctl32/taskdialog.c | 62 +++++++++++++++++++++++++++++---
dlls/comctl32/tests/taskdialog.c | 61 +++++++++++++++++--------------
2 files changed, 93 insertions(+), 30 deletions(-)
diff --git a/dlls/comctl32/taskdialog.c b/dlls/comctl32/taskdialog.c
index c3c5fa0420..eb2f2a4082 100644
--- a/dlls/comctl32/taskdialog.c
+++ b/dlls/comctl32/taskdialog.c
@@ -60,6 +60,8 @@ struct taskdialog_info
HWND progress_bar;
HWND *radio_buttons;
INT radio_button_count;
+ HWND *command_links;
+ INT command_link_count;
HWND *buttons;
INT button_count;
HWND default_button;
@@ -184,7 +186,8 @@ static HWND taskdialog_find_button(HWND *buttons, INT count, INT id)
static void taskdialog_enable_button(const struct taskdialog_info *dialog_info, INT id, BOOL enable)
{
- HWND hwnd = taskdialog_find_button(dialog_info->buttons, dialog_info->button_count, id);
+ HWND hwnd = taskdialog_find_button(dialog_info->command_links, dialog_info->command_link_count, id);
+ if (!hwnd) hwnd = taskdialog_find_button(dialog_info->buttons, dialog_info->button_count, id);
if (hwnd) EnableWindow(hwnd, enable);
}
@@ -253,6 +256,11 @@ static BOOL taskdialog_hyperlink_enabled(struct taskdialog_info *dialog_info)
return dialog_info->taskconfig->dwFlags & TDF_ENABLE_HYPERLINKS;
}
+static BOOL taskdialog_use_command_link(struct taskdialog_info *dialog_info)
+{
+ return dialog_info->taskconfig->dwFlags & (TDF_USE_COMMAND_LINKS | TDF_USE_COMMAND_LINKS_NO_ICON);
+}
+
static void taskdialog_get_label_size(struct taskdialog_info *dialog_info, HWND hwnd, LONG max_width, SIZE *size,
BOOL syslink)
{
@@ -468,6 +476,34 @@ static void taskdialog_add_radio_buttons(struct taskdialog_info *dialog_info)
}
}
+static void taskdialog_add_command_links(struct taskdialog_info *dialog_info)
+{
+ const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+ DWORD default_style = BS_MULTILINE | BS_LEFT | BS_TOP | WS_CHILD | WS_VISIBLE | WS_TABSTOP, style;
+ BOOL is_default;
+ WCHAR *textW;
+ INT i;
+
+ if (!taskconfig->cButtons || !taskconfig->pButtons || !taskdialog_use_command_link(dialog_info)) return;
+
+ dialog_info->command_links = Alloc(taskconfig->cButtons * sizeof(*dialog_info->command_links));
+ if (!dialog_info->command_links) return;
+
+ dialog_info->command_link_count = taskconfig->cButtons;
+ for (i = 0; i < dialog_info->command_link_count; i++)
+ {
+ is_default = taskconfig->pButtons[i].nButtonID == taskconfig->nDefaultButton;
+ style = is_default ? default_style | BS_DEFCOMMANDLINK : default_style | BS_COMMANDLINK;
+ textW = taskdialog_gettext(dialog_info, TRUE, taskconfig->pButtons[i].pszButtonText);
+ dialog_info->command_links[i] = CreateWindowW(WC_BUTTONW, textW, style, 0, 0, 0, 0, dialog_info->hwnd,
+ (HMENU)taskconfig->pButtons[i].nButtonID, 0, NULL);
+ SendMessageW(dialog_info->command_links[i], WM_SETFONT, (WPARAM)dialog_info->font, 0);
+ Free(textW);
+
+ if (is_default && !dialog_info->default_button) dialog_info->default_button = dialog_info->command_links[i];
+ }
+}
+
static void taskdialog_add_button(struct taskdialog_info *dialog_info, HWND *button, INT_PTR id, const WCHAR *text,
BOOL custom_button)
{
@@ -486,17 +522,18 @@ static void taskdialog_add_button(struct taskdialog_info *dialog_info, HWND *but
static void taskdialog_add_buttons(struct taskdialog_info *dialog_info)
{
const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+ BOOL use_command_links = taskdialog_use_command_link(dialog_info);
DWORD flags = taskconfig->dwCommonButtons;
INT count, max_count;
/* Allocate enough memory for the custom and the default buttons. Maximum 6 default buttons possible. */
max_count = 6;
- if (taskconfig->cButtons && taskconfig->pButtons) max_count += taskconfig->cButtons;
+ if (!use_command_links && taskconfig->cButtons && taskconfig->pButtons) max_count += taskconfig->cButtons;
dialog_info->buttons = Alloc(max_count * sizeof(*dialog_info->buttons));
if (!dialog_info->buttons) return;
- for (count = 0; count < taskconfig->cButtons; count++)
+ for (count = 0; !use_command_links && count < taskconfig->cButtons; count++)
taskdialog_add_button(dialog_info, &dialog_info->buttons[count], taskconfig->pButtons[count].nButtonID,
taskconfig->pButtons[count].pszButtonText, TRUE);
@@ -514,7 +551,7 @@ static void taskdialog_add_buttons(struct taskdialog_info *dialog_info)
if (flags & TDCBF_CANCEL_BUTTON) TASKDIALOG_INIT_COMMON_BUTTON(CANCEL);
if (flags & TDCBF_CLOSE_BUTTON) TASKDIALOG_INIT_COMMON_BUTTON(CLOSE);
- if (!count) TASKDIALOG_INIT_COMMON_BUTTON(OK);
+ if (!count && !dialog_info->command_link_count) TASKDIALOG_INIT_COMMON_BUTTON(OK);
#undef TASKDIALOG_INIT_COMMON_BUTTON
dialog_info->button_count = count;
@@ -603,6 +640,19 @@ static void taskdialog_layout(struct taskdialog_info *dialog_info)
dialog_height = y + size.cy;
}
+ /* Command links */
+ for (i = 0; i < dialog_info->command_link_count; i++)
+ {
+ x = main_icon_right + h_spacing;
+ y = dialog_height + v_spacing;
+ taskdialog_get_label_size(dialog_info, dialog_info->command_links[i], dialog_width - x - h_spacing, &size, FALSE);
+ size.cx = dialog_width - x - h_spacing;
+ /* Add spacing */
+ size.cy += 4;
+ SetWindowPos(dialog_info->command_links[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 */
@@ -738,9 +788,12 @@ static void taskdialog_init(struct taskdialog_info *dialog_info, HWND hwnd)
taskdialog_add_content(dialog_info);
taskdialog_add_progress_bar(dialog_info);
taskdialog_add_radio_buttons(dialog_info);
+ taskdialog_add_command_links(dialog_info);
taskdialog_add_buttons(dialog_info);
/* Set default button */
+ if (!dialog_info->default_button && dialog_info->command_links)
+ dialog_info->default_button = dialog_info->command_links[0];
if (!dialog_info->default_button) dialog_info->default_button = dialog_info->buttons[0];
SendMessageW(dialog_info->hwnd, WM_NEXTDLGCTL, (WPARAM)dialog_info->default_button, TRUE);
id = GetWindowLongW(dialog_info->default_button, GWLP_ID);
@@ -756,6 +809,7 @@ static void taskdialog_destroy(struct taskdialog_info *dialog_info)
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);
+ if (dialog_info->command_links) Free(dialog_info->command_links);
}
static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
diff --git a/dlls/comctl32/tests/taskdialog.c b/dlls/comctl32/tests/taskdialog.c
index 2cda04081f..33d3757308 100644
--- a/dlls/comctl32/tests/taskdialog.c
+++ b/dlls/comctl32/tests/taskdialog.c
@@ -323,7 +323,7 @@ static void test_callback(void)
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 */
@@ -373,31 +373,40 @@ static void test_buttons(void)
info.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_CLOSE_BUTTON;
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, 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, 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, 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, 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, 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, 0, msg_return_press_custom4, "default button: valid default - 2");
+ /* 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, 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, 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, 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, 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, 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, msg_return_press_custom4, "default button: valid default - 2");
+ }
/* Test radio buttons */
info.nDefaultButton = 0;
--
2.17.1
June 17, 2018
[PATCH 2/3] comctl32/taskdialog: Add support for radio buttons.
by Zhiyi Zhang
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/comctl32/taskdialog.c | 130 ++++++++++++++++++++++-
dlls/comctl32/tests/taskdialog.c | 172 +++++++++++++++++++++++++++----
2 files changed, 281 insertions(+), 21 deletions(-)
diff --git a/dlls/comctl32/taskdialog.c b/dlls/comctl32/taskdialog.c
index 33fb578910..c3c5fa0420 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, unsigned long 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);
}
@@ -260,6 +285,40 @@ static void taskdialog_get_label_size(struct taskdialog_info *dialog_info, HWND
ReleaseDC(hwnd, hdc);
}
+static void taskdialog_get_checkbox_height(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};
+ WCHAR text[1024];
+ INT text_length;
+ LONG text_offset, checkbox_width, checkbox_height;
+
+ hdc = GetDC(hwnd);
+ hfont = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0);
+ old_hfont = SelectObject(hdc, hfont);
+
+ checkbox_width = 12 * GetDeviceCaps(hdc, LOGPIXELSX) / 96 + 1;
+ checkbox_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 - checkbox_width - text_offset;
+ text_length = GetWindowTextW(hwnd, text, ARRAY_SIZE(text));
+ size->cy = DrawTextW(hdc, text, text_length, &rect, style);
+ size->cx = min(max_width - checkbox_width - text_offset, rect.right - rect.left);
+ size->cx += checkbox_width + text_offset;
+ size->cy = max(size->cy, checkbox_height);
+ if (old_hfont) SelectObject(hdc, old_hfont);
+ ReleaseDC(hwnd, hdc);
+}
+
static ULONG_PTR taskdialog_get_standard_icon(LPCWSTR icon)
{
if (icon == TD_WARNING_ICON)
@@ -300,6 +359,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;
@@ -363,6 +444,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)
{
@@ -487,6 +592,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_checkbox_height(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 */
@@ -621,6 +737,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 */
@@ -638,6 +755,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)
@@ -689,6 +807,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;
@@ -697,6 +821,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)
@@ -762,7 +888,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
June 17, 2018
[PATCH 1/3] comctl32/taskdialog: Fix buttons might disappear.
by Zhiyi Zhang
In the old button layout algorithm, line count is added
before adding button. This cause line count buffer
overflow when the first button is very long.
This patch modify the algorithm to add button first before
adjusting line count.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/comctl32/taskdialog.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/dlls/comctl32/taskdialog.c b/dlls/comctl32/taskdialog.c
index 1a5fad1609..33fb578910 100644
--- a/dlls/comctl32/taskdialog.c
+++ b/dlls/comctl32/taskdialog.c
@@ -506,16 +506,15 @@ static void taskdialog_layout(struct taskdialog_info *dialog_info)
x = h_spacing;
for (i = 0, line_count = 0; i < dialog_info->button_count; i++)
{
- if (x + button_layout_infos[i].width + h_spacing >= dialog_width)
+ button_layout_infos[i].line = line_count;
+ x += button_layout_infos[i].width + h_spacing;
+ line_widths[line_count] += button_layout_infos[i].width + h_spacing;
+
+ if ((i + 1 < dialog_info->button_count) && (x + button_layout_infos[i + 1].width + h_spacing >= dialog_width))
{
x = h_spacing;
line_count++;
}
-
- button_layout_infos[i].line = line_count;
-
- x += button_layout_infos[i].width + h_spacing;
- line_widths[line_count] += button_layout_infos[i].width + h_spacing;
}
line_count++;
--
2.17.1
June 17, 2018
[PATCH 2/2] msvcp120: Add test for Concurrent_vector_swap.
by Hua Meng
Signed-off-by: Hua meng <161220092(a)smail.nju.edu.cn>
---
dlls/msvcp120/tests/msvcp120.c | 41 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/dlls/msvcp120/tests/msvcp120.c b/dlls/msvcp120/tests/msvcp120.c
index 895ab36..aec66fb 100644
--- a/dlls/msvcp120/tests/msvcp120.c
+++ b/dlls/msvcp120/tests/msvcp120.c
@@ -402,6 +402,8 @@ static void (__thiscall *p_vector_base_v4__Internal_copy)(
static void (__thiscall *p_vector_base_v4__Internal_assign)(
vector_base_v4*, vector_base_v4*, size_t, void (__cdecl*)(void*, size_t),
void (__cdecl*)(void*, const void*, size_t), void (__cdecl*)(void*, const void*, size_t));
+static void (__thiscall *p_vector_base_v4__Internal_swap)(
+ vector_base_v4*, const vector_base_v4*);
static HMODULE msvcp;
#define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcp,y)
@@ -548,6 +550,8 @@ static BOOL init(void)
"?_Internal_copy(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IEAAXAEBV123(a)_KP6AXPEAXPEBX1@Z(a)Z");
SET(p_vector_base_v4__Internal_assign,
"?_Internal_assign(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IEAAXAEBV123(a)_KP6AXPEAX1@ZP6AX2PEBX1(a)Z5@Z");
+ SET(p_vector_base_v4__Internal_swap,
+ "?_Internal_swap(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IEAAXAEAV123@@Z");
} else {
SET(p_tr2_sys__File_size,
"?_File_size(a)sys@tr2(a)std@@YA_KPBD(a)Z");
@@ -663,6 +667,8 @@ static BOOL init(void)
"?_Internal_copy(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAEXABV123(a)IP6AXPAXPBXI@Z(a)Z");
SET(p_vector_base_v4__Internal_assign,
"?_Internal_assign(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAEXABV123(a)IP6AXPAXI@ZP6AX1PBXI(a)Z4@Z");
+ SET(p_vector_base_v4__Internal_swap,
+ "?_Internal_swap(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAEXAAV123@@Z");
#else
SET(p__Thrd_current,
"_Thrd_current");
@@ -706,6 +712,8 @@ static BOOL init(void)
"?_Internal_copy(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAAXABV123(a)IP6AXPAXPBXI@Z(a)Z");
SET(p_vector_base_v4__Internal_assign,
"?_Internal_assign(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAAXABV123(a)IP6AXPAXI@ZP6AX1PBXI(a)Z4@Z");
+ SET(p_vector_base_v4__Internal_swap,
+ "?_Internal_swap(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAAXAAV123@@Z");
#endif
}
SET(p__Thrd_equal,
@@ -2851,6 +2859,39 @@ static void test_vector_base_v4(void)
CHECK_CALLED(concurrent_vector_int_destroy);
concurrent_vector_int_dtor(&v2);
+ concurrent_vector_int_ctor(&v2);
+ SET_EXPECT(concurrent_vector_int_alloc);
+ data = call_func3(p_vector_base_v4__Internal_push_back, &v2, sizeof(int), &idx);
+ ok(data != NULL, "_Internal_push_back returned NULL\n");
+ data = call_func3(p_vector_base_v4__Internal_push_back, &v2, sizeof(int), &idx);
+ ok(data != NULL, "_Internal_push_back returned NULL\n");
+ CHECK_CALLED(concurrent_vector_int_alloc);
+ SET_EXPECT(concurrent_vector_int_alloc);
+ data = call_func3(p_vector_base_v4__Internal_push_back, &v2, sizeof(int), &idx);
+ ok(data != NULL, "_Internal_push_back returned NULL\n");
+ CHECK_CALLED(concurrent_vector_int_alloc);
+ vector_elem_count += 3;
+ ok(idx == 2, "idx got %ld expected 2\n", (long)idx);
+ call_func2(p_vector_base_v4__Internal_swap,
+ &v2, &vector);
+ ok(v2.first_block == 1, "v2.first_block got %ld expected 1\n",
+ (long)v2.first_block);
+ ok(v2.early_size == 5, "v2.early_size got %ld expected 5\n",
+ (long)v2.early_size);
+ ok(vector.early_size == 3, "vector.early_size got %ld expected 3\n",
+ (long)vector.early_size);
+ call_func2(p_vector_base_v4__Internal_swap,
+ &v2, &vector);
+ ok(v2.early_size == 3, "v2.early_size got %ld expected 3\n",
+ (long)v2.early_size);
+ ok(vector.early_size == 5, "vector.early_size got %ld expected 5\n",
+ (long)vector.early_size);
+ SET_EXPECT(concurrent_vector_int_destroy);
+ size = (size_t)call_func2(p_vector_base_v4__Internal_clear,
+ &v2, concurrent_vector_int_destroy);
+ CHECK_CALLED(concurrent_vector_int_destroy);
+ concurrent_vector_int_dtor(&v2);
+
SET_EXPECT(concurrent_vector_int_destroy);
size = (size_t)call_func2(p_vector_base_v4__Internal_clear,
&vector, concurrent_vector_int_destroy);
--
2.11.0
June 17, 2018
[PATCH 1/2] msvcp120: Add test for Concurrent_vector_assign.
by Hua Meng
Signed-off-by: Hua meng <161220092(a)smail.nju.edu.cn>
---
dlls/msvcp120/tests/msvcp120.c | 56 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/dlls/msvcp120/tests/msvcp120.c b/dlls/msvcp120/tests/msvcp120.c
index c34bd65..895ab36 100644
--- a/dlls/msvcp120/tests/msvcp120.c
+++ b/dlls/msvcp120/tests/msvcp120.c
@@ -40,6 +40,7 @@ struct expect_struct {
DEFINE_EXPECT(concurrent_vector_int_alloc);
DEFINE_EXPECT(concurrent_vector_int_destroy);
DEFINE_EXPECT(concurrent_vector_int_copy);
+ DEFINE_EXPECT(concurrent_vector_int_assign);
};
#define SET_EXPECT(func) \
@@ -114,6 +115,8 @@ static void * (WINAPI *call_thiscall_func3)( void *func, void *this, const void
const void *b );
static void * (WINAPI *call_thiscall_func4)( void *func, void *this, const void *a,
const void *b, const void *c );
+static void * (WINAPI *call_thiscall_func6)( void *func, void *this, const void *a,
+ const void *b, const void *c, const void *d, const void *e );
static void init_thiscall_thunk(void)
{
@@ -128,6 +131,7 @@ static void init_thiscall_thunk(void)
call_thiscall_func2 = (void *)thunk;
call_thiscall_func3 = (void *)thunk;
call_thiscall_func4 = (void *)thunk;
+ call_thiscall_func6 = (void *)thunk;
}
#define call_func1(func,_this) call_thiscall_func1(func,_this)
@@ -136,6 +140,8 @@ static void init_thiscall_thunk(void)
(const void*)(b))
#define call_func4(func,_this,a,b,c) call_thiscall_func4(func,_this,(const void*)(a),\
(const void*)(b),(const void*)(c))
+#define call_func6(func,_this,a,b,c,d,e) call_thiscall_func6(func,_this,(const void*)(a),\
+ (const void*)(b),(const void*)(c),(const void*)(d),(const void*)(e))
#else
#define init_thiscall_thunk()
@@ -143,6 +149,7 @@ static void init_thiscall_thunk(void)
#define call_func2(func,_this,a) func(_this,a)
#define call_func3(func,_this,a,b) func(_this,a,b)
#define call_func4(func,_this,a,b,c) func(_this,a,b,c)
+#define call_func6(func,_this,a,b,c,d,e) func(_this,a,b,c,d,e)
#endif /* __i386__ */
static inline float __port_infinity(void)
@@ -392,6 +399,9 @@ static size_t (__thiscall *p_vector_base_v4__Internal_clear)(
vector_base_v4*, void (__cdecl*)(void*, size_t));
static void (__thiscall *p_vector_base_v4__Internal_copy)(
vector_base_v4*, vector_base_v4*, size_t, void (__cdecl*)(void*, const void*, size_t));
+static void (__thiscall *p_vector_base_v4__Internal_assign)(
+ vector_base_v4*, vector_base_v4*, size_t, void (__cdecl*)(void*, size_t),
+ void (__cdecl*)(void*, const void*, size_t), void (__cdecl*)(void*, const void*, size_t));
static HMODULE msvcp;
#define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcp,y)
@@ -536,6 +546,8 @@ static BOOL init(void)
"?_Internal_clear(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IEAA_KP6AXPEAX_K(a)Z@Z");
SET(p_vector_base_v4__Internal_copy,
"?_Internal_copy(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IEAAXAEBV123(a)_KP6AXPEAXPEBX1@Z(a)Z");
+ SET(p_vector_base_v4__Internal_assign,
+ "?_Internal_assign(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IEAAXAEBV123(a)_KP6AXPEAX1@ZP6AX2PEBX1(a)Z5@Z");
} else {
SET(p_tr2_sys__File_size,
"?_File_size(a)sys@tr2(a)std@@YA_KPBD(a)Z");
@@ -649,6 +661,8 @@ static BOOL init(void)
"?_Internal_clear(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAEIP6AXPAXI(a)Z@Z");
SET(p_vector_base_v4__Internal_copy,
"?_Internal_copy(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAEXABV123(a)IP6AXPAXPBXI@Z(a)Z");
+ SET(p_vector_base_v4__Internal_assign,
+ "?_Internal_assign(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAEXABV123(a)IP6AXPAXI@ZP6AX1PBXI(a)Z4@Z");
#else
SET(p__Thrd_current,
"_Thrd_current");
@@ -690,6 +704,8 @@ static BOOL init(void)
"?_Internal_clear(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAAIP6AXPAXI(a)Z@Z");
SET(p_vector_base_v4__Internal_copy,
"?_Internal_copy(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAAXABV123(a)IP6AXPAXPBXI@Z(a)Z");
+ SET(p_vector_base_v4__Internal_assign,
+ "?_Internal_assign(a)_Concurrent_vector_base_v4@details(a)Concurrency@@IAAXABV123(a)IP6AXPAXI@ZP6AX1PBXI(a)Z4@Z");
#endif
}
SET(p__Thrd_equal,
@@ -2509,6 +2525,12 @@ static void __cdecl concurrent_vector_int_copy(void *dst, const void *src, size_
memcpy(dst, src, n*sizeof(int));
}
+static void __cdecl concurrent_vector_int_assign(void *dst, const void *src, size_t n)
+{
+ CHECK_EXPECT2(concurrent_vector_int_assign);
+ memcpy(dst, src, n*sizeof(int));
+}
+
static void test_queue_base_v4(void)
{
queue_base_v4 queue;
@@ -2793,6 +2815,40 @@ static void test_vector_base_v4(void)
SET_EXPECT(concurrent_vector_int_destroy);
size = (size_t)call_func2(p_vector_base_v4__Internal_clear,
&v2, concurrent_vector_int_destroy);
+ CHECK_CALLED(concurrent_vector_int_destroy);
+ concurrent_vector_int_dtor(&v2);
+
+ concurrent_vector_int_ctor(&v2);
+ SET_EXPECT(concurrent_vector_int_alloc);
+ data = call_func3(p_vector_base_v4__Internal_push_back, &v2, sizeof(int), &idx);
+ CHECK_CALLED(concurrent_vector_int_alloc);
+ ok(data != NULL, "_Internal_push_back returned NULL\n");
+ data = call_func3(p_vector_base_v4__Internal_push_back, &v2, sizeof(int), &idx);
+ ok(data != NULL, "_Internal_push_back returned NULL\n");
+ SET_EXPECT(concurrent_vector_int_alloc);
+ data = call_func3(p_vector_base_v4__Internal_push_back, &v2, sizeof(int), &idx);
+ ok(data != NULL, "_Internal_push_back returned NULL\n");
+ CHECK_CALLED(concurrent_vector_int_alloc);
+ vector_elem_count += 3;
+ ok(idx == 2, "idx got %ld expected 2\n", (long)idx);
+ SET_EXPECT(concurrent_vector_int_assign);
+ SET_EXPECT(concurrent_vector_int_copy);
+ SET_EXPECT(concurrent_vector_int_alloc);
+ call_func6(p_vector_base_v4__Internal_assign, &v2, &vector, sizeof(int),
+ concurrent_vector_int_destroy, concurrent_vector_int_assign,
+ concurrent_vector_int_copy);
+ CHECK_CALLED(concurrent_vector_int_assign);
+ CHECK_CALLED(concurrent_vector_int_copy);
+ CHECK_CALLED(concurrent_vector_int_alloc);
+ ok(v2.first_block == 1, "v2.first_block got %ld expected 1\n",
+ (long)v2.first_block);
+ ok(v2.early_size == 5, "v2.early_size got %ld expected 5\n",
+ (long)v2.early_size);
+
+ SET_EXPECT(concurrent_vector_int_destroy);
+ size = (size_t)call_func2(p_vector_base_v4__Internal_clear,
+ &v2, concurrent_vector_int_destroy);
+ CHECK_CALLED(concurrent_vector_int_destroy);
concurrent_vector_int_dtor(&v2);
SET_EXPECT(concurrent_vector_int_destroy);
--
2.11.0
June 17, 2018
[PATCH v3] vbscript: Treat \r as a newline separator.
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
Sorry about the delay; seems this one got lost somehow.
dlls/vbscript/lex.c | 6 ++++--
dlls/vbscript/tests/run.c | 12 ++++++++++++
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c
index 98b4cbb..b0fac48 100644
--- a/dlls/vbscript/lex.c
+++ b/dlls/vbscript/lex.c
@@ -383,13 +383,14 @@ static int parse_hex_literal(parser_ctx_t *ctx, LONG *ret)
static void skip_spaces(parser_ctx_t *ctx)
{
- while(*ctx->ptr == ' ' || *ctx->ptr == '\t' || *ctx->ptr == '\r')
+ while(*ctx->ptr == ' ' || *ctx->ptr == '\t')
ctx->ptr++;
}
static int comment_line(parser_ctx_t *ctx)
{
- ctx->ptr = strchrW(ctx->ptr, '\n');
+ static const WCHAR newlineW[] = {'\n','\r',0};
+ ctx->ptr = strpbrkW(ctx->ptr, newlineW);
if(ctx->ptr)
ctx->ptr++;
else
@@ -421,6 +422,7 @@ static int parse_next_token(void *lval, parser_ctx_t *ctx)
switch(c) {
case '\n':
+ case '\r':
ctx->ptr++;
return tNL;
case '\'':
diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c
index 6b57540..191f5a7 100644
--- a/dlls/vbscript/tests/run.c
+++ b/dlls/vbscript/tests/run.c
@@ -2394,6 +2394,18 @@ static void run_tests(void)
ok(FAILED(hres), "script didn't fail\n");
todo_wine CHECK_CALLED(OnScriptError);
+ SET_EXPECT(global_success_d);
+ SET_EXPECT(global_success_i);
+ parse_script_a("' comment\r"
+ "Sub testsub(arg)\r"
+ "If arg = 1 Then\r\r"
+ "Call reportSuccess()\n\n"
+ "End If\r\n"
+ "End Sub\n\r"
+ "Call testsub(1)");
+ CHECK_CALLED(global_success_d);
+ CHECK_CALLED(global_success_i);
+
run_from_res("lang.vbs");
run_from_res("api.vbs");
run_from_res("regexp.vbs");
--
2.7.4
June 17, 2018
[PATCH 2/2] hnetcfg: Store the UNC path in INetFwAuthorizedApplication_put_ProcessImageFileName().
by Zebediah Figura
Fixes test failures when running from virtual drive.
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/hnetcfg/apps.c | 31 ++++++++++++++++++++++++++-----
dlls/hnetcfg/tests/Makefile.in | 2 +-
dlls/hnetcfg/tests/policy.c | 15 ++++++++++++++-
3 files changed, 41 insertions(+), 7 deletions(-)
diff --git a/dlls/hnetcfg/apps.c b/dlls/hnetcfg/apps.c
index fda714e..e3b6b36 100644
--- a/dlls/hnetcfg/apps.c
+++ b/dlls/hnetcfg/apps.c
@@ -263,18 +263,39 @@ static HRESULT WINAPI fw_app_get_ProcessImageFileName(
}
static HRESULT WINAPI fw_app_put_ProcessImageFileName(
- INetFwAuthorizedApplication *iface,
- BSTR imageFileName )
+ INetFwAuthorizedApplication *iface, BSTR image )
{
fw_app *This = impl_from_INetFwAuthorizedApplication( iface );
+ UNIVERSAL_NAME_INFOW *info;
+ WCHAR *netpath;
+ DWORD res;
+ DWORD sz;
- FIXME("%p, %s\n", This, debugstr_w(imageFileName));
+ FIXME("%p, %s\n", This, debugstr_w(image));
- if (!imageFileName || !imageFileName[0])
+ if (!image || !image[0])
return E_INVALIDARG;
+ sz = 0;
+ res = WNetGetUniversalNameW(image, UNIVERSAL_NAME_INFO_LEVEL, NULL, &sz);
+ if (res == WN_MORE_DATA)
+ {
+ if (!(netpath = heap_alloc(sz)))
+ return E_OUTOFMEMORY;
+
+ info = (UNIVERSAL_NAME_INFOW *)&netpath;
+ res = WNetGetUniversalNameW(image, UNIVERSAL_NAME_INFO_LEVEL, &info, &sz);
+ if (res == NO_ERROR)
+ {
+ SysFreeString(This->filename);
+ This->filename = SysAllocString(info->lpUniversalName);
+ }
+ heap_free(netpath);
+ return HRESULT_FROM_WIN32(res);
+ }
+
SysFreeString( This->filename );
- This->filename = SysAllocString( imageFileName );
+ This->filename = SysAllocString(image);
return This->filename ? S_OK : E_OUTOFMEMORY;
}
diff --git a/dlls/hnetcfg/tests/Makefile.in b/dlls/hnetcfg/tests/Makefile.in
index 8315b4b..922370a 100644
--- a/dlls/hnetcfg/tests/Makefile.in
+++ b/dlls/hnetcfg/tests/Makefile.in
@@ -1,5 +1,5 @@
TESTDLL = hnetcfg.dll
-IMPORTS = ole32 uuid oleaut32 advapi32
+IMPORTS = ole32 uuid oleaut32 advapi32 mpr
C_SRCS = \
policy.c
diff --git a/dlls/hnetcfg/tests/policy.c b/dlls/hnetcfg/tests/policy.c
index 012bbcd..f2d1372 100644
--- a/dlls/hnetcfg/tests/policy.c
+++ b/dlls/hnetcfg/tests/policy.c
@@ -106,9 +106,12 @@ static void test_NetFwAuthorizedApplication(void)
{
INetFwAuthorizedApplication *app;
static WCHAR empty[] = {0};
+ UNIVERSAL_NAME_INFOW *info;
+ WCHAR netpath[MAX_PATH];
WCHAR image[MAX_PATH];
HRESULT hr;
BSTR bstr;
+ DWORD sz;
hr = CoCreateInstance(&CLSID_NetFwAuthorizedApplication, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
&IID_INetFwAuthorizedApplication, (void**)&app);
@@ -135,9 +138,19 @@ static void test_NetFwAuthorizedApplication(void)
ok(hr == S_OK, "got: %08x\n", hr);
SysFreeString(bstr);
+ info = (UNIVERSAL_NAME_INFOW *)&netpath;
+ sz = sizeof(netpath);
+ hr = WNetGetUniversalNameW(image, UNIVERSAL_NAME_INFO_LEVEL, &info, &sz);
+ if (hr != NO_ERROR)
+ {
+ info->lpUniversalName = netpath + sizeof(*info)/sizeof(WCHAR);
+ lstrcpyW(info->lpUniversalName, image);
+ }
+
hr = INetFwAuthorizedApplication_get_ProcessImageFileName(app, &bstr);
ok(hr == S_OK, "got: %08x\n", hr);
- ok(!lstrcmpiW(bstr,image), "got: %s\n", wine_dbgstr_w(bstr));
+ ok(!lstrcmpW(bstr,info->lpUniversalName), "expected %s, got %s\n",
+ wine_dbgstr_w(info->lpUniversalName), wine_dbgstr_w(bstr));
SysFreeString(bstr);
INetFwAuthorizedApplication_Release(app);
--
2.7.4
June 16, 2018
[PATCH 1/2] hnetcfg/tests: Fix BSTR usage in test_NetFwAuthorizedApplication().
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/hnetcfg/tests/policy.c | 52 ++++++++++++++++++++-------------------------
1 file changed, 23 insertions(+), 29 deletions(-)
diff --git a/dlls/hnetcfg/tests/policy.c b/dlls/hnetcfg/tests/policy.c
index 4ee19d8..012bbcd 100644
--- a/dlls/hnetcfg/tests/policy.c
+++ b/dlls/hnetcfg/tests/policy.c
@@ -105,48 +105,42 @@ static void test_interfaces(void)
static void test_NetFwAuthorizedApplication(void)
{
INetFwAuthorizedApplication *app;
+ static WCHAR empty[] = {0};
+ WCHAR image[MAX_PATH];
HRESULT hr;
+ BSTR bstr;
hr = CoCreateInstance(&CLSID_NetFwAuthorizedApplication, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
&IID_INetFwAuthorizedApplication, (void**)&app);
ok(hr == S_OK, "got: %08x\n", hr);
- if(hr == S_OK)
- {
- BSTR image = SysAllocStringLen( NULL, MAX_PATH );
- static WCHAR empty[] = {0};
- BSTR bstr;
- if (!GetModuleFileNameW( NULL, image, MAX_PATH ))
- {
- ok(0, "Failed to get filename\n");
- SysFreeString( image );
- return;
- }
+ hr = GetModuleFileNameW(NULL, image, sizeof(image));
+ ok(hr, "GetModuleFileName failed: %u\n", GetLastError());
- hr = INetFwAuthorizedApplication_get_ProcessImageFileName(app, NULL);
- ok(hr == E_POINTER, "got: %08x\n", hr);
+ hr = INetFwAuthorizedApplication_get_ProcessImageFileName(app, NULL);
+ ok(hr == E_POINTER, "got: %08x\n", hr);
- hr = INetFwAuthorizedApplication_get_ProcessImageFileName(app, &bstr);
- ok(hr == S_OK || hr == HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY), "got: %08x\n", hr);
- ok(!bstr, "got: %s\n", wine_dbgstr_w(bstr));
+ hr = INetFwAuthorizedApplication_get_ProcessImageFileName(app, &bstr);
+ ok(hr == S_OK || hr == HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY), "got: %08x\n", hr);
+ ok(!bstr, "got: %s\n", wine_dbgstr_w(bstr));
- hr = INetFwAuthorizedApplication_put_ProcessImageFileName(app, NULL);
- ok(hr == E_INVALIDARG || hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "got: %08x\n", hr);
+ hr = INetFwAuthorizedApplication_put_ProcessImageFileName(app, NULL);
+ ok(hr == E_INVALIDARG || hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "got: %08x\n", hr);
- hr = INetFwAuthorizedApplication_put_ProcessImageFileName(app, empty);
- ok(hr == E_INVALIDARG || hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "got: %08x\n", hr);
+ hr = INetFwAuthorizedApplication_put_ProcessImageFileName(app, empty);
+ ok(hr == E_INVALIDARG || hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "got: %08x\n", hr);
- hr = INetFwAuthorizedApplication_put_ProcessImageFileName(app, image);
- ok(hr == S_OK, "got: %08x\n", hr);
+ bstr = SysAllocString(image);
+ hr = INetFwAuthorizedApplication_put_ProcessImageFileName(app, bstr);
+ ok(hr == S_OK, "got: %08x\n", hr);
+ SysFreeString(bstr);
- hr = INetFwAuthorizedApplication_get_ProcessImageFileName(app, &bstr);
- ok(hr == S_OK, "got: %08x\n", hr);
- ok(!lstrcmpiW(bstr,image), "got: %s\n", wine_dbgstr_w(bstr));
- SysFreeString( bstr );
+ hr = INetFwAuthorizedApplication_get_ProcessImageFileName(app, &bstr);
+ ok(hr == S_OK, "got: %08x\n", hr);
+ ok(!lstrcmpiW(bstr,image), "got: %s\n", wine_dbgstr_w(bstr));
+ SysFreeString(bstr);
- SysFreeString( image );
- INetFwAuthorizedApplication_Release(app);
- }
+ INetFwAuthorizedApplication_Release(app);
}
START_TEST(policy)
--
2.7.4
June 16, 2018