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
[PATCH v2 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 17, 2018
[PATCH] ntdll: Add stub for WinSqmSetDWORD
by Fabian Maurer
This is an undocumented win7 function appearently used to telemetry.
It's used by some native win7 dlls.
Signed-off-by: Fabian Maurer <dark.shadow4(a)web.de>
---
dlls/ntdll/misc.c | 10 ++++++++++
dlls/ntdll/ntdll.spec | 1 +
2 files changed, 11 insertions(+)
diff --git a/dlls/ntdll/misc.c b/dlls/ntdll/misc.c
index 88e8b33324..85000ab225 100644
--- a/dlls/ntdll/misc.c
+++ b/dlls/ntdll/misc.c
@@ -484,3 +484,13 @@ void WINAPI DbgUiRemoteBreakin( void *arg )
{
FIXME("stub\n");
}
+
+/***********************************************************************
+ * WinSqmSetDWORD (NTDLL.@)
+ *
+ * SQM seems to be used for telemetry
+ */
+void WINAPI WinSqmSetDWORD(HANDLE session, DWORD datapoint_id, DWORD datapoint_value)
+{
+ FIXME("(%p, %d, %d): stub\n", session, datapoint_id, datapoint_value);
+}
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index fb505e2208..1c366649e0 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -1032,6 +1032,7 @@
@ stdcall -ret64 VerSetConditionMask(int64 long long)
@ stdcall WinSqmEndSession(long)
@ stdcall WinSqmIsOptedIn()
+@ stdcall WinSqmSetDWORD(ptr long long)
@ stdcall WinSqmStartSession(ptr long long)
@ stdcall -private ZwAcceptConnectPort(ptr long ptr long ptr ptr) NtAcceptConnectPort
@ stdcall -private ZwAccessCheck(ptr long long ptr ptr ptr ptr ptr) NtAccessCheck
--
2.17.1
June 17, 2018
[PATCH] ntdll: Add stub for RtlExpandEnvironmentStrings
by Fabian Maurer
This function is used by some native win7 dlls
Signed-off-by: Fabian Maurer <dark.shadow4(a)web.de>
---
dlls/ntdll/env.c | 8 ++++++++
dlls/ntdll/ntdll.spec | 1 +
2 files changed, 9 insertions(+)
diff --git a/dlls/ntdll/env.c b/dlls/ntdll/env.c
index a5bdf0f050..328ba79aaa 100644
--- a/dlls/ntdll/env.c
+++ b/dlls/ntdll/env.c
@@ -362,6 +362,14 @@ NTSTATUS WINAPI RtlExpandEnvironmentStrings_U(PCWSTR renv, const UNICODE_STRING*
return (count) ? STATUS_SUCCESS : STATUS_BUFFER_TOO_SMALL;
}
+/******************************************************************************
+ * RtlExpandEnvironmentStrings [NTDLL.@]
+ */
+NTSTATUS WINAPI RtlExpandEnvironmentStrings(PVOID environment, PWSTR src, SIZE_T src_length, PWSTR dst, SIZE_T dst_length, PSIZE_T return_length)
+{
+ FIXME("(%p, %p, %lu, %p, %lu, %p): stub\n", environment, src, src_length, dst, dst_length, return_length);
+ return STATUS_NOT_IMPLEMENTED;
+}
static inline void normalize( void *base, WCHAR **ptr )
{
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 45cedb74f5..fb505e2208 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -596,6 +596,7 @@
@ stdcall RtlEraseUnicodeString(ptr)
@ stdcall RtlExitUserProcess(long)
@ stdcall RtlExitUserThread(long)
+@ stdcall RtlExpandEnvironmentStrings(ptr ptr long ptr long ptr)
@ stdcall RtlExpandEnvironmentStrings_U(ptr ptr ptr ptr)
@ stub RtlExtendHeap
@ stdcall -arch=win32 -ret64 RtlExtendedIntegerMultiply(int64 long)
--
2.17.1
June 17, 2018
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
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
Re: [PATCH v5 3/8] kernel32/tests: Add GetSystemFirmwareTable tests
by Alex Henrie
On Fri, Jun 15, 2018 at 2:37 AM Huw Davies <huw(a)codeweavers.com> wrote:
>
> On Fri, Jun 15, 2018 at 12:59:09AM -0600, Alex Henrie wrote:
> > + sfti->ProviderSignature = RSMB;
> > + sfti->Action = SystemFirmwareTable_Get;
>
> You need to initialize TableID.
When querying the RSMB table, TableID is ignored. You get the same
results no matter what the table ID is. I'm adding a test that
demonstrates this.
I did, however, notice that some of the RSMB table values change over
time. So, I'm going to omit the test for NtQuerySystemInformation and
GetSystemFirmwareTable returning exactly the same data, and instead
just check that they both return the same amount of data.
If you'd like to look over my latest work before Monday, you can see
it at https://github.com/alexhenrie/wine/commits/master
Thanks for the help!
-Alex
June 16, 2018
[PATCH] comctl32/imagelist: fix ImageList_Read/Write.
by Denis Malikov
From: Denis Malikov <mdn40000(a)mail.ru>
Date: Sat, 16 Jun 2018 16:35:45 +0700
Subject: [PATCH] comctl32/imagelist: fix ImageList_Read/Write.
Fix for versions x600 and x620 and pointer calculation for mixing image and mask bits.
Tested on ReactOS 0.4.10 with *.reg files extracted from:
- XP/2003 key HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\TrayNotify;
- Vista/7 key HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify
Signed-off-by: Denis Malikov <mdn40000(a)mail.ru>
---
dlls/comctl32/imagelist.c | 59 +++++++++++++++++++++++++++--------------------
1 file changed, 34 insertions(+), 25 deletions(-)
diff --git a/dlls/comctl32/imagelist.c b/dlls/comctl32/imagelist.c
index a08d60752e..052d59f9e4 100644
--- a/dlls/comctl32/imagelist.c
+++ b/dlls/comctl32/imagelist.c
@@ -59,7 +59,7 @@ struct _IMAGELIST
INT cGrow; /* 0C: cGrow */
INT cx; /* 10: cx */
INT cy; /* 14: cy */
- DWORD x4;
+ DWORD x4; /* hack for IL from stream. Keep version here */
UINT flags; /* 1C: flags */
COLORREF clrFg; /* 20: foreground color */
COLORREF clrBk; /* 24: background color */
@@ -83,6 +83,7 @@ struct _IMAGELIST
};
#define IMAGELIST_MAGIC 0x53414D58
+#define IMAGELIST_VERSION 0x101
/* Header used by ImageList_Read() and ImageList_Write() */
#include "pshpack2.h"
@@ -806,6 +807,7 @@ ImageList_Create (INT cx, INT cy, UINT flags,
himl->clrFg = CLR_DEFAULT;
himl->clrBk = CLR_NONE;
himl->color_table_set = FALSE;
+ himl->x4 = 0;
/* initialize overlay mask indices */
for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
@@ -2257,38 +2259,43 @@ HIMAGELIST WINAPI ImageList_Read(IStream *pstm)
BITMAPINFO *image_info = (BITMAPINFO *)image_buf;
BITMAPINFO *mask_info = (BITMAPINFO *)mask_buf;
void *image_bits, *mask_bits = NULL;
- ILHEAD ilHead;
- HIMAGELIST himl;
+ ILHEAD ilHead;
+ HIMAGELIST himl;
unsigned int i;
TRACE("%p\n", pstm);
if (FAILED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
- return NULL;
+ return NULL;
if (ilHead.usMagic != (('L' << 8) | 'I'))
- return NULL;
- if (ilHead.usVersion != 0x101) /* probably version? */
- return NULL;
+ return NULL;
+ if (ilHead.usVersion != IMAGELIST_VERSION &&
+ ilHead.usVersion != 0x600 && /* XP/2003 version */
+ ilHead.usVersion != 0x620) /* Vista/7 version */
+ return NULL;
TRACE("cx %u, cy %u, flags 0x%04x, cCurImage %u, cMaxImage %u\n",
ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
himl = ImageList_Create(ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
if (!himl)
- return NULL;
+ return NULL;
+
+ // keep version from stream
+ himl->x4 = ilHead.usVersion;
if (!(image_bits = read_bitmap(pstm, image_info)))
{
- WARN("failed to read bitmap from stream\n");
- return NULL;
+ WARN("failed to read bitmap from stream\n");
+ return NULL;
}
if (ilHead.flags & ILC_MASK)
{
if (!(mask_bits = read_bitmap(pstm, mask_info)))
{
WARN("failed to read mask bitmap from stream\n");
- return NULL;
- }
+ return NULL;
+ }
}
else mask_info = NULL;
@@ -2296,23 +2303,25 @@ HIMAGELIST WINAPI ImageList_Read(IStream *pstm)
{
DWORD *ptr = image_bits;
BYTE *mask_ptr = mask_bits;
- int stride = himl->cy * image_info->bmiHeader.biWidth;
+ int stride = himl->cy * (ilHead.usVersion != IMAGELIST_VERSION ? himl->cx : image_info->bmiHeader.biWidth);
+ int image_step = ilHead.usVersion != IMAGELIST_VERSION ? 1 : TILE_COUNT;
+ int mask_step = ilHead.usVersion != IMAGELIST_VERSION ? 4 : 8;
if (image_info->bmiHeader.biHeight > 0) /* bottom-up */
{
ptr += image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride;
- mask_ptr += (image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride) / 8;
+ mask_ptr += (image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride) / mask_step;
stride = -stride;
image_info->bmiHeader.biHeight = himl->cy;
}
else image_info->bmiHeader.biHeight = -himl->cy;
- for (i = 0; i < ilHead.cCurImage; i += TILE_COUNT)
+ for (i = 0; i < ilHead.cCurImage; i += image_step)
{
- add_dib_bits( himl, i, min( ilHead.cCurImage - i, TILE_COUNT ),
+ add_dib_bits( himl, i, min( ilHead.cCurImage - i, image_step ),
himl->cx, himl->cy, image_info, mask_info, ptr, mask_ptr );
ptr += stride;
- mask_ptr += stride / 8;
+ mask_ptr += stride / mask_step;
}
}
else
@@ -2333,7 +2342,7 @@ HIMAGELIST WINAPI ImageList_Read(IStream *pstm)
ImageList_SetBkColor(himl,ilHead.bkcolor);
for (i=0;i<4;i++)
- ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
+ ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
return himl;
}
@@ -3078,10 +3087,10 @@ BOOL WINAPI ImageList_Write(HIMAGELIST himl, IStream *pstm)
TRACE("%p %p\n", himl, pstm);
if (!is_valid(himl))
- return FALSE;
+ return FALSE;
ilHead.usMagic = (('L' << 8) | 'I');
- ilHead.usVersion = 0x101;
+ ilHead.usVersion = himl->x4 > 0 ? himl->x4 : IMAGELIST_VERSION;
ilHead.cCurImage = himl->cCurImage;
ilHead.cMaxImage = himl->cMaxImage;
ilHead.cGrow = himl->cGrow;
@@ -3090,23 +3099,23 @@ BOOL WINAPI ImageList_Write(HIMAGELIST himl, IStream *pstm)
ilHead.bkcolor = himl->clrBk;
ilHead.flags = himl->flags;
for(i = 0; i < 4; i++) {
- ilHead.ovls[i] = himl->nOvlIdx[i];
+ ilHead.ovls[i] = himl->nOvlIdx[i];
}
TRACE("cx %u, cy %u, flags 0x04%x, cCurImage %u, cMaxImage %u\n",
ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
if(FAILED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
- return FALSE;
+ return FALSE;
/* write the bitmap */
if(!_write_bitmap(himl->hbmImage, pstm))
- return FALSE;
+ return FALSE;
/* write the mask if we have one */
if(himl->flags & ILC_MASK) {
- if(!_write_bitmap(himl->hbmMask, pstm))
- return FALSE;
+ if(!_write_bitmap(himl->hbmMask, pstm))
+ return FALSE;
}
return TRUE;
--
2.16.2.windows.1
June 16, 2018
Re: [PATCH] gdiplus: Check return value of SelectClipPath in brush_fill_path().
by Zhiyi Zhang
Thanks. I'll work on it as you suggest.
On Sat 6 16 23:26, Vincent Povirk wrote:
> If converting a path to a region fails for an open path, then our code
> in get_path_hrgn is also wrong. From reading gdi32 code, think it will
> work as long as there are points in the path, but the only way to be
> sure is to add a test.
>
> If we check for failure in SelectClipPath, I agree that we should not
> continue the operation for any error. I think we should report failure
> to the caller if it's an error we don't expect. That would also help
> explain why it's correct to silently ignore the failure.
>
> On Sat, Jun 16, 2018 at 9:31 AM, Zhiyi Zhang <zzhang(a)codeweavers.com> wrote:
>> Hi Vincent,
>>
>> Yes, we could check if a path is empty just like get_path_hrgn did.
>> I also worried that a not empty but open path will also make SelectClipPath()
>> fail. Is there any function to check if a path is closed? I couldn't found any.
>> As for SelectClipPath() last error, I don't think any further operation should
>> be continued if any error occurs.
>> So we add a check for empty path and also skip further operation if SelectClipPath()
>> returns any error. Is that enough?
>>
>> Thanks,
>> Zhiyi
>>
>> On Fri 6 15 23:55, Vincent Povirk wrote:
>>> It looks like we also encountered this case in get_path_hrgn. Maybe we
>>> shouldn't call brush_fill_pixels if the path is empty? If we're going
>>> to ignore errors, I think we should at least check GetLastError() to
>>> make sure it's one we expect.
>>>
>>> On Fri, Jun 15, 2018 at 4:04 AM, Zhiyi Zhang <zzhang(a)codeweavers.com> wrote:
>>>> For Crossover bug 16126.
>>>>
>>>> When GraphicPath is empty, filling path with gdi32 will
>>>> result in a DC with empty path. When SelectClipPath() is
>>>> called with such a DC, it will fail because it requires
>>>> a closed path in DC. Thus further operation should be canceled.
>>>>
>>>> Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
>>>> ---
>>>> dlls/gdiplus/graphics.c | 5 +++--
>>>> 1 file changed, 3 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
>>>> index 76aabe74bf..2a95d686fa 100644
>>>> --- a/dlls/gdiplus/graphics.c
>>>> +++ b/dlls/gdiplus/graphics.c
>>>> @@ -1052,6 +1052,7 @@ static BOOL brush_can_fill_path(GpBrush *brush, BOOL is_fill)
>>>>
>>>> static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
>>>> {
>>>> + BOOL success;
>>>> switch (brush->bt)
>>>> {
>>>> case BrushTypeSolidColor:
>>>> @@ -1064,8 +1065,8 @@ static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
>>>> RECT rc;
>>>> /* partially transparent fill */
>>>>
>>>> - SelectClipPath(graphics->hdc, RGN_AND);
>>>> - if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
>>>> + success = SelectClipPath(graphics->hdc, RGN_AND);
>>>> + if (success && GetClipBox(graphics->hdc, &rc) != NULLREGION)
>>>> {
>>>> HDC hdc = CreateCompatibleDC(NULL);
>>>>
>>>> --
>>>> 2.17.1
>>>>
>>>>
>>>>
>
>
June 16, 2018
Re: [PATCH] gdiplus: Check return value of SelectClipPath in brush_fill_path().
by Vincent Povirk
If converting a path to a region fails for an open path, then our code
in get_path_hrgn is also wrong. From reading gdi32 code, think it will
work as long as there are points in the path, but the only way to be
sure is to add a test.
If we check for failure in SelectClipPath, I agree that we should not
continue the operation for any error. I think we should report failure
to the caller if it's an error we don't expect. That would also help
explain why it's correct to silently ignore the failure.
On Sat, Jun 16, 2018 at 9:31 AM, Zhiyi Zhang <zzhang(a)codeweavers.com> wrote:
> Hi Vincent,
>
> Yes, we could check if a path is empty just like get_path_hrgn did.
> I also worried that a not empty but open path will also make SelectClipPath()
> fail. Is there any function to check if a path is closed? I couldn't found any.
> As for SelectClipPath() last error, I don't think any further operation should
> be continued if any error occurs.
> So we add a check for empty path and also skip further operation if SelectClipPath()
> returns any error. Is that enough?
>
> Thanks,
> Zhiyi
>
> On Fri 6 15 23:55, Vincent Povirk wrote:
>> It looks like we also encountered this case in get_path_hrgn. Maybe we
>> shouldn't call brush_fill_pixels if the path is empty? If we're going
>> to ignore errors, I think we should at least check GetLastError() to
>> make sure it's one we expect.
>>
>> On Fri, Jun 15, 2018 at 4:04 AM, Zhiyi Zhang <zzhang(a)codeweavers.com> wrote:
>>> For Crossover bug 16126.
>>>
>>> When GraphicPath is empty, filling path with gdi32 will
>>> result in a DC with empty path. When SelectClipPath() is
>>> called with such a DC, it will fail because it requires
>>> a closed path in DC. Thus further operation should be canceled.
>>>
>>> Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
>>> ---
>>> dlls/gdiplus/graphics.c | 5 +++--
>>> 1 file changed, 3 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
>>> index 76aabe74bf..2a95d686fa 100644
>>> --- a/dlls/gdiplus/graphics.c
>>> +++ b/dlls/gdiplus/graphics.c
>>> @@ -1052,6 +1052,7 @@ static BOOL brush_can_fill_path(GpBrush *brush, BOOL is_fill)
>>>
>>> static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
>>> {
>>> + BOOL success;
>>> switch (brush->bt)
>>> {
>>> case BrushTypeSolidColor:
>>> @@ -1064,8 +1065,8 @@ static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
>>> RECT rc;
>>> /* partially transparent fill */
>>>
>>> - SelectClipPath(graphics->hdc, RGN_AND);
>>> - if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
>>> + success = SelectClipPath(graphics->hdc, RGN_AND);
>>> + if (success && GetClipBox(graphics->hdc, &rc) != NULLREGION)
>>> {
>>> HDC hdc = CreateCompatibleDC(NULL);
>>>
>>> --
>>> 2.17.1
>>>
>>>
>>>
June 16, 2018
[PATCH] comctl32/imagelist: fix ImageList_Read/Write.
by Локтар Огар
From: Denis Malikov <mdn40000(a)mail.ru>
Date: Sat, 16 Jun 2018 16:35:45 +0700
Subject: [PATCH] comctl32/imagelist: fix ImageList_Read/Write.
Fix for versions x600 and x620 and pointer calculation for mixing
image and mask bits.
Tested on ReactOS 0.4.10 with *.reg files extracted from:
- XP/2003 key HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\TrayNotify;
- Vista/7 key HKEY_CLASSES_ROOT\Local
Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify
Signed-off-by: Denis Malikov <mdn40000(a)mail.ru>
---
dlls/comctl32/imagelist.c | 59 +++++++++++++++++++++++++++--------------------
1 file changed, 34 insertions(+), 25 deletions(-)
diff --git a/dlls/comctl32/imagelist.c b/dlls/comctl32/imagelist.c
index a08d60752e..052d59f9e4 100644
--- a/dlls/comctl32/imagelist.c
+++ b/dlls/comctl32/imagelist.c
@@ -59,7 +59,7 @@ struct _IMAGELIST
INT cGrow; /* 0C: cGrow */
INT cx; /* 10: cx */
INT cy; /* 14: cy */
- DWORD x4;
+ DWORD x4; /* hack for IL from
stream. Keep version here */
UINT flags; /* 1C: flags */
COLORREF clrFg; /* 20: foreground color */
COLORREF clrBk; /* 24: background color */
@@ -83,6 +83,7 @@ struct _IMAGELIST
};
#define IMAGELIST_MAGIC 0x53414D58
+#define IMAGELIST_VERSION 0x101
/* Header used by ImageList_Read() and ImageList_Write() */
#include "pshpack2.h"
@@ -806,6 +807,7 @@ ImageList_Create (INT cx, INT cy, UINT flags,
himl->clrFg = CLR_DEFAULT;
himl->clrBk = CLR_NONE;
himl->color_table_set = FALSE;
+ himl->x4 = 0;
/* initialize overlay mask indices */
for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
@@ -2257,38 +2259,43 @@ HIMAGELIST WINAPI ImageList_Read(IStream *pstm)
BITMAPINFO *image_info = (BITMAPINFO *)image_buf;
BITMAPINFO *mask_info = (BITMAPINFO *)mask_buf;
void *image_bits, *mask_bits = NULL;
- ILHEAD ilHead;
- HIMAGELIST himl;
+ ILHEAD ilHead;
+ HIMAGELIST himl;
unsigned int i;
TRACE("%p\n", pstm);
if (FAILED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
- return NULL;
+ return NULL;
if (ilHead.usMagic != (('L' << 8) | 'I'))
- return NULL;
- if (ilHead.usVersion != 0x101) /* probably version? */
- return NULL;
+ return NULL;
+ if (ilHead.usVersion != IMAGELIST_VERSION &&
+ ilHead.usVersion != 0x600 && /* XP/2003 version */
+ ilHead.usVersion != 0x620) /* Vista/7 version */
+ return NULL;
TRACE("cx %u, cy %u, flags 0x%04x, cCurImage %u, cMaxImage %u\n",
ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage,
ilHead.cMaxImage);
himl = ImageList_Create(ilHead.cx, ilHead.cy, ilHead.flags,
ilHead.cCurImage, ilHead.cMaxImage);
if (!himl)
- return NULL;
+ return NULL;
+
+ // keep version from stream
+ himl->x4 = ilHead.usVersion;
if (!(image_bits = read_bitmap(pstm, image_info)))
{
- WARN("failed to read bitmap from stream\n");
- return NULL;
+ WARN("failed to read bitmap from stream\n");
+ return NULL;
}
if (ilHead.flags & ILC_MASK)
{
if (!(mask_bits = read_bitmap(pstm, mask_info)))
{
WARN("failed to read mask bitmap from stream\n");
- return NULL;
- }
+ return NULL;
+ }
}
else mask_info = NULL;
@@ -2296,23 +2303,25 @@ HIMAGELIST WINAPI ImageList_Read(IStream *pstm)
{
DWORD *ptr = image_bits;
BYTE *mask_ptr = mask_bits;
- int stride = himl->cy * image_info->bmiHeader.biWidth;
+ int stride = himl->cy * (ilHead.usVersion !=
IMAGELIST_VERSION ? himl->cx : image_info->bmiHeader.biWidth);
+ int image_step = ilHead.usVersion != IMAGELIST_VERSION ? 1 :
TILE_COUNT;
+ int mask_step = ilHead.usVersion != IMAGELIST_VERSION ? 4 : 8;
if (image_info->bmiHeader.biHeight > 0) /* bottom-up */
{
ptr += image_info->bmiHeader.biHeight *
image_info->bmiHeader.biWidth - stride;
- mask_ptr += (image_info->bmiHeader.biHeight *
image_info->bmiHeader.biWidth - stride) / 8;
+ mask_ptr += (image_info->bmiHeader.biHeight *
image_info->bmiHeader.biWidth - stride) / mask_step;
stride = -stride;
image_info->bmiHeader.biHeight = himl->cy;
}
else image_info->bmiHeader.biHeight = -himl->cy;
- for (i = 0; i < ilHead.cCurImage; i += TILE_COUNT)
+ for (i = 0; i < ilHead.cCurImage; i += image_step)
{
- add_dib_bits( himl, i, min( ilHead.cCurImage - i, TILE_COUNT ),
+ add_dib_bits( himl, i, min( ilHead.cCurImage - i, image_step ),
himl->cx, himl->cy, image_info, mask_info,
ptr, mask_ptr );
ptr += stride;
- mask_ptr += stride / 8;
+ mask_ptr += stride / mask_step;
}
}
else
@@ -2333,7 +2342,7 @@ HIMAGELIST WINAPI ImageList_Read(IStream *pstm)
ImageList_SetBkColor(himl,ilHead.bkcolor);
for (i=0;i<4;i++)
- ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
+ ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
return himl;
}
@@ -3078,10 +3087,10 @@ BOOL WINAPI ImageList_Write(HIMAGELIST himl,
IStream *pstm)
TRACE("%p %p\n", himl, pstm);
if (!is_valid(himl))
- return FALSE;
+ return FALSE;
ilHead.usMagic = (('L' << 8) | 'I');
- ilHead.usVersion = 0x101;
+ ilHead.usVersion = himl->x4 > 0 ? himl->x4 : IMAGELIST_VERSION;
ilHead.cCurImage = himl->cCurImage;
ilHead.cMaxImage = himl->cMaxImage;
ilHead.cGrow = himl->cGrow;
@@ -3090,23 +3099,23 @@ BOOL WINAPI ImageList_Write(HIMAGELIST himl,
IStream *pstm)
ilHead.bkcolor = himl->clrBk;
ilHead.flags = himl->flags;
for(i = 0; i < 4; i++) {
- ilHead.ovls[i] = himl->nOvlIdx[i];
+ ilHead.ovls[i] = himl->nOvlIdx[i];
}
TRACE("cx %u, cy %u, flags 0x04%x, cCurImage %u, cMaxImage %u\n",
ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage,
ilHead.cMaxImage);
if(FAILED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
- return FALSE;
+ return FALSE;
/* write the bitmap */
if(!_write_bitmap(himl->hbmImage, pstm))
- return FALSE;
+ return FALSE;
/* write the mask if we have one */
if(himl->flags & ILC_MASK) {
- if(!_write_bitmap(himl->hbmMask, pstm))
- return FALSE;
+ if(!_write_bitmap(himl->hbmMask, pstm))
+ return FALSE;
}
return TRUE;
--
2.16.2.windows.1
June 16, 2018
Re: [PATCH] gdiplus: Check return value of SelectClipPath in brush_fill_path().
by Zhiyi Zhang
Hi Vincent,
Yes, we could check if a path is empty just like get_path_hrgn did.
I also worried that a not empty but open path will also make SelectClipPath()
fail. Is there any function to check if a path is closed? I couldn't found any.
As for SelectClipPath() last error, I don't think any further operation should
be continued if any error occurs.
So we add a check for empty path and also skip further operation if SelectClipPath()
returns any error. Is that enough?
Thanks,
Zhiyi
On Fri 6 15 23:55, Vincent Povirk wrote:
> It looks like we also encountered this case in get_path_hrgn. Maybe we
> shouldn't call brush_fill_pixels if the path is empty? If we're going
> to ignore errors, I think we should at least check GetLastError() to
> make sure it's one we expect.
>
> On Fri, Jun 15, 2018 at 4:04 AM, Zhiyi Zhang <zzhang(a)codeweavers.com> wrote:
>> For Crossover bug 16126.
>>
>> When GraphicPath is empty, filling path with gdi32 will
>> result in a DC with empty path. When SelectClipPath() is
>> called with such a DC, it will fail because it requires
>> a closed path in DC. Thus further operation should be canceled.
>>
>> Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
>> ---
>> dlls/gdiplus/graphics.c | 5 +++--
>> 1 file changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
>> index 76aabe74bf..2a95d686fa 100644
>> --- a/dlls/gdiplus/graphics.c
>> +++ b/dlls/gdiplus/graphics.c
>> @@ -1052,6 +1052,7 @@ static BOOL brush_can_fill_path(GpBrush *brush, BOOL is_fill)
>>
>> static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
>> {
>> + BOOL success;
>> switch (brush->bt)
>> {
>> case BrushTypeSolidColor:
>> @@ -1064,8 +1065,8 @@ static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
>> RECT rc;
>> /* partially transparent fill */
>>
>> - SelectClipPath(graphics->hdc, RGN_AND);
>> - if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
>> + success = SelectClipPath(graphics->hdc, RGN_AND);
>> + if (success && GetClipBox(graphics->hdc, &rc) != NULLREGION)
>> {
>> HDC hdc = CreateCompatibleDC(NULL);
>>
>> --
>> 2.17.1
>>
>>
>>
June 16, 2018
[PATCH] comctl32/imagelist: fix ImageList_Read/Write.
by Денис Маликов
From: Denis Malikov <mdn40000(a)mail.ru>
Date: Sat, 16 Jun 2018 16:35:45 +0700
Subject: [PATCH] comctl32/imagelist: fix ImageList_Read/Write.
Fixed acceptable version and pointer calculation for mixing image and mask bits.
Tested on ReactOS 0.4.10 with *.reg files extracted from XP/2003 key HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\TrayNotify
Signed-off-by: Denis Malikov <mdn40000(a)mail.ru>
---
dlls/comctl32/imagelist.c | 48 +++++++++++++++++++++++------------------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/dlls/comctl32/imagelist.c b/dlls/comctl32/imagelist.c
index a08d60752e..f0f8a695fe 100644
--- a/dlls/comctl32/imagelist.c
+++ b/dlls/comctl32/imagelist.c
@@ -2257,38 +2257,38 @@ HIMAGELIST WINAPI ImageList_Read(IStream *pstm)
BITMAPINFO *image_info = (BITMAPINFO *)image_buf;
BITMAPINFO *mask_info = (BITMAPINFO *)mask_buf;
void *image_bits, *mask_bits = NULL;
- ILHEAD ilHead;
- HIMAGELIST himl;
+ ILHEAD ilHead;
+ HIMAGELIST himl;
unsigned int i;
TRACE("%p\n", pstm);
if (FAILED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
- return NULL;
+ return NULL;
if (ilHead.usMagic != (('L' << 8) | 'I'))
- return NULL;
- if (ilHead.usVersion != 0x101) /* probably version? */
- return NULL;
+ return NULL;
+ if (ilHead.usVersion != 0x600) /* XP/2003 version */
+ return NULL;
TRACE("cx %u, cy %u, flags 0x%04x, cCurImage %u, cMaxImage %u\n",
ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
himl = ImageList_Create(ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
if (!himl)
- return NULL;
+ return NULL;
if (!(image_bits = read_bitmap(pstm, image_info)))
{
- WARN("failed to read bitmap from stream\n");
- return NULL;
+ WARN("failed to read bitmap from stream\n");
+ return NULL;
}
if (ilHead.flags & ILC_MASK)
{
if (!(mask_bits = read_bitmap(pstm, mask_info)))
{
WARN("failed to read mask bitmap from stream\n");
- return NULL;
- }
+ return NULL;
+ }
}
else mask_info = NULL;
@@ -2296,23 +2296,23 @@ HIMAGELIST WINAPI ImageList_Read(IStream *pstm)
{
DWORD *ptr = image_bits;
BYTE *mask_ptr = mask_bits;
- int stride = himl->cy * image_info->bmiHeader.biWidth;
+ int stride = himl->cy * himl->cx;
if (image_info->bmiHeader.biHeight > 0) /* bottom-up */
{
ptr += image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride;
- mask_ptr += (image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride) / 8;
+ mask_ptr += (image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride) / 4;
stride = -stride;
image_info->bmiHeader.biHeight = himl->cy;
}
else image_info->bmiHeader.biHeight = -himl->cy;
- for (i = 0; i < ilHead.cCurImage; i += TILE_COUNT)
+ for (i = 0; i < ilHead.cCurImage; i++)
{
- add_dib_bits( himl, i, min( ilHead.cCurImage - i, TILE_COUNT ),
+ add_dib_bits( himl, i, 1,
himl->cx, himl->cy, image_info, mask_info, ptr, mask_ptr );
ptr += stride;
- mask_ptr += stride / 8;
+ mask_ptr += stride / 4;
}
}
else
@@ -2333,7 +2333,7 @@ HIMAGELIST WINAPI ImageList_Read(IStream *pstm)
ImageList_SetBkColor(himl,ilHead.bkcolor);
for (i=0;i<4;i++)
- ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
+ ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
return himl;
}
@@ -3078,10 +3078,10 @@ BOOL WINAPI ImageList_Write(HIMAGELIST himl, IStream *pstm)
TRACE("%p %p\n", himl, pstm);
if (!is_valid(himl))
- return FALSE;
+ return FALSE;
ilHead.usMagic = (('L' << 8) | 'I');
- ilHead.usVersion = 0x101;
+ ilHead.usVersion = 0x600;
ilHead.cCurImage = himl->cCurImage;
ilHead.cMaxImage = himl->cMaxImage;
ilHead.cGrow = himl->cGrow;
@@ -3090,23 +3090,23 @@ BOOL WINAPI ImageList_Write(HIMAGELIST himl, IStream *pstm)
ilHead.bkcolor = himl->clrBk;
ilHead.flags = himl->flags;
for(i = 0; i < 4; i++) {
- ilHead.ovls[i] = himl->nOvlIdx[i];
+ ilHead.ovls[i] = himl->nOvlIdx[i];
}
TRACE("cx %u, cy %u, flags 0x04%x, cCurImage %u, cMaxImage %u\n",
ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
if(FAILED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
- return FALSE;
+ return FALSE;
/* write the bitmap */
if(!_write_bitmap(himl->hbmImage, pstm))
- return FALSE;
+ return FALSE;
/* write the mask if we have one */
if(himl->flags & ILC_MASK) {
- if(!_write_bitmap(himl->hbmMask, pstm))
- return FALSE;
+ if(!_write_bitmap(himl->hbmMask, pstm))
+ return FALSE;
}
return TRUE;
--
2.16.2.windows.1
June 16, 2018
[PATCH] msi: Mark exported wine functions CDECL.
by Zebediah Figura
Fixes relay traces on 64-bit.
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
dlls/msi/custom.c | 2 +-
programs/msiexec/msiexec.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c
index 8deebe5..e68528f 100644
--- a/dlls/msi/custom.c
+++ b/dlls/msi/custom.c
@@ -484,7 +484,7 @@ static void handle_msi_break(LPCSTR target)
static WCHAR ncalrpcW[] = {'n','c','a','l','r','p','c',0};
static WCHAR endpoint_lrpcW[] = {'m','s','i',0};
-UINT __wine_msi_call_dll_function(const GUID *guid)
+UINT CDECL __wine_msi_call_dll_function(const GUID *guid)
{
MsiCustomActionEntryPoint fn;
MSIHANDLE remote_package = 0;
diff --git a/programs/msiexec/msiexec.c b/programs/msiexec/msiexec.c
index 2ed0557..5ebfea7 100644
--- a/programs/msiexec/msiexec.c
+++ b/programs/msiexec/msiexec.c
@@ -393,7 +393,7 @@ static DWORD DoUnregServer(void)
return ret;
}
-extern UINT __wine_msi_call_dll_function(GUID *guid);
+extern UINT CDECL __wine_msi_call_dll_function(GUID *guid);
static int DoEmbedding(LPCWSTR key)
{
--
2.7.4
June 15, 2018
Re: [PATCH] msi/tests: Use the available ARRAY_SIZE() macro
by Hans Leidekker
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
June 15, 2018
Re: [PATCH] msi/tests: Use the available ARRAY_SIZE() macro
by Marvin
Hi,
While running your changed tests on Windows, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at
https://testbot.winehq.org/JobDetails.pl?Key=39159
Your paranoid android.
=== wxppro (32 bit install) ===
TestBot process got stuck or died unexpectedly
The previous 1 run(s) terminated abnormally
June 15, 2018