From: Alistair Leslie-Hughes leslie_alistair@hotmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=17205
Signed-off-by: Alistair Leslie-Hughes leslie_alistair@hotmail.com --- dlls/user32/msgbox.c | 85 ++++++++++++++++- dlls/user32/tests/dialog.c | 166 ++++++++++++++++++++++++++++++++++ dlls/user32/tests/resource.rc | 11 +++ 3 files changed, 257 insertions(+), 5 deletions(-)
diff --git a/dlls/user32/msgbox.c b/dlls/user32/msgbox.c index 4d345777a10..6b5d867eb1f 100644 --- a/dlls/user32/msgbox.c +++ b/dlls/user32/msgbox.c @@ -41,6 +41,11 @@ struct ThreadWindows HWND *handles; };
+/* Index the order the buttons need to appear to an ID* constant */ +static const int buttonOrder[10] = { IDYES, IDNO, IDOK, IDABORT, IDRETRY, + IDCANCEL, IDIGNORE, IDTRYAGAIN, + IDCONTINUE, IDHELP }; + static BOOL CALLBACK MSGBOX_EnumProc(HWND hwnd, LPARAM lParam) { struct ThreadWindows *threadWindows = (struct ThreadWindows *)lParam; @@ -74,11 +79,6 @@ static void MSGBOX_OnInit(HWND hwnd, LPMSGBOXPARAMSW lpmb) WCHAR *buffer = NULL; const WCHAR *ptr;
- /* Index the order the buttons need to appear to an ID* constant */ - static const int buttonOrder[10] = { IDYES, IDNO, IDOK, IDABORT, IDRETRY, - IDCANCEL, IDIGNORE, IDTRYAGAIN, - IDCONTINUE, IDHELP }; - nclm.cbSize = sizeof(nclm); SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
@@ -320,6 +320,76 @@ static void MSGBOX_OnInit(HWND hwnd, LPMSGBOXPARAMSW lpmb) HeapFree( GetProcessHeap(), 0, buffer ); }
+static void MSGBOX_CopyToClipbaord( HWND hwnd ) +{ + int i; + static const WCHAR line[] = L"---------------------------\r\n"; + static const WCHAR carriage[] = L"\r\n"; + static const WCHAR spaces[] = L" "; + int lenTitle = GetWindowTextLengthW(hwnd) + 1; + int lenMsg = GetWindowTextLengthW(GetDlgItem(hwnd, MSGBOX_IDTEXT)) + 1; + + /* + --------------------------- + Dialog Title + --------------------------- + Dialog Message + --------------------------- + Button(s) Text. OK + --------------------------- + */ + int len = ((wcslen(carriage) * 3) + (wcslen(line) * 4) + lenTitle + lenMsg) * sizeof(WCHAR); + WCHAR *text = heap_alloc(len); + if(text) + { + lstrcpyW(text, line); + if (GetWindowTextW(hwnd, text + lstrlenW(text), lenTitle)) + { + HGLOBAL hMem; + WCHAR *data; + + lstrcatW(text, carriage); + lstrcatW(text, line); + GetWindowTextW(GetDlgItem(hwnd, MSGBOX_IDTEXT), text + lstrlenW(text), lenMsg); + lstrcatW(text, carriage); + lstrcatW(text, line); + + for (i = 0; i < ARRAY_SIZE(buttonOrder); i++) + { + HWND hItem = GetDlgItem(hwnd, buttonOrder[i]); + if (GetWindowLongW(hItem, GWL_STYLE) & WS_VISIBLE) + { + WCHAR buffer[1024] = {0}; + int j = 0, k = lstrlenW(text); + GetWindowTextW(hItem, buffer, 1024); + while(buffer[j] != 0) + { + if(buffer[j] != '&') + text[k++] = buffer[j]; + j++; + } + text[k] = 0; + lstrcatW(text, spaces); + } + } + + lstrcatW(text, carriage); + lstrcatW(text, line); + + hMem = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE|GMEM_ZEROINIT, (len + 1) * sizeof(WCHAR)); + data = GlobalLock(hMem); + lstrcpyW(data, text); + GlobalUnlock(hMem); + + OpenClipboard(hwnd); + NtUserEmptyClipboard(); + SetClipboardData(CF_UNICODETEXT, hMem); + NtUserCloseClipboard(); + } + + heap_free(text); + } +}
/************************************************************************** * MSGBOX_DlgProc @@ -338,6 +408,11 @@ static INT_PTR CALLBACK MSGBOX_DlgProc( HWND hwnd, UINT message, SetPropA(hwnd, "WINE_MSGBOX_HELPCALLBACK", mbp->lpfnMsgBoxCallback); break; } + case WM_COPY: + { + MSGBOX_CopyToClipbaord(hwnd); + break; + }
case WM_COMMAND: switch (LOWORD(wParam)) diff --git a/dlls/user32/tests/dialog.c b/dlls/user32/tests/dialog.c index 7ea0d13c0f3..647abf5a779 100644 --- a/dlls/user32/tests/dialog.c +++ b/dlls/user32/tests/dialog.c @@ -2068,6 +2068,171 @@ static void test_MessageBoxFontTest(void) DestroyWindow(hDlg); }
+static const char msgbox_title[] = "%5!z9ZXw*ia;57n/FGl.bCH,Su"mfKN;foCqAU'j6AmoJgAc_D:Z0A'E6PF_O/w"; + +DWORD WINAPI WorkerThread(void *param) +{ + WCHAR *expected = param; + char windowTitle[sizeof(msgbox_title)]; + HWND hwndMbox; + BOOL succeeded = FALSE; + + Sleep(200); + + hwndMbox = GetForegroundWindow(); + + /* Find the Window, if it doesn't have focus */ + if (!(IsWindow(hwndMbox) && + GetWindowTextA(hwndMbox, windowTitle, sizeof(msgbox_title)) && + lstrcmpA(msgbox_title, windowTitle) == 0)) + { + hwndMbox = FindWindowA(NULL, msgbox_title); + if (!IsWindow(hwndMbox)) + goto cleanup; + } + + SendMessageA(hwndMbox, WM_COPY, 0, 0); + + if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL)) + { + HANDLE textHandle = GetClipboardData(CF_UNICODETEXT); + WCHAR *text = GlobalLock(textHandle); + + if (text != NULL) + { + succeeded = lstrcmpW(expected, text) == 0; + if(!succeeded) + { + ok(0, "%s\n", wine_dbgstr_w(text)); + ok(0, "%s\n", wine_dbgstr_w(expected)); + } + + GlobalUnlock(textHandle); + } + else + ok(0, "No text on clipboard.\n"); + + CloseClipboard(); + + } + else + trace("Clipboard error\n"); + + PostMessageA(hwndMbox, WM_COMMAND, IDIGNORE, 0); /* For MB_ABORTRETRYIGNORE dialog. */ + PostMessageA(hwndMbox, WM_CLOSE, 0, 0); + +cleanup: + ok(succeeded, "Failed to get string.\n"); + + return 0; +} + +static WCHAR *shell_get_resource_string(UINT id) +{ + const WCHAR *resource; + unsigned int size; + WCHAR *ret; + + size = LoadStringW(NULL, id, (WCHAR *)&resource, 0); + ret = malloc((size + 1) * sizeof(WCHAR)); + memcpy(ret, resource, size * sizeof(WCHAR)); + ret[size] = 0; + return ret; +} + +static WCHAR *create_msgbox_message(UINT res1, UINT res2, UINT res3) +{ + /* + --------------------------- + Dialog Title + --------------------------- + Dialog Message + --------------------------- + Button(s) Text. OK<+3 spaces> + --------------------------- + */ + static WCHAR text[512]; + WCHAR *btn1text = shell_get_resource_string(res1); + + lstrcpyW(text, L"---------------------------\r\n"); + lstrcatW(text, L"%5!z9ZXw*ia;57n/FGl.bCH,Su"mfKN;foCqAU'j6AmoJgAc_D:Z0A'E6PF_O/w"); + lstrcatW(text, L"\r\n"); + lstrcatW(text, L"---------------------------\r\n"); + lstrcatW(text, L"Message\r\n"); + lstrcatW(text, L"---------------------------\r\n"); + + lstrcatW(text, btn1text); + lstrcatW(text, L" "); + free(btn1text); + + if (res2 != 0) + { + WCHAR *btn2text = shell_get_resource_string(res2); + lstrcatW(text, btn2text); + lstrcatW(text, L" "); + free(btn2text); + } + if (res3 != 0) + { + WCHAR *btn3text = shell_get_resource_string(res3); + lstrcatW(text, btn3text); + lstrcatW(text, L" "); + free(btn3text); + } + lstrcatW(text, L"\r\n---------------------------\r\n"); + + return text; +} + +static void test_MessageBox_WM_COPY_Test(void) +{ + DWORD tid = 0; + WCHAR *expected; + HANDLE hthread; + + expected = create_msgbox_message(102 /* OK */, 0, 0); + hthread = CreateThread(NULL, 0, WorkerThread, expected, 0, &tid); + MessageBoxA(NULL, "Message", msgbox_title, MB_OK); + ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + CloseHandle(hthread); + + expected = create_msgbox_message(102 /* OK */, 105 /* Cancel */, 0); + hthread = CreateThread(NULL, 0, WorkerThread, expected, 0, &tid); + MessageBoxA(NULL, "Message", msgbox_title, MB_OKCANCEL); + ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + CloseHandle(hthread); + + expected = create_msgbox_message(103 /* Abort */, 104 /* Retry */, 106 /* Ignore */); + hthread = CreateThread(NULL, 0, WorkerThread, expected, 0, &tid); + MessageBoxA(NULL, "Message", msgbox_title, MB_ABORTRETRYIGNORE); + ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + CloseHandle(hthread); + + expected = create_msgbox_message(100 /* Yes */, 101 /* No */, 0); + hthread = CreateThread(NULL, 0, WorkerThread, expected, 0, &tid); + MessageBoxA(NULL, "Message", msgbox_title, MB_YESNO); + ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + CloseHandle(hthread); + + expected = create_msgbox_message(100 /* Yes */, 101 /* No */, 105 /* Cancel */); + hthread = CreateThread(NULL, 0, WorkerThread, expected, 0, &tid); + MessageBoxA(NULL, "Message", msgbox_title, MB_YESNOCANCEL); + ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + CloseHandle(hthread); + + expected = create_msgbox_message(104 /* Retry */, 105 /* Cancel */, 0); + hthread = CreateThread(NULL, 0, WorkerThread, expected, 0, &tid); + MessageBoxA(NULL, "Message", msgbox_title, MB_RETRYCANCEL); + ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + CloseHandle(hthread); + + expected = create_msgbox_message(105 /* Cancel */, 107 /* Try again */, 108 /* Continue */); + hthread = CreateThread(NULL, 0, WorkerThread, expected, 0, &tid); + MessageBoxA(NULL, "Message", msgbox_title, MB_CANCELTRYCONTINUE); + ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + CloseHandle(hthread); +} + static void test_SaveRestoreFocus(void) { HWND hDlg; @@ -2440,6 +2605,7 @@ START_TEST(dialog)
if (!RegisterWindowClasses()) assert(0);
+ test_MessageBox_WM_COPY_Test(); test_dialog_custom_data(); test_GetNextDlgItem(); test_IsDialogMessage(); diff --git a/dlls/user32/tests/resource.rc b/dlls/user32/tests/resource.rc index a957e50689d..5056386ff0e 100644 --- a/dlls/user32/tests/resource.rc +++ b/dlls/user32/tests/resource.rc @@ -42,6 +42,17 @@ STRINGTABLE 0 "String resource" 1 "Another string resource" 2 L"This is a wide string resource" + + 100 "Yes" + 101 "No" + 102 "OK" + 103 "Abort" + 104 "Retry" + 105 "Cancel" + 106 "Ignore" + 107 "Try Again" + 108 "Continue" + 65534 "Test high id" }