Peter Dons Tychsen : user32: Do not allow a change of capture if the currently capture window is a menu unless explicitly specified .
Alexandre Julliard
julliard at winehq.org
Thu Jan 14 11:33:33 CST 2010
Module: wine
Branch: master
Commit: d21c131fb543cd3c43632821dc96df930cb8f84e
URL: http://source.winehq.org/git/wine.git/?a=commit;h=d21c131fb543cd3c43632821dc96df930cb8f84e
Author: Peter Dons Tychsen <donpedro at tdcadsl.dk>
Date: Mon Jan 11 21:47:43 2010 +0100
user32: Do not allow a change of capture if the currently capture window is a menu unless explicitly specified.
---
dlls/user32/input.c | 15 +++++---
dlls/user32/tests/win.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++
server/queue.c | 6 +++
3 files changed, 107 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/input.c b/dlls/user32/input.c
index bfe80c4..96c7038 100644
--- a/dlls/user32/input.c
+++ b/dlls/user32/input.c
@@ -101,12 +101,15 @@ BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret )
}
SERVER_END_REQ;
- USER_Driver->pSetCapture( hwnd, gui_flags );
+ if (ret)
+ {
+ USER_Driver->pSetCapture( hwnd, gui_flags );
- if (previous && previous != hwnd)
- SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
+ if (previous && previous != hwnd)
+ SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
- if (prev_ret) *prev_ret = previous;
+ if (prev_ret) *prev_ret = previous;
+ }
return ret;
}
@@ -226,7 +229,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH SetCursorPos( INT x, INT y )
*/
HWND WINAPI DECLSPEC_HOTPATCH SetCapture( HWND hwnd )
{
- HWND previous;
+ HWND previous = 0;
set_capture_window( hwnd, 0, &previous );
return previous;
@@ -241,7 +244,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH ReleaseCapture(void)
BOOL ret = set_capture_window( 0, 0, NULL );
/* Somebody may have missed some mouse movements */
- mouse_event( MOUSEEVENTF_MOVE, 0, 0, 0, 0 );
+ if (ret) mouse_event( MOUSEEVENTF_MOVE, 0, 0, 0, 0 );
return ret;
}
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c
index 24e6ac2..34ff9d0 100644
--- a/dlls/user32/tests/win.c
+++ b/dlls/user32/tests/win.c
@@ -2697,6 +2697,97 @@ 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;
+ 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);
+ ok(!set_cap_wnd, "ReleaseCapture should have failed!\n");
+
+ /* check that ReleaseCapture fails and does not touch the error code */
+ status = ReleaseCapture();
+ ok(!status, "ReleaseCapture should have failed!\n");
+
+ /* 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;
+ 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 +5912,7 @@ START_TEST(win)
test_capture_1();
test_capture_2();
test_capture_3(hwndMain, hwndMain2);
+ test_capture_4();
test_CreateWindow();
test_parent_owner();
diff --git a/server/queue.c b/server/queue.c
index d880dff..cfe9818 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -2145,6 +2145,12 @@ DECL_HANDLER(set_capture_window)
{
struct thread_input *input = queue->input;
+ /* if in menu mode, reject all requests to change focus, except if the menu bit is set */
+ if (input->menu_owner && !(req->flags & CAPTURE_MENU))
+ {
+ set_error(STATUS_ACCESS_DENIED);
+ return;
+ }
reply->previous = input->capture;
input->capture = get_user_full_handle( req->handle );
input->menu_owner = (req->flags & CAPTURE_MENU) ? input->capture : 0;
More information about the wine-cvs
mailing list