[v2 PATCH] user32/msgbox: Support WM_COPY Message
Alistair Leslie-Hughes
leslie_alistair at hotmail.com
Tue Nov 8 04:44:06 CST 2016
Fixes: https://bugs.winehq.org/show_bug.cgi?id=17205
Signed-off-by: Alistair Leslie-Hughes <leslie_alistair at hotmail.com>
---
dlls/user32/msgbox.c | 86 +++++++++++++++++++--
dlls/user32/tests/dialog.c | 187 ++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 267 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/msgbox.c b/dlls/user32/msgbox.c
index 2ba98c9..4735b8a 100644
--- a/dlls/user32/msgbox.c
+++ b/dlls/user32/msgbox.c
@@ -44,6 +44,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;
@@ -77,11 +82,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);
@@ -319,6 +319,77 @@ static void MSGBOX_OnInit(HWND hwnd, LPMSGBOXPARAMSW lpmb)
HeapFree( GetProcessHeap(), 0, buffer );
}
+static void MSGBOX_CopyToClipboard( HWND hwnd )
+{
+ int i;
+ static const WCHAR line[] = {'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-',
+ '-','-','-','-','-','-','-','-','\r','\n', 0};
+ static const WCHAR crlf[] = {'\r','\n', 0};
+ static const WCHAR spaces[] = {' ',' ',' ', 0};
+ int lenTitle = GetWindowTextLengthW(hwnd) + 1;
+ int lenMsg = GetWindowTextLengthW(GetDlgItem(hwnd, MSGBOX_IDTEXT)) + 1;
+
+ /*
+ ---------------------------
+ Dialog Title
+ ---------------------------
+ Dialog Message
+ ---------------------------
+ Button(s) Text. OK
+ ---------------------------
+ */
+ int len = ((sizeof(crlf) * 3) + (sizeof(line) * 4) + lenTitle + lenMsg) * sizeof(WCHAR);
+ WCHAR *text = HeapAlloc( GetProcessHeap(), 0, len);
+ if(text)
+ {
+ lstrcpyW(text, line);
+ if (GetWindowTextW(hwnd, text + lstrlenW(text), lenTitle))
+ {
+ HGLOBAL hMem;
+ WCHAR *data;
+
+ lstrcatW(text, crlf);
+ lstrcatW(text, line);
+ GetWindowTextW(GetDlgItem(hwnd, MSGBOX_IDTEXT), text + lstrlenW(text), lenMsg);
+ lstrcatW(text, crlf);
+ lstrcatW(text, line);
+
+ for (i = 0; i < (sizeof(buttonOrder) / sizeof(buttonOrder[0])); 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, crlf);
+ 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);
+ EmptyClipboard();
+ SetClipboardData(CF_UNICODETEXT, hMem);
+ CloseClipboard();
+ }
+
+ HeapFree(GetProcessHeap(), 0, text);
+ }
+}
/**************************************************************************
* MSGBOX_DlgProc
@@ -337,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_CopyToClipboard(hwnd);
+ break;
+ }
case WM_COMMAND:
switch (LOWORD(wParam))
diff --git a/dlls/user32/tests/dialog.c b/dlls/user32/tests/dialog.c
index a37c678..0bb7dca 100644
--- a/dlls/user32/tests/dialog.c
+++ b/dlls/user32/tests/dialog.c
@@ -40,6 +40,7 @@
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
+#include "winnls.h"
#define MAXHWNDS 1024
static HWND hwnd [MAXHWNDS];
@@ -1392,6 +1393,187 @@ 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";
+static WCHAR expectedOK[] =
+{
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f',
+'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P',
+'F','_','O','/','w','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'M','e','s','s','a','g','e','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'O','K',' ',' ',' ','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0
+};
+static WCHAR expectedOkCancel[] =
+{
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f',
+'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P',
+'F','_','O','/','w','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'M','e','s','s','a','g','e','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'O','K',' ',' ',' ','C','a','n','c','e','l',' ',' ',' ','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0
+};
+static WCHAR expectedAbortRetryIgnore[] =
+{
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f',
+'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P',
+'F','_','O','/','w','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'M','e','s','s','a','g','e','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'A','b','o','r','t',' ',' ',' ','R','e','t','r','y',' ',' ',' ','I','g','n','o','r','e',' ',' ',' ','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0
+};
+
+static WCHAR expectedYesNo[] =
+{
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f',
+'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P',
+'F','_','O','/','w','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'M','e','s','s','a','g','e','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'Y','e','s',' ',' ',' ','N','o',' ',' ',' ','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0
+};
+static WCHAR expectedYesNoCancel[] =
+{
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f',
+'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P',
+'F','_','O','/','w','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'M','e','s','s','a','g','e','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'Y','e','s',' ',' ',' ','N','o',' ',' ',' ','C','a','n','c','e','l',' ',' ',' ','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0
+};
+static WCHAR expectedRetryCancel[] =
+{
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f',
+'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P',
+'F','_','O','/','w','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'M','e','s','s','a','g','e','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'R','e','t','r','y',' ',' ',' ','C','a','n','c','e','l',' ',' ',' ','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0
+};
+static WCHAR expectedCancelTryContinue[] =
+{
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f',
+'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P',
+'F','_','O','/','w','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'M','e','s','s','a','g','e','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
+'C','a','n','c','e','l',' ',' ',' ','T','r','y',' ','A','g','a','i','n',' ',' ',' ','C','o','n','t','i','n','u','e',' ',' ',' ','\r','\n',
+'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0
+};
+
+BOOL non_english = FALSE;
+
+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)
+ {
+ if(non_english)
+ ok(lstrlenW(text) > 0, "Empty string on clipboard\n");
+ else
+ {
+ 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 || non_english, "Failed to get string.\n");
+
+ return 0;
+}
+
+static void test_MessageBox_WM_COPY_Test(void)
+{
+ DWORD tid = 0;
+
+ non_english = (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH);
+ trace("non_english %d\n", non_english);
+
+ CreateThread(NULL, 0, WorkerThread, &expectedOK, 0, &tid);
+ MessageBoxA(NULL, "Message", msgbox_title, MB_OK);
+
+ CreateThread(NULL, 0, WorkerThread, &expectedOkCancel, 0, &tid);
+ MessageBoxA(NULL, "Message", msgbox_title, MB_OKCANCEL);
+
+ CreateThread(NULL, 0, WorkerThread, &expectedAbortRetryIgnore, 0, &tid);
+ MessageBoxA(NULL, "Message", msgbox_title, MB_ABORTRETRYIGNORE);
+
+ CreateThread(NULL, 0, WorkerThread, &expectedYesNo, 0, &tid);
+ MessageBoxA(NULL, "Message", msgbox_title, MB_YESNO);
+
+ CreateThread(NULL, 0, WorkerThread, &expectedYesNoCancel, 0, &tid);
+ MessageBoxA(NULL, "Message", msgbox_title, MB_YESNOCANCEL);
+
+ CreateThread(NULL, 0, WorkerThread, &expectedRetryCancel, 0, &tid);
+ MessageBoxA(NULL, "Message", msgbox_title, MB_RETRYCANCEL);
+
+ CreateThread(NULL, 0, WorkerThread, &expectedCancelTryContinue, 0, &tid);
+ MessageBoxA(NULL, "Message", msgbox_title, MB_CANCELTRYCONTINUE);
+}
+
static void test_SaveRestoreFocus(void)
{
HWND hDlg;
@@ -1534,9 +1716,12 @@ START_TEST(dialog)
test_focus();
test_GetDlgItem();
test_GetDlgItemText();
- test_DialogBoxParamA();
test_DisabledDialogTest();
test_MessageBoxFontTest();
+ test_MessageBox_WM_COPY_Test();
test_SaveRestoreFocus();
test_timer_message();
+
+ /* This test can make some of the above tests fail. */
+ test_DialogBoxParamA();
}
--
2.10.2
More information about the wine-patches
mailing list