user32: Do not allow a change of capture if the currently capture window is a menu unless explicitly specified.

This commit is contained in:
Peter Dons Tychsen 2010-01-11 21:47:43 +01:00 committed by Alexandre Julliard
parent f6a34c4ece
commit d21c131fb5
3 changed files with 107 additions and 6 deletions

View File

@ -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;
}

View File

@ -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(&gti, 0, sizeof(GUITHREADINFO));
gti.cbSize = sizeof(GUITHREADINFO);
status = GetGUIThreadInfo(GetCurrentThreadId(), &gti);
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(&gti, 0, sizeof(GUITHREADINFO));
gti.cbSize = sizeof(GUITHREADINFO);
status = GetGUIThreadInfo(GetCurrentThreadId(), &gti);
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();

View File

@ -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;