Skip to content

Commit

Permalink
[Screen Ruler] Better error handling and reuse D3D device (#20223)
Browse files Browse the repository at this point in the history
* [Screen Ruler] simplify lines calculation

* [Screen Ruler] Add inches and centimeters support

* [Chore] prefer x64 toolset to avoid hitting C1076

* [Screen Ruler] Allow making screenshots in non-continuous mode

* [Screen Ruler] Use single d3d device for all ops

* [Screen Ruler] remove gpu mutex and clean up screen capturing

* [Screen Ruler] handle and log DXGI initialization failure

* [Screen Ruler] Add unhandled exception handler

* [Screen Ruler] comment out Units of Measure setting

* [Screen Ruler] introduce a separate device dedicated for capturing
  • Loading branch information
yuyoyuppe committed Sep 5, 2022
1 parent feead9c commit 9d7c9c1
Show file tree
Hide file tree
Showing 40 changed files with 958 additions and 429 deletions.
11 changes: 6 additions & 5 deletions .github/actions/spell-check/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,6 @@ CSIDL
csignal
cso
CSRW
cstddef
cstdint
cstdlib
cstring
Expand Down Expand Up @@ -402,6 +401,7 @@ DBLEPSILON
DCapture
DCBA
DCOM
dcommon
dcomp
dcompi
DComposition
Expand Down Expand Up @@ -490,7 +490,6 @@ dreamsofameaningfullife
drivedetectionwarning
dshow
dst
DState
DTo
dutil
DVASPECT
Expand Down Expand Up @@ -522,6 +521,7 @@ DWORDLONG
dworigin
dwrite
dxgi
dxgidebug
dxgiformat
dxguid
ecount
Expand Down Expand Up @@ -811,6 +811,7 @@ ICapture
icase
ICEBLUE
IClass
IClosable
ICollection
IColor
ICommand
Expand Down Expand Up @@ -881,7 +882,6 @@ IMAGERESIZERCONTEXTMENU
IMAGERESIZEREXT
imageresizerinput
imageresizersettings
TEXTEXTRACTOR
imagingdevices
IMain
IMarkdown
Expand Down Expand Up @@ -1278,6 +1278,7 @@ Moq
MOUSEACTIVATE
MOUSEHWHEEL
MOUSEINPUT
MOUSELEAVE
MOUSEMOVE
MOUSEWHEEL
MOVESIZEEND
Expand Down Expand Up @@ -1632,7 +1633,6 @@ ptd
PTOKEN
PToy
ptr
ptrdiff
ptstr
PVOID
pwa
Expand Down Expand Up @@ -1746,6 +1746,7 @@ RIGHTSCROLLBAR
riid
riverar
RKey
RLO
RMENU
RNumber
roadmap
Expand Down Expand Up @@ -2063,6 +2064,7 @@ testhost
testprocess
TEXCOORD
textblock
TEXTEXTRACTOR
TEXTINCLUDE
THH
THICKFRAME
Expand Down Expand Up @@ -2272,7 +2274,6 @@ wchar
WClass
wcout
wcscat
wcschr
wcscmp
wcscpy
wcslen
Expand Down
1 change: 1 addition & 0 deletions Cpp.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

<!-- C++ source compile-specific things for all configurations -->
<PropertyGroup>
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
<VcpkgEnabled>false</VcpkgEnabled>
<ExternalIncludePath>$(MSBuildThisFileFullPath)\..\deps\;$(ExternalIncludePath)</ExternalIncludePath>
</PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion installer/PowerToysSetup/Product.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@

<?define ImageResizerSparsePackageAssets=LargeTile.png;SmallTile.png;SplashScreen.png;Square150x150Logo.png;Square44x44Logo.png;storelogo.png;Wide310x150Logo.png?>

<?define MeasureToolFiles=CoreMessagingXP.dll;dcompi.dll;dwmcorei.dll;DwmSceneI.dll;DWriteCore.dll;marshal.dll;Microsoft.DirectManipulation.dll;Microsoft.InputStateManager.dll;Microsoft.InteractiveExperiences.Projection.dll;Microsoft.Internal.FrameworkUdk.dll;Microsoft.UI.Composition.OSSupport.dll;Microsoft.UI.Input.dll;Microsoft.UI.Windowing.Core.dll;Microsoft.UI.Xaml.Controls.dll;Microsoft.UI.Xaml.Controls.pri;Microsoft.ui.xaml.dll;Microsoft.UI.Xaml.Internal.dll;Microsoft.UI.Xaml.Phone.dll;Microsoft.ui.xaml.resources.19h1.dll;Microsoft.ui.xaml.resources.common.dll;Microsoft.Web.WebView2.Core.dll;Microsoft.Windows.ApplicationModel.Resources.dll;Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection.dll;Microsoft.Windows.AppLifecycle.Projection.dll;Microsoft.Windows.AppNotifications.Projection.dll;Microsoft.Windows.PushNotifications.Projection.dll;Microsoft.Windows.SDK.NET.dll;Microsoft.Windows.System.Projection.dll;Microsoft.WindowsAppRuntime.Bootstrap.dll;Microsoft.WindowsAppRuntime.Bootstrap.Net.dll;Microsoft.WindowsAppRuntime.dll;Microsoft.WindowsAppRuntime.Insights.Resource.dll;Microsoft.WindowsAppRuntime.Release.Net.dll;Microsoft.WinUI.dll;MRM.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;PowerToys.MeasureToolCore.dll;PowerToys.MeasureToolUI.deps.json;PowerToys.MeasureToolUI.dll;PowerToys.MeasureToolUI.exe;PowerToys.MeasureToolUI.runtimeconfig.json;PushNotificationsLongRunningTask.ProxyStub.dll;resources.pri;System.CodeDom.dll;System.Management.dll;WindowsAppRuntime.png;WindowsAppSdk.AppxDeploymentExtensions.Desktop.dll;WinRT.Runtime.dll;WinUIEdit.dll;WinUIEx.dll;wuceffectsi.dll?>
<?define MeasureToolFiles=CoreMessagingXP.dll;dcompi.dll;dwmcorei.dll;DwmSceneI.dll;DWriteCore.dll;marshal.dll;Microsoft.DirectManipulation.dll;Microsoft.InputStateManager.dll;Microsoft.InteractiveExperiences.Projection.dll;Microsoft.Internal.FrameworkUdk.dll;Microsoft.UI.Composition.OSSupport.dll;Microsoft.UI.Input.dll;Microsoft.UI.Windowing.Core.dll;Microsoft.UI.Xaml.Controls.dll;Microsoft.UI.Xaml.Controls.pri;Microsoft.ui.xaml.dll;Microsoft.UI.Xaml.Internal.dll;Microsoft.UI.Xaml.Phone.dll;Microsoft.ui.xaml.resources.19h1.dll;Microsoft.ui.xaml.resources.common.dll;Microsoft.Web.WebView2.Core.dll;Microsoft.Windows.ApplicationModel.Resources.dll;Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection.dll;Microsoft.Windows.AppLifecycle.Projection.dll;Microsoft.Windows.AppNotifications.Projection.dll;Microsoft.Windows.PushNotifications.Projection.dll;Microsoft.Windows.SDK.NET.dll;Microsoft.Windows.System.Projection.dll;Microsoft.WindowsAppRuntime.Bootstrap.dll;Microsoft.WindowsAppRuntime.Bootstrap.Net.dll;Microsoft.WindowsAppRuntime.dll;Microsoft.WindowsAppRuntime.Insights.Resource.dll;Microsoft.WindowsAppRuntime.Release.Net.dll;Microsoft.WinUI.dll;MRM.dll;PowerToys.ManagedCommon.dll;PowerToys.Interop.dll;PowerToys.ManagedTelemetry.dll;PowerToys.MeasureToolCore.dll;PowerToys.MeasureToolUI.deps.json;PowerToys.MeasureToolUI.dll;PowerToys.MeasureToolUI.exe;PowerToys.MeasureToolUI.runtimeconfig.json;PushNotificationsLongRunningTask.ProxyStub.dll;resources.pri;System.CodeDom.dll;System.Management.dll;WindowsAppRuntime.png;WindowsAppSdk.AppxDeploymentExtensions.Desktop.dll;WinRT.Runtime.dll;WinUIEdit.dll;WinUIEx.dll;wuceffectsi.dll?>

<?define PowerRenameMicrosoftUIXamlAssetsInstallFiles=NoiseAsset_256x256_PNG.png?>

Expand Down
10 changes: 5 additions & 5 deletions src/common/utils/UnhandledExceptionHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ inline void LogStackTrace()
Logger::error(L"Failed to capture context. {}", get_last_error_or_default(GetLastError()));
return;
}

STACKFRAME64 stack;
memset(&stack, 0, sizeof(STACKFRAME64));

Expand Down Expand Up @@ -238,14 +238,14 @@ inline LONG WINAPI UnhandledExceptionHandler(PEXCEPTION_POINTERS info)
}

/* Handler to trap abort() calls */
inline void AbortHandler(int signal_number)
inline void AbortHandler(int /*signal_number*/)
{
Logger::error("--- ABORT");
try
{
LogStackTrace();
}
catch(...)
catch (...)
{
Logger::error("Failed to log stack trace on abort");
Logger::flush();
Expand All @@ -271,9 +271,9 @@ inline void InitUnhandledExceptionHandler(void)
// Global handler for unhandled exceptions
SetUnhandledExceptionFilter(UnhandledExceptionHandler);
// Handler for abort()
signal(SIGABRT, &AbortHandler);
signal(SIGABRT, &AbortHandler);
}
catch(...)
catch (...)
{
Logger::error("Failed to init global unhandled exception handler");
}
Expand Down
64 changes: 32 additions & 32 deletions src/modules/MeasureTool/MeasureToolCore/BoundsToolOverlayUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ LRESULT CALLBACK BoundsToolWndProc(HWND window, UINT message, WPARAM wparam, LPA
auto toolState = GetWindowParam<BoundsToolState*>(window);
if (!toolState)
break;
const POINT cursorPos = convert::FromSystemToRelativeForDirect2D(window, toolState->commonState->cursorPosSystemSpace);
const POINT cursorPos = convert::FromSystemToWindow(window, toolState->commonState->cursorPosSystemSpace);

D2D_POINT_2F newRegionStart = { .x = static_cast<float>(cursorPos.x), .y = static_cast<float>(cursorPos.y) };
toolState->perScreen[window].currentRegionStart = newRegionStart;
break;
}
case WM_CURSOR_LEFT_MONITOR:
{
for (; ShowCursor(true) < 0;)
;
auto toolState = GetWindowParam<BoundsToolState*>(window);
if (!toolState)
break;
Expand All @@ -59,12 +61,12 @@ LRESULT CALLBACK BoundsToolWndProc(HWND window, UINT message, WPARAM wparam, LPA

if (const bool shiftPress = GetKeyState(VK_SHIFT) & 0x8000; shiftPress)
{
const auto cursorPos = convert::FromSystemToRelativeForDirect2D(window, toolState->commonState->cursorPosSystemSpace);
const auto cursorPos = convert::FromSystemToWindow(window, toolState->commonState->cursorPosSystemSpace);

D2D1_RECT_F rect;
std::tie(rect.left, rect.right) = std::minmax(static_cast<float>(cursorPos.x), toolState->perScreen[window].currentRegionStart->x);
std::tie(rect.top, rect.bottom) = std::minmax(static_cast<float>(cursorPos.y), toolState->perScreen[window].currentRegionStart->y);
toolState->perScreen[window].measurements.push_back(rect);
toolState->perScreen[window].measurements.push_back(Measurement{ rect });
}

toolState->perScreen[window].currentRegionStart = std::nullopt;
Expand Down Expand Up @@ -97,45 +99,42 @@ LRESULT CALLBACK BoundsToolWndProc(HWND window, UINT message, WPARAM wparam, LPA

namespace
{
void DrawMeasurement(const D2D1_RECT_F rect,
void DrawMeasurement(const Measurement& measurement,
const bool alignTextBoxToCenter,
const CommonState& commonState,
HWND window,
const D2DState& d2dState)
const D2DState& d2dState,
float mouseX,
float mouseY)
{
const bool screenQuadrantAware = !alignTextBoxToCenter;
const auto prevMode = d2dState.rt->GetAntialiasMode();
d2dState.rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
d2dState.rt->DrawRectangle(rect, d2dState.solidBrushes[Brush::line].get());
d2dState.rt->SetAntialiasMode(prevMode);
d2dState.ToggleAliasedLinesMode(true);
d2dState.dxgiWindowState.rt->DrawRectangle(measurement.rect, d2dState.solidBrushes[Brush::line].get());
d2dState.ToggleAliasedLinesMode(false);

OverlayBoxText text;
const auto width = std::abs(rect.right - rect.left + 1);
const auto height = std::abs(rect.top - rect.bottom + 1);
const uint32_t textLen = swprintf_s(text.buffer.data(),
text.buffer.size(),
L"%.0f × %.0f",
width,
height);
std::optional<size_t> crossSymbolPos = wcschr(text.buffer.data(), L' ') - text.buffer.data() + 1;
const auto [crossSymbolPos, measureStringBufLen] =
measurement.Print(text.buffer.data(),
text.buffer.size(),
true,
true,
commonState.units);

commonState.overlayBoxText.Access([&](OverlayBoxText& v) {
v = text;
});

float cornerX = rect.right;
float cornerY = rect.bottom;
if (alignTextBoxToCenter)
{
cornerX = rect.left + width / 2;
cornerY = rect.top + height / 2;
mouseX = measurement.rect.left + measurement.Width(Measurement::Unit::Pixel) / 2;
mouseY = measurement.rect.top + measurement.Height(Measurement::Unit::Pixel) / 2;
}

d2dState.DrawTextBox(text.buffer.data(),
textLen,
measureStringBufLen,
crossSymbolPos,
cornerX,
cornerY,
mouseX,
mouseY,
screenQuadrantAware,
window);
}
Expand All @@ -150,20 +149,21 @@ void DrawBoundsToolTick(const CommonState& commonState,
if (it == end(toolState.perScreen))
return;

d2dState.rt->Clear();
d2dState.dxgiWindowState.rt->Clear();

const auto& perScreen = it->second;
for (const auto& measure : perScreen.measurements)
DrawMeasurement(measure, true, commonState, window, d2dState);
DrawMeasurement(measure, true, commonState, window, d2dState, measure.rect.right, measure.rect.bottom);

if (!perScreen.currentRegionStart.has_value())
return;

const auto cursorPos = convert::FromSystemToRelativeForDirect2D(window, commonState.cursorPosSystemSpace);
const auto cursorPos = convert::FromSystemToWindow(window, commonState.cursorPosSystemSpace);

const D2D1_RECT_F rect{ .left = perScreen.currentRegionStart->x,
.top = perScreen.currentRegionStart->y,
.right = static_cast<float>(cursorPos.x),
.bottom = static_cast<float>(cursorPos.y) };
DrawMeasurement(rect, false, commonState, window, d2dState);
D2D1_RECT_F rect;
const float cursorX = static_cast<float>(cursorPos.x);
const float cursorY = static_cast<float>(cursorPos.y);
std::tie(rect.left, rect.right) = std::minmax(cursorX, perScreen.currentRegionStart->x);
std::tie(rect.top, rect.bottom) = std::minmax(cursorY, perScreen.currentRegionStart->y);
DrawMeasurement(Measurement{ rect }, false, commonState, window, d2dState, cursorX, cursorY);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,9 @@
namespace convert
{
// Converts a given point from multi-monitor coordinate system to the one relative to HWND
inline POINT FromSystemToRelative(HWND window, POINT p)
inline POINT FromSystemToWindow(HWND window, POINT p)
{
ScreenToClient(window, &p);
return p;
}

// Converts a given point from multi-monitor coordinate system to the one relative to HWND and also ready
// to be used in Direct2D calls with AA mode set to aliased
inline POINT FromSystemToRelativeForDirect2D(HWND window, POINT p)
{
ScreenToClient(window, &p);
// Submitting DrawLine calls to Direct2D with thickness == 1.f and AA mode set to aliased causes
// them to be drawn offset by [1,1] toward upper-left corner, so we must to compensate for that.
++p.x;
++p.y;
return p;
}
}
Loading

0 comments on commit 9d7c9c1

Please sign in to comment.