https://git.reactos.org/?p=reactos.git;a=commitdiff;h=e6bced7a353132121387c7...
commit e6bced7a353132121387c77ed16d67bd10e9d8d5 Author: Katayama Hirofumi MZ katayama.hirofumi.mz@gmail.com AuthorDate: Wed May 3 07:39:05 2023 +0900 Commit: GitHub noreply@github.com CommitDate: Wed May 3 07:39:05 2023 +0900
[EXPLORER][RUNDLL32] Restore minimized non-task windows (#5228)
The minimized non-task windows were not usable due to the bugs. In some situations, the system will restore the minimized non-task windows. - Add IsTaskWnd helper function. - Add SendPulseToTray function to send a pulse to the tray window. - At some shell hook handlings, send a pulse to the tray window. - Add IgnorePulse flag to control the timing of restoring. - Add a timer to reset IgnorePulse flag. - If the pulse has come and IgnorePulse flag is false, then restore the minimized non-task windows. - Modify the rundll32 window procedure. - Use WINDOWPLACEMENT to restore the minimized windows. CORE-13895, CORE-18350 --- base/shell/explorer/precomp.h | 3 + base/shell/explorer/taskswnd.cpp | 40 +++++++------ base/shell/explorer/traywnd.cpp | 123 +++++++++++++++++++++++++++++++-------- base/system/rundll32/rundll32.c | 51 +++++++++++++++- 4 files changed, 175 insertions(+), 42 deletions(-)
diff --git a/base/shell/explorer/precomp.h b/base/shell/explorer/precomp.h index efce3c2a233..881c2d05bce 100644 --- a/base/shell/explorer/precomp.h +++ b/base/shell/explorer/precomp.h @@ -130,6 +130,7 @@ HRESULT WINAPI _CBandSite_CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void #define TWM_GETTASKSWITCH (WM_USER + 236) #define TWM_OPENSTARTMENU (WM_USER + 260) #define TWM_SETTINGSCHANGED (WM_USER + 300) +#define TWM_PULSE (WM_USER + 400)
extern const GUID IID_IShellDesktopTray;
@@ -149,6 +150,7 @@ DECLARE_INTERFACE_(ITrayWindow, IUnknown) STDMETHOD_(HWND, DisplayProperties) (THIS) PURE; STDMETHOD_(BOOL, ExecContextMenuCmd) (THIS_ UINT uiCmd) PURE; STDMETHOD_(BOOL, Lock) (THIS_ BOOL bLock) PURE; + STDMETHOD_(BOOL, IsTaskWnd) (THIS_ HWND hWnd) PURE; }; #undef INTERFACE
@@ -166,6 +168,7 @@ DECLARE_INTERFACE_(ITrayWindow, IUnknown) #define ITrayWindow_DisplayProperties(p) (p)->lpVtbl->DisplayProperties(p) #define ITrayWindow_ExecContextMenuCmd(p,a) (p)->lpVtbl->ExecContextMenuCmd(p,a) #define ITrayWindow_Lock(p,a) (p)->lpVtbl->Lock(p,a) +#define ITrayWindow_IsTaskWnd(p,a) (p)->lpVtbl->IsTaskWnd(p,a) #endif
HRESULT CreateTrayWindow(ITrayWindow ** ppTray); diff --git a/base/shell/explorer/taskswnd.cpp b/base/shell/explorer/taskswnd.cpp index da260dbc3e2..5437f4701f0 100644 --- a/base/shell/explorer/taskswnd.cpp +++ b/base/shell/explorer/taskswnd.cpp @@ -82,6 +82,7 @@ typedef struct _TASK_ITEM PTASK_GROUP Group; INT Index; INT IconIndex; + WINDOWPLACEMENT wndpl;
union { @@ -1112,6 +1113,8 @@ public: TaskItem->hWnd = hWnd; TaskItem->Index = -1; TaskItem->Group = AddToTaskGroup(hWnd); + TaskItem->wndpl.length = sizeof(TaskItem->wndpl); + ::GetWindowPlacement(hWnd, &TaskItem->wndpl);
if (!m_IsDestroying) { @@ -1131,7 +1134,6 @@ public: }
CheckActivateTaskItem(TaskItem); - return FALSE; }
@@ -1384,22 +1386,11 @@ public:
BOOL CALLBACK EnumWindowsProc(IN HWND hWnd) { - /* Only show windows that still exist and are visible and none of explorer's - special windows (such as the desktop or the tray window) */ - if (::IsWindow(hWnd) && ::IsWindowVisible(hWnd) && - !m_Tray->IsSpecialHWND(hWnd)) + if (m_Tray->IsTaskWnd(hWnd)) { - DWORD exStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE); - /* Don't list popup windows and also no tool windows */ - if ((::GetWindow(hWnd, GW_OWNER) == NULL || exStyle & WS_EX_APPWINDOW) && - !(exStyle & WS_EX_TOOLWINDOW)) - { - TRACE("Adding task for %p...\n", hWnd); - AddTask(hWnd); - } - + TRACE("Adding task for %p...\n", hWnd); + AddTask(hWnd); } - return TRUE; }
@@ -1475,6 +1466,12 @@ public: return TRUE; }
+ VOID SendPulseToTray(BOOL bDelete, HWND hwndActive) + { + HWND hwndTray = m_Tray->GetHWND(); + ::SendMessage(hwndTray, TWM_PULSE, bDelete, (LPARAM)hwndActive); + } + BOOL HandleAppCommand(IN WPARAM wParam, IN LPARAM lParam) { BOOL Ret = FALSE; @@ -1516,17 +1513,20 @@ public: break;
case HSHELL_WINDOWCREATED: + SendPulseToTray(FALSE, (HWND)lParam); AddTask((HWND) lParam); break;
case HSHELL_WINDOWDESTROYED: /* The window still exists! Delay destroying it a bit */ - DeleteTask((HWND) lParam); + SendPulseToTray(TRUE, (HWND)lParam); + DeleteTask((HWND)lParam); break;
case HSHELL_RUDEAPPACTIVATED: case HSHELL_WINDOWACTIVATED: - ActivateTask((HWND) lParam); + SendPulseToTray(FALSE, (HWND)lParam); + ActivateTask((HWND)lParam); break;
case HSHELL_FLASH: @@ -1597,12 +1597,17 @@ public:
if (!bIsMinimized && bIsActive) { + TaskItem->wndpl.length = sizeof(TaskItem->wndpl); + ::GetWindowPlacement(TaskItem->hWnd, &TaskItem->wndpl); + ::ShowWindowAsync(TaskItem->hWnd, SW_MINIMIZE); TRACE("Valid button clicked. App window Minimized.\n"); } else { ::SwitchToThisWindow(TaskItem->hWnd, TRUE); + ::SetWindowPlacement(TaskItem->hWnd, &TaskItem->wndpl); + TRACE("Valid button clicked. App window Restored.\n"); } } @@ -1631,6 +1636,7 @@ public: TaskItem = FindTaskItemByIndex((INT) wIndex); if (TaskItem != NULL) { + SendPulseToTray(FALSE, TaskItem->hWnd); HandleTaskItemClick(TaskItem); return TRUE; } diff --git a/base/shell/explorer/traywnd.cpp b/base/shell/explorer/traywnd.cpp index ca930e56e55..05d130b4c3d 100644 --- a/base/shell/explorer/traywnd.cpp +++ b/base/shell/explorer/traywnd.cpp @@ -169,7 +169,13 @@ IsThereAnyEffectiveWindow(BOOL bMustBeInMonitor) return ei.hwndFound != NULL; }
-CSimpleArray<HWND> g_MinimizedAll; +/* Minimized window position info */ +struct MINWNDPOS +{ + HWND hwnd; + WINDOWPLACEMENT wndpl; +}; +CSimpleArray<MINWNDPOS> g_MinimizedAll;
/* * ITrayWindow @@ -559,6 +565,7 @@ public: DWORD InSizeMove : 1; DWORD IsDragging : 1; DWORD NewPosSize : 1; + DWORD IgnorePulse : 1; }; };
@@ -587,6 +594,7 @@ public: ZeroMemory(&m_TraySize, sizeof(m_TraySize)); ZeroMemory(&m_AutoHideOffset, sizeof(m_AutoHideOffset)); ZeroMemory(&m_MouseTrackingInfo, sizeof(m_MouseTrackingInfo)); + IgnorePulse = TRUE; }
virtual ~CTrayWindow() @@ -2460,6 +2468,22 @@ ChangePos: return bPrevLock; }
+ /* The task window is visible and non-WS_EX_TOOLWINDOW and + { has WS_EX_APPWINDOW style or has no owner } and is none of explorer's + special windows (such as the desktop or the tray window) */ + BOOL STDMETHODCALLTYPE IsTaskWnd(HWND hWnd) + { + if (::IsWindow(hWnd) && ::IsWindowVisible(hWnd) && !IsSpecialHWND(hWnd)) + { + DWORD exStyle = (DWORD)::GetWindowLongPtr(hWnd, GWL_EXSTYLE); + if (((exStyle & WS_EX_APPWINDOW) || ::GetWindow(hWnd, GW_OWNER) == NULL) && + !(exStyle & WS_EX_TOOLWINDOW)) + { + return TRUE; + } + } + return FALSE; + }
/* * IContextMenu @@ -2596,6 +2620,15 @@ ChangePos: return TRUE; }
+#define TIMER_ID_IGNOREPULSERESET 888 +#define TIMER_IGNOREPULSERESET_TIMEOUT 200 + + LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + KillTimer(TIMER_ID_IGNOREPULSERESET); + return 0; + } + LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (m_Theme) @@ -3160,6 +3193,39 @@ HandleTrayContextMenu: return (LRESULT)m_TaskSwitch; }
+ void RestoreMinimizedNonTaskWnds(BOOL bDestroyed, HWND hwndActive) + { + for (INT i = g_MinimizedAll.GetSize() - 1; i >= 0; --i) + { + HWND hwnd = g_MinimizedAll[i].hwnd; + if (!hwnd || hwndActive == hwnd) + continue; + + if (::IsWindowVisible(hwnd) && ::IsIconic(hwnd) && + (!IsTaskWnd(hwnd) || !::IsWindowEnabled(hwnd))) + { + ::SetWindowPlacement(hwnd, &g_MinimizedAll[i].wndpl); // Restore + } + } + + g_MinimizedAll.RemoveAll(); + + if (!bDestroyed) + ::SetForegroundWindow(hwndActive); + } + + LRESULT OnPulse(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if (IgnorePulse) + return 0; + + KillTimer(TIMER_ID_IGNOREPULSERESET); + IgnorePulse = TRUE; + RestoreMinimizedNonTaskWnds((BOOL)wParam, (HWND)lParam); + SetTimer(TIMER_ID_IGNOREPULSERESET, TIMER_IGNOREPULSERESET_TIMEOUT, NULL); + return 0; + } + LRESULT OnHotkey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return HandleHotKey(wParam); @@ -3170,8 +3236,7 @@ HandleTrayContextMenu: HWND hwndDesktop; HWND hTrayWnd; HWND hwndProgman; - BOOL bRet; - CSimpleArray<HWND> *pMinimizedAll; + CSimpleArray<MINWNDPOS> *pMinimizedAll; BOOL bShowDesktop; };
@@ -3185,11 +3250,9 @@ HandleTrayContextMenu: static BOOL CALLBACK MinimizeWindowsProc(HWND hwnd, LPARAM lParam) { MINIMIZE_INFO *info = (MINIMIZE_INFO *)lParam; - if (hwnd == info->hwndDesktop || hwnd == info->hTrayWnd || - hwnd == info->hwndProgman) - { - return TRUE; - } + if (hwnd == info->hwndDesktop || hwnd == info->hTrayWnd || hwnd == info->hwndProgman) + return TRUE; // Ignore special windows + if (!info->bShowDesktop) { if (!::IsWindowEnabled(hwnd) || IsDialog(hwnd)) @@ -3198,35 +3261,38 @@ HandleTrayContextMenu: if (hwndOwner && !::IsWindowEnabled(hwndOwner)) return TRUE; } + if (::IsWindowVisible(hwnd) && !::IsIconic(hwnd)) { + MINWNDPOS mwp; + mwp.hwnd = hwnd; + mwp.wndpl.length = sizeof(mwp.wndpl); + ::GetWindowPlacement(hwnd, &mwp.wndpl); // Save the position and status + + info->pMinimizedAll->Add(mwp); + ::ShowWindowAsync(hwnd, SW_MINIMIZE); - info->bRet = TRUE; - info->pMinimizedAll->Add(hwnd); } + return TRUE; }
VOID MinimizeAll(BOOL bShowDesktop = FALSE) { + IgnorePulse = TRUE; + KillTimer(TIMER_ID_IGNOREPULSERESET); + MINIMIZE_INFO info; info.hwndDesktop = GetDesktopWindow();; info.hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL); info.hwndProgman = FindWindowW(L"Progman", NULL); - info.bRet = FALSE; info.pMinimizedAll = &g_MinimizedAll; info.bShowDesktop = bShowDesktop; EnumWindows(MinimizeWindowsProc, (LPARAM)&info);
- // invalid handles should be cleared to avoid mismatch of handles - for (INT i = 0; i < g_MinimizedAll.GetSize(); ++i) - { - if (!::IsWindow(g_MinimizedAll[i])) - g_MinimizedAll[i] = NULL; - } - ::SetForegroundWindow(m_DesktopWnd); ::SetFocus(m_DesktopWnd); + SetTimer(TIMER_ID_IGNOREPULSERESET, TIMER_IGNOREPULSERESET_TIMEOUT, NULL); }
VOID ShowDesktop() @@ -3236,15 +3302,20 @@ HandleTrayContextMenu:
VOID RestoreAll() { + IgnorePulse = TRUE; + KillTimer(TIMER_ID_IGNOREPULSERESET); + for (INT i = g_MinimizedAll.GetSize() - 1; i >= 0; --i) { - HWND hwnd = g_MinimizedAll[i]; + HWND hwnd = g_MinimizedAll[i].hwnd; if (::IsWindowVisible(hwnd) && ::IsIconic(hwnd)) { - ::ShowWindowAsync(hwnd, SW_RESTORE); + ::SetWindowPlacement(hwnd, &g_MinimizedAll[i].wndpl); } } + g_MinimizedAll.RemoveAll(); + SetTimer(TIMER_ID_IGNOREPULSERESET, TIMER_IGNOREPULSERESET_TIMEOUT, NULL); }
LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) @@ -3288,9 +3359,12 @@ HandleTrayContextMenu: { ProcessAutoHide(); } - - bHandled = FALSE; - return TRUE; + else if (wParam == TIMER_ID_IGNOREPULSERESET) + { + KillTimer(TIMER_ID_IGNOREPULSERESET); + IgnorePulse = FALSE; + } + return 0; }
LRESULT OnNcActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) @@ -3479,7 +3553,7 @@ HandleTrayContextMenu: MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_CREATE, OnCreate) - /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/ + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) MESSAGE_HANDLER(WM_COMMAND, OnCommand) MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand) @@ -3512,6 +3586,7 @@ HandleTrayContextMenu: MESSAGE_HANDLER(TWM_OPENSTARTMENU, OnOpenStartMenu) MESSAGE_HANDLER(TWM_DOEXITWINDOWS, OnDoExitWindows) MESSAGE_HANDLER(TWM_GETTASKSWITCH, OnGetTaskSwitch) + MESSAGE_HANDLER(TWM_PULSE, OnPulse) ALT_MSG_MAP(1) END_MSG_MAP()
diff --git a/base/system/rundll32/rundll32.c b/base/system/rundll32/rundll32.c index b02517ef56a..44b3e543813 100644 --- a/base/system/rundll32/rundll32.c +++ b/base/system/rundll32/rundll32.c @@ -29,6 +29,7 @@ #include <winnls.h> #include <winuser.h> #include <tchar.h> +#include <undocuser.h> // For WM_POPUPSYSTEMMENU
#include "resource.h"
@@ -299,9 +300,57 @@ LPSTR DuplicateToMultiByte(LPCTSTR lptString, size_t nBufferSize) return lpString; }
+typedef struct +{ + HWND hwndOwner; + HWND hwndTarget; +} FIND_OWNED, *PFIND_OWNED; + +static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) +{ + PFIND_OWNED pFindOwned = (PFIND_OWNED)lParam; + if (pFindOwned->hwndOwner == GetWindow(hwnd, GW_OWNER)) + { + pFindOwned->hwndTarget = hwnd; + return FALSE; + } + return TRUE; +} + LRESULT CALLBACK EmptyWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - return DefWindowProc(hWnd, uMsg, wParam, lParam); + switch (uMsg) + { + case WM_POPUPSYSTEMMENU: + case WM_SYSCOMMAND: + { + /* Find the owned window */ + FIND_OWNED FindOwned = { hWnd, NULL }; + EnumWindows(EnumWindowsProc, (LPARAM)&FindOwned); + /* Forward message */ + if (FindOwned.hwndTarget) + PostMessageW(FindOwned.hwndTarget, uMsg, wParam, lParam); + break; + } + case WM_ACTIVATE: + { + /* Find the owned window */ + FIND_OWNED FindOwned = { hWnd, NULL }; + EnumWindows(EnumWindowsProc, (LPARAM)&FindOwned); + if (FindOwned.hwndTarget) + { + if (LOWORD(wParam) != WA_INACTIVE) /* To be activated */ + { + SetActiveWindow(FindOwned.hwndTarget); + return 0; + } + } + /* Fall through */ + } + default: + return DefWindowProc(hWnd, uMsg, wParam, lParam); + } + return 0; }
// Registers a minimal window class for passing to the dll function