mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
FancyZones: prevent WinHookEventProc reentrancy bugs by serializing events to FancyZones::WndProc
This commit is contained in:
committed by
Andrey Nekrasov
parent
283bfde3d9
commit
57c4658021
@@ -1,6 +1,8 @@
|
||||
#include "pch.h"
|
||||
#include "common/dpi_aware.h"
|
||||
#include "common/on_thread_executor.h"
|
||||
|
||||
#include <common/dpi_aware.h>
|
||||
#include <common/on_thread_executor.h>
|
||||
#include <common/window_helpers.h>
|
||||
|
||||
#include "FancyZones.h"
|
||||
#include "lib/Settings.h"
|
||||
@@ -8,13 +10,12 @@
|
||||
#include "lib/JsonHelpers.h"
|
||||
#include "lib/ZoneSet.h"
|
||||
#include "lib/WindowMoveHandler.h"
|
||||
#include "lib/FancyZonesWinHookEventIDs.h"
|
||||
#include "lib/util.h"
|
||||
#include "trace.h"
|
||||
#include "VirtualDesktopUtils.h"
|
||||
|
||||
#include <functional>
|
||||
#include <common/window_helpers.h>
|
||||
#include <lib/util.h>
|
||||
#include <unordered_set>
|
||||
#include <interface/win_hook_event_data.h>
|
||||
|
||||
enum class DisplayChangeType
|
||||
{
|
||||
@@ -72,14 +73,46 @@ public:
|
||||
MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept
|
||||
{
|
||||
std::unique_lock writeLock(m_lock);
|
||||
m_windowMoveHandler.MoveSizeUpdate(monitor, ptScreen, m_zoneWindowMap);
|
||||
m_windowMoveHandler.MoveSizeUpdate(monitor, ptScreen, m_zoneWindowMap);
|
||||
}
|
||||
IFACEMETHODIMP_(void)
|
||||
MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept
|
||||
{
|
||||
std::unique_lock writeLock(m_lock);
|
||||
m_windowMoveHandler.MoveSizeEnd(window, ptScreen, m_zoneWindowMap);
|
||||
m_windowMoveHandler.MoveSizeEnd(window, ptScreen, m_zoneWindowMap);
|
||||
}
|
||||
IFACEMETHODIMP_(void)
|
||||
HandleWinHookEvent(const WinHookEvent* data) noexcept
|
||||
{
|
||||
const auto wparam = reinterpret_cast<WPARAM>(data->hwnd);
|
||||
const LONG lparam = 0;
|
||||
std::shared_lock readLock(m_lock);
|
||||
switch (data->event)
|
||||
{
|
||||
case EVENT_SYSTEM_MOVESIZESTART:
|
||||
PostMessageW(m_window, WM_PRIV_MOVESIZESTART, wparam, lparam);
|
||||
break;
|
||||
case EVENT_SYSTEM_MOVESIZEEND:
|
||||
PostMessageW(m_window, WM_PRIV_MOVESIZEEND, wparam, lparam);
|
||||
break;
|
||||
case EVENT_OBJECT_LOCATIONCHANGE:
|
||||
PostMessageW(m_window, WM_PRIV_LOCATIONCHANGE, wparam, lparam);
|
||||
break;
|
||||
case EVENT_OBJECT_NAMECHANGE:
|
||||
PostMessageW(m_window, WM_PRIV_NAMECHANGE, wparam, lparam);
|
||||
break;
|
||||
|
||||
case EVENT_OBJECT_UNCLOAKED:
|
||||
case EVENT_OBJECT_SHOW:
|
||||
case EVENT_OBJECT_CREATE:
|
||||
if (data->idObject == OBJID_WINDOW)
|
||||
{
|
||||
PostMessageW(m_window, WM_PRIV_WINDOWCREATED, wparam, lparam);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
VirtualDesktopChanged() noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
@@ -189,7 +222,7 @@ private:
|
||||
void MoveWindowsOnDisplayChange() noexcept;
|
||||
void CycleActiveZoneSet(DWORD vkCode) noexcept;
|
||||
bool OnSnapHotkey(DWORD vkCode) noexcept;
|
||||
|
||||
|
||||
void RegisterVirtualDesktopUpdates(std::vector<GUID>& ids) noexcept;
|
||||
void RegisterNewWorkArea(GUID virtualDesktopId, HMONITOR monitor) noexcept;
|
||||
bool IsNewWorkArea(GUID virtualDesktopId, HMONITOR monitor) noexcept;
|
||||
@@ -204,7 +237,7 @@ private:
|
||||
mutable std::shared_mutex m_lock;
|
||||
HWND m_window{};
|
||||
WindowMoveHandler m_windowMoveHandler;
|
||||
|
||||
|
||||
std::map<HMONITOR, winrt::com_ptr<IZoneWindow>> m_zoneWindowMap; // Map of monitor to ZoneWindow (one per monitor)
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings{};
|
||||
GUID m_currentVirtualDesktopId{}; // UUID of the current virtual desktop. Is GUID_NULL until first VD switch per session.
|
||||
@@ -263,8 +296,7 @@ FancyZones::Run() noexcept
|
||||
.wait();
|
||||
|
||||
m_terminateVirtualDesktopTrackerEvent.reset(CreateEvent(nullptr, FALSE, FALSE, nullptr));
|
||||
m_virtualDesktopTrackerThread.submit(OnThreadExecutor::task_t{ [&] {
|
||||
VirtualDesktopUtils::HandleVirtualDesktopUpdates(m_window, WM_PRIV_VD_UPDATE, m_terminateVirtualDesktopTrackerEvent.get()); } });
|
||||
m_virtualDesktopTrackerThread.submit(OnThreadExecutor::task_t{ [&] { VirtualDesktopUtils::HandleVirtualDesktopUpdates(m_window, WM_PRIV_VD_UPDATE, m_terminateVirtualDesktopTrackerEvent.get()); } });
|
||||
}
|
||||
|
||||
// IFancyZones
|
||||
@@ -289,8 +321,8 @@ FancyZones::Destroy() noexcept
|
||||
IFACEMETHODIMP_(void)
|
||||
FancyZones::VirtualDesktopChanged() noexcept
|
||||
{
|
||||
// VirtualDesktopChanged is called from another thread but results in new windows being created.
|
||||
// Jump over to the UI thread to handle it.
|
||||
// VirtualDesktopChanged is called from a reentrant WinHookProc function, therefore we must postpone the actual logic
|
||||
// until we're in FancyZones::WndProc, which is not reentrant.
|
||||
std::shared_lock readLock(m_lock);
|
||||
PostMessage(m_window, WM_PRIV_VD_SWITCH, 0, 0);
|
||||
}
|
||||
@@ -557,6 +589,9 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
|
||||
|
||||
default:
|
||||
{
|
||||
POINT ptScreen;
|
||||
GetPhysicalCursorPos(&ptScreen);
|
||||
|
||||
if (message == WM_PRIV_VD_INIT)
|
||||
{
|
||||
OnDisplayChange(DisplayChangeType::Initialization);
|
||||
@@ -587,6 +622,31 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
|
||||
m_terminateEditorEvent.release();
|
||||
}
|
||||
}
|
||||
else if (message == WM_PRIV_MOVESIZESTART)
|
||||
{
|
||||
auto hwnd = reinterpret_cast<HWND>(wparam);
|
||||
if (auto monitor = MonitorFromPoint(ptScreen, MONITOR_DEFAULTTONULL))
|
||||
{
|
||||
MoveSizeStart(hwnd, monitor, ptScreen);
|
||||
}
|
||||
}
|
||||
else if (message == WM_PRIV_MOVESIZEEND)
|
||||
{
|
||||
auto hwnd = reinterpret_cast<HWND>(wparam);
|
||||
MoveSizeEnd(hwnd, ptScreen);
|
||||
}
|
||||
else if (message == WM_PRIV_LOCATIONCHANGE && InMoveSize())
|
||||
{
|
||||
if (auto monitor = MonitorFromPoint(ptScreen, MONITOR_DEFAULTTONULL))
|
||||
{
|
||||
MoveSizeUpdate(monitor, ptScreen);
|
||||
}
|
||||
}
|
||||
else if (message == WM_PRIV_WINDOWCREATED)
|
||||
{
|
||||
auto hwnd = reinterpret_cast<HWND>(wparam);
|
||||
WindowCreated(hwnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DefWindowProc(window, message, wparam, lparam);
|
||||
@@ -672,7 +732,6 @@ void FancyZones::AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LRESULT CALLBACK FancyZones::s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||
{
|
||||
auto thisRef = reinterpret_cast<FancyZones*>(GetWindowLongPtr(window, GWLP_USERDATA));
|
||||
|
||||
Reference in New Issue
Block a user