user32: Do not allow a change of capture if the currently capture window is a menu unless explicitly specified. Handle failure in set_capture_window() correctly in SetCapture() and ReleaseCapture(). With tests.
Peter Dons Tychsen (none)
donpedro at donpedro.
Wed Jan 6 20:25:11 CST 2010
Tested on windows-xp
Fixes bug http://bugs.winehq.org/show_bug.cgi?id=21212
---
dlls/user32/input.c | 23 ++++++++++-
dlls/user32/tests/win.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 119 insertions(+), 2 deletions(-)
diff --git a/dlls/user32/input.c b/dlls/user32/input.c
index bfe80c4..83cb7fa 100644
--- a/dlls/user32/input.c
+++ b/dlls/user32/input.c
@@ -85,6 +85,17 @@ BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret )
HWND previous = 0;
UINT flags = 0;
BOOL ret;
+ GUITHREADINFO info;
+ if(!GetGUIThreadInfo(GetCurrentThreadId(), &info))
+ {
+ return FALSE;
+ }
+
+ /* if in menu mode, reject all requests to change focus, except if the menu bit is set */
+ if((info.flags & GUI_INMENUMODE) && !(gui_flags & GUI_INMENUMODE))
+ {
+ return FALSE;
+ }
if (gui_flags & GUI_INMENUMODE) flags |= CAPTURE_MENU;
if (gui_flags & GUI_INMOVESIZE) flags |= CAPTURE_MOVESIZE;
@@ -228,7 +239,11 @@ HWND WINAPI DECLSPEC_HOTPATCH SetCapture( HWND hwnd )
{
HWND previous;
- set_capture_window( hwnd, 0, &previous );
+ if(!set_capture_window( hwnd, 0, &previous ))
+ {
+ return NULL;
+ }
+
return previous;
}
@@ -239,11 +254,15 @@ HWND WINAPI DECLSPEC_HOTPATCH SetCapture( HWND hwnd )
BOOL WINAPI DECLSPEC_HOTPATCH ReleaseCapture(void)
{
BOOL ret = set_capture_window( 0, 0, NULL );
+ if(!ret)
+ {
+ return FALSE;
+ }
/* Somebody may have missed some mouse movements */
mouse_event( MOUSEEVENTF_MOVE, 0, 0, 0, 0 );
- return ret;
+ return TRUE;
}
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c
index 24e6ac2..4ee293d 100644
--- a/dlls/user32/tests/win.c
+++ b/dlls/user32/tests/win.c
@@ -2697,6 +2697,103 @@ static void test_capture_3(HWND hwnd1, HWND hwnd2)
ok (ret, "releasecapture did not return TRUE after second try.\n");
}
+static LRESULT CALLBACK test_capture_4_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ GUITHREADINFO gti;
+ HWND cap_wnd, cap_wnd2, set_cap_wnd;
+ BOOL status;
+ DWORD err;
+ switch (msg)
+ {
+ case WM_CAPTURECHANGED:
+
+ /* now try to release capture from menu. this should fail */
+ memset(>i, 0, sizeof(GUITHREADINFO));
+ gti.cbSize = sizeof(GUITHREADINFO);
+ status = GetGUIThreadInfo(GetCurrentThreadId(), >i);
+ ok(status, "GetGUIThreadInfo() failed!\n");
+ cap_wnd = GetCapture();
+ ok(gti.flags & GUI_INMENUMODE, "Thread info incorrect (flags=%08X)!\n", gti.flags);
+
+ /* check that re-setting the capture for the menu fails */
+ set_cap_wnd = SetCapture(cap_wnd);
+ ok(!set_cap_wnd, "SetCapture should have failed!\n");
+
+ /* check that SetCapture fails for another window and that it does not touch the error code */
+ set_cap_wnd = SetCapture(hWnd);
+ err = GetLastError();
+ ok(!set_cap_wnd, "ReleaseCapture should have failed!\n");
+ ok(err == ERROR_SUCCESS, "Bad error-code from SetCapture. got %08X expected %08X\n", err, 0);
+
+ /* check that ReleaseCapture fails and does not touch the error code */
+ status = ReleaseCapture();
+ err = GetLastError();
+ ok(!status, "ReleaseCapture should have failed!\n");
+ ok(err == ERROR_SUCCESS, "Bad error-code from ReleaseCapture. got %08X expected %08X\n", err, 0);
+
+ /* check that thread info did not change */
+ memset(>i, 0, sizeof(GUITHREADINFO));
+ gti.cbSize = sizeof(GUITHREADINFO);
+ status = GetGUIThreadInfo(GetCurrentThreadId(), >i);
+ ok(status, "GetGUIThreadInfo() failed!\n");
+ ok(gti.flags & GUI_INMENUMODE, "Thread info incorrect (flags=%08X)!\n", gti.flags);
+
+ /* verify that no capture change took place */
+ cap_wnd2 = GetCapture();
+ ok(cap_wnd2 == cap_wnd, "Capture changed!\n");
+
+ /* we are done. kill the window */
+ DestroyWindow(hWnd);
+ break;
+
+ default:
+ return( DefWindowProcA( hWnd, msg, wParam, lParam ) );
+ }
+ return 0;
+}
+
+/* Test that no-one can mess around with the current capture while a menu is open */
+static void test_capture_4(void)
+{
+ BOOL ret;
+ HMENU hmenu;
+ MSG msg;
+ HWND hwnd;
+ WNDCLASSA wclass;
+ HINSTANCE hInstance = GetModuleHandleA( NULL );
+ wclass.lpszClassName = "TestCapture4Class";
+ wclass.style = CS_HREDRAW | CS_VREDRAW;
+ wclass.lpfnWndProc = test_capture_4_proc;
+ wclass.hInstance = hInstance;
+ wclass.hIcon = LoadIconA( 0, IDI_APPLICATION );
+ wclass.hCursor = LoadCursorA( NULL, IDC_ARROW );
+ wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
+ wclass.lpszMenuName = 0;
+ wclass.cbClsExtra = 0;
+ wclass.cbWndExtra = 0;
+ assert (RegisterClassA( &wclass ));
+ assert (hwnd = CreateWindowA( wclass.lpszClassName, "MenuTest",
+ WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,
+ 400, 200, NULL, NULL, hInstance, NULL) );
+ ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
+ if (!hwnd) return;
+ hmenu = CreatePopupMenu();
+
+ ret = AppendMenuA( hmenu, MF_STRING, 1, "winetest2");
+ ok( ret, "AppendMenA has failed!\n");
+
+ /* set main window to have initial capture */
+ SetCapture(hwnd);
+
+ /* create popup (it will self-destruct) */
+ ret = TrackPopupMenu(hmenu, 0x100, 100,100, 0, hwnd, NULL);
+ ok( ret == 0, "TrackPopupMenu returned %d expected zero\n", ret);
+
+ /* clean up */
+ DestroyMenu(hmenu);
+ DestroyWindow(hwnd);
+}
+
/* PeekMessage wrapper that ignores the messages we don't care about */
static BOOL peek_message( MSG *msg )
{
@@ -5821,6 +5918,7 @@ START_TEST(win)
test_capture_1();
test_capture_2();
test_capture_3(hwndMain, hwndMain2);
+ test_capture_4();
test_CreateWindow();
test_parent_owner();
--
1.6.2.5
--=-C7vuVwwuKOCgLiPXTwdK--
More information about the wine-patches
mailing list