user32: Do not allow a change of capture if the currently capture window is a menu unless explicitly specified.
This commit is contained in:
parent
f6a34c4ece
commit
d21c131fb5
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue