diff --git a/reactos/dll/win32/user32/windows/menu.c b/reactos/dll/win32/user32/windows/menu.c index 92749931c8a..004eaa7886b 100644 --- a/reactos/dll/win32/user32/windows/menu.c +++ b/reactos/dll/win32/user32/windows/menu.c @@ -1576,6 +1576,11 @@ static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT fl MenuInfo.FocusedItem = NO_SELECTED_ITEM; } + /* ReactOS Check */ + if (!ValidateHwnd(hwndOwner)) + { // This window maybe already DEAD!!! + return FALSE; + } /* store the owner for DrawItem */ MenuInfo.WndOwner = hwndOwner; MenuSetRosMenuInfo(&MenuInfo); @@ -3208,14 +3213,16 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, fEndMenu = !fRemove; } + if (wFlags & TF_ENDMENU) fEndMenu = TRUE; + /* owner may not be visible when tracking a popup, so use the menu itself */ capture_win = (wFlags & TPM_POPUPMENU) ? MenuInfo.Wnd : mt.OwnerWnd; (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, capture_win); // 1 SetCapture(capture_win); // 2 - FIXME("MenuTrackMenu 1\n"); while (! fEndMenu) { + BOOL ErrorExit = FALSE; PVOID menu = ValidateHandle(mt.CurrentMenu, VALIDATE_TYPE_MENU); if (!menu) /* sometimes happens if I do a window manager close */ break; @@ -3233,6 +3240,12 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, } else { + /* ReactOS Check */ + if (!ValidateHwnd(mt.OwnerWnd) || !ValidateHwnd(MenuInfo.Wnd)) + { + ErrorExit = TRUE; // Do not wait on dead windows, now test_capture_4 works. + break; + } if (!enterIdleSent) { HWND win = MenuInfo.Flags & MF_POPUP ? MenuInfo.Wnd : NULL; @@ -3241,9 +3254,10 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, } WaitMessage(); } - //FIXME("MenuTrackMenu loop 1\n"); } + if (ErrorExit) break; // Gracefully dropout. + /* check if EndMenu() tried to cancel us, by posting this message */ if (msg.message == WM_CANCELMODE) { @@ -3449,7 +3463,6 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, { PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); DispatchMessageW( &msg ); - //FIXME("MenuTrackMenu loop 2\n"); continue; } @@ -3460,9 +3473,7 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, if (fRemove && !(mt.TrackFlags & TF_SKIPREMOVE) ) PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); else mt.TrackFlags &= ~TF_SKIPREMOVE; - //FIXME("MenuTrackMenu loop 3\n"); } - FIXME("MenuTrackMenu 2\n"); (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, NULL); SetCapture(NULL); /* release the capture */ @@ -3521,12 +3532,11 @@ static BOOL FASTCALL MenuInitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT HideCaret(0); - MenuGetRosMenuInfo(&MenuInfo, hMenu); /* This makes the menus of applications built with Delphi work. * It also enables menus to be displayed in more than one window, * but there are some bugs left that need to be fixed in this case. */ - if(MenuInfo.Self == hMenu) + if (MenuGetRosMenuInfo(&MenuInfo, hMenu)) { MenuInfo.Wnd = hWnd; MenuSetRosMenuInfo(&MenuInfo); @@ -3658,13 +3668,7 @@ VOID MenuTrackKbdMenuBar(HWND hwnd, UINT wParam, WCHAR wChar) MenuSelectItem( hwnd, &MenuInfo, uItem, TRUE, 0 ); - if (wParam & HTSYSMENU) - { - /* prevent sysmenu activation for managed windows on Alt down/up */ -// if (GetPropA( hwnd, "__wine_x11_managed" )) - wFlags |= TF_ENDMENU; /* schedule end of menu tracking */ - } - else + if (!(wParam & HTSYSMENU) || wChar == ' ') { if( uItem == NO_SELECTED_ITEM ) MenuMoveSelection( hwnd, &MenuInfo, ITEM_NEXT ); @@ -3693,6 +3697,12 @@ BOOL WINAPI TrackPopupMenuEx( HMENU Menu, UINT Flags, int x, int y, return FALSE; } + /* ReactOS Check */ + if (!ValidateHwnd(Wnd)) + { + return FALSE; + } + MenuGetRosMenuInfo(&MenuInfo, Menu); if (IsWindow(MenuInfo.Wnd)) { diff --git a/reactos/dll/win32/user32/windows/message.c b/reactos/dll/win32/user32/windows/message.c index 13d12147d09..8cc1a07f581 100644 --- a/reactos/dll/win32/user32/windows/message.c +++ b/reactos/dll/win32/user32/windows/message.c @@ -2380,9 +2380,7 @@ GetCapture(VOID) BOOL WINAPI ReleaseCapture(VOID) { - HWND hwndPrev = NtUserSetCapture(NULL); - return(hwndPrev ? TRUE : FALSE); -// return (BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_RELEASECAPTURE); + return (BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_RELEASECAPTURE); } diff --git a/reactos/subsystems/win32/win32k/include/focus.h b/reactos/subsystems/win32/win32k/include/focus.h index 299efb56e0f..5c7e6fcefcc 100644 --- a/reactos/subsystems/win32/win32k/include/focus.h +++ b/reactos/subsystems/win32/win32k/include/focus.h @@ -7,6 +7,10 @@ HWND FASTCALL IntGetCaptureWindow(VOID); HWND FASTCALL IntGetFocusWindow(VOID); +HWND FASTCALL +co_UserSetCapture(HWND hWnd); +BOOL FASTCALL +IntReleaseCapture(VOID); /* * These functions take the window handles from current thread queue. diff --git a/reactos/subsystems/win32/win32k/ntuser/focus.c b/reactos/subsystems/win32/win32k/ntuser/focus.c index 65750944072..cdc26a7ff94 100644 --- a/reactos/subsystems/win32/win32k/ntuser/focus.c +++ b/reactos/subsystems/win32/win32k/ntuser/focus.c @@ -580,17 +580,44 @@ co_UserSetCapture(HWND hWnd) ThreadQueue->CaptureWindow = hWnd; - /// These are hacks! - /* also remove other windows if not capturing anymore */ - if (hWnd == NULL) + if (hWnd == NULL) // Release mode. { + MOUSEINPUT mi; + /// These are hacks! + /* also remove other windows if not capturing anymore */ MsqSetStateWindow(ThreadQueue, MSQ_STATE_MENUOWNER, NULL); MsqSetStateWindow(ThreadQueue, MSQ_STATE_MOVESIZE, NULL); - } /// + /* Somebody may have missed some mouse movements */ + mi.dx = 0; + mi.dy = 0; + mi.mouseData = 0; + mi.dwFlags = MOUSEEVENTF_MOVE; + mi.time = 0; + mi.dwExtraInfo = 0; + IntMouseInput(&mi); + } return hWndPrev; } +BOOL +FASTCALL +IntReleaseCapture(VOID) +{ + PTHREADINFO pti; + PUSER_MESSAGE_QUEUE ThreadQueue; + + pti = PsGetCurrentThreadWin32Thread(); + ThreadQueue = pti->MessageQueue; + + // Can not release inside WM_CAPTURECHANGED!! + if (ThreadQueue->QF_flags & QF_CAPTURELOCKED) return FALSE; + + co_UserSetCapture(NULL); + + return TRUE; +} + /* * @implemented */ diff --git a/reactos/subsystems/win32/win32k/ntuser/message.c b/reactos/subsystems/win32/win32k/ntuser/message.c index 4081267b8c3..31fc6ac7d7c 100644 --- a/reactos/subsystems/win32/win32k/ntuser/message.c +++ b/reactos/subsystems/win32/win32k/ntuser/message.c @@ -16,7 +16,6 @@ #include BOOLEAN NTAPI PsGetProcessExitProcessCalled(PEPROCESS Process); -HWND FASTCALL co_UserSetCapture(HWND hWnd); #define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE) @@ -861,7 +860,6 @@ co_IntWaitMessage( PWND Window, { SetLastNtError(Status); DPRINT1("Exit co_IntWaitMessage on error!\n"); - return FALSE; } if (Status == STATUS_USER_APC || Status == STATUS_TIMEOUT) diff --git a/reactos/subsystems/win32/win32k/ntuser/simplecall.c b/reactos/subsystems/win32/win32k/ntuser/simplecall.c index 21109806fe9..e5243d93ad1 100644 --- a/reactos/subsystems/win32/win32k/ntuser/simplecall.c +++ b/reactos/subsystems/win32/win32k/ntuser/simplecall.c @@ -119,6 +119,9 @@ NtUserCallNoParam(DWORD Routine) RETURN( (DWORD_PTR)MAKELONG(pti->ptLast.x, pti->ptLast.y)); } + case NOPARAM_ROUTINE_RELEASECAPTURE: + RETURN( (DWORD_PTR)IntReleaseCapture()); + default: DPRINT1("Calling invalid routine number 0x%x in NtUserCallNoParam\n", Routine); EngSetLastError(ERROR_INVALID_PARAMETER); @@ -252,7 +255,6 @@ NtUserCallOneParam( { BOOL ret = TRUE; - _SEH2_TRY { ProbeForWrite((POINT*)Param,sizeof(POINT),1);