You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
155 lines
5.8 KiB
155 lines
5.8 KiB
//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
//// PARTICULAR PURPOSE.
|
|
////
|
|
//// Copyright (c) Microsoft Corporation. All rights reserved
|
|
|
|
#include "pch.h"
|
|
#include "PerMonitorDPIWindow.h"
|
|
|
|
namespace NativeHelpers
|
|
{
|
|
|
|
//Constructor; sets the current process as Per_Monitor_DPI_Aware
|
|
PerMonitorDPIWindow::PerMonitorDPIWindow(void)
|
|
{
|
|
Loaded += gcnew System::Windows::RoutedEventHandler(this, &NativeHelpers::PerMonitorDPIWindow::OnLoaded);
|
|
if (PerMonitorDPIHelper::SetPerMonitorDPIAware())
|
|
{
|
|
m_perMonitorEnabled = true;
|
|
}
|
|
else
|
|
{
|
|
throw gcnew System::Exception(L"Enabling Per-monitor DPI Failed. Do you have [assembly: DisableDpiAwareness] in your assembly manifest [AssemblyInfo.cs]?");
|
|
}
|
|
|
|
}
|
|
|
|
PerMonitorDPIWindow::~PerMonitorDPIWindow()
|
|
{
|
|
}
|
|
|
|
//OnLoaded Handler: Adjusts the window size and graphics and text size based on current DPI of the Window
|
|
|
|
void PerMonitorDPIWindow::OnLoaded(Object^ , RoutedEventArgs^ )
|
|
{
|
|
// WPF has already scaled window size, graphics and text based on system DPI. In order to scale the window based on monitor DPI, update the
|
|
// window size, graphics and text based on monitor DPI. For example consider an application with size 600 x 400 in device independent pixels
|
|
// - Size in device independent pixels = 600 x 400
|
|
// - Size calculated by WPF based on system/WPF DPI = 192 (scale factor = 2)
|
|
// - Expected size based on monitor DPI = 144 (scale factor = 1.5)
|
|
|
|
// Similarly the graphics and text are updated updated by applying appropriate scale transform to the top level node of the WPF application
|
|
|
|
// Important Note: This method overwrites the size of the window and the scale transform of the root node of the WPF Window. Hence,
|
|
// this sample may not work "as is" if
|
|
// - The size of the window impacts other portions of the application like this WPF Window being hosted inside another application.
|
|
// - The WPF application that is extending this class is setting some other transform on the root visual; the sample may
|
|
// overwrite some other transform that is being applied by the WPF application itself.
|
|
|
|
|
|
|
|
|
|
if (m_perMonitorEnabled)
|
|
{
|
|
m_source = (HwndSource^) PresentationSource::FromVisual((Visual^) this);
|
|
HwndSourceHook^ hook = gcnew HwndSourceHook(this, &PerMonitorDPIWindow::HandleMessages);
|
|
m_source->AddHook(hook);
|
|
|
|
|
|
//Calculate the DPI used by WPF; this is same as the system DPI.
|
|
|
|
m_wpfDPI = 96.0 * m_source->CompositionTarget->TransformToDevice.M11;
|
|
|
|
//Get the Current DPI of the monitor of the window.
|
|
|
|
m_currentDPI = NativeHelpers::PerMonitorDPIHelper::GetDpiForWindow(m_source->Handle);
|
|
|
|
//Calculate the scale factor used to modify window size, graphics and text
|
|
m_scaleFactor = m_currentDPI / m_wpfDPI;
|
|
|
|
//Update Width and Height based on the on the current DPI of the monitor
|
|
|
|
Width = Width * m_scaleFactor;
|
|
Height = Height * m_scaleFactor;
|
|
|
|
//Update graphics and text based on the current DPI of the monitor
|
|
|
|
UpdateLayoutTransform(m_scaleFactor);
|
|
}
|
|
}
|
|
|
|
//Called when the DPI of the window changes. This method adjusts the graphics and text size based on the new DPI of the window
|
|
void PerMonitorDPIWindow::OnDPIChanged()
|
|
{
|
|
m_scaleFactor = m_currentDPI / m_wpfDPI;
|
|
UpdateLayoutTransform(m_scaleFactor);
|
|
DPIChanged(this, EventArgs::Empty);
|
|
}
|
|
|
|
|
|
void PerMonitorDPIWindow::UpdateLayoutTransform(double scaleFactor)
|
|
{
|
|
// Adjust the rendering graphics and text size by applying the scale transform to the top level visual node of the Window
|
|
if (m_perMonitorEnabled)
|
|
{
|
|
auto child = GetVisualChild(0);
|
|
if (m_scaleFactor != 1.0) {
|
|
ScaleTransform^ dpiScale = gcnew ScaleTransform(scaleFactor, scaleFactor);
|
|
child->SetValue(Window::LayoutTransformProperty, dpiScale);
|
|
}
|
|
else
|
|
{
|
|
child->SetValue(Window::LayoutTransformProperty, nullptr);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Message handler of the Per_Monitor_DPI_Aware window. The handles the WM_DPICHANGED message and adjusts window size, graphics and text
|
|
// based on the DPI of the monitor. The window message provides the new window size (lparam) and new DPI (wparam)
|
|
|
|
IntPtr PerMonitorDPIWindow::HandleMessages(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, bool% )
|
|
{
|
|
double oldDpi;
|
|
switch (msg)
|
|
{
|
|
case WM_DPICHANGED:
|
|
LPRECT lprNewRect = (LPRECT)lParam.ToPointer();
|
|
SetWindowPos(static_cast<HWND>(hwnd.ToPointer()), 0, lprNewRect->left, lprNewRect->top, lprNewRect->right - lprNewRect->left, lprNewRect->bottom - lprNewRect->top, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
|
|
oldDpi = m_currentDPI;
|
|
m_currentDPI = static_cast<int>(LOWORD(wParam.ToPointer()));
|
|
if (oldDpi != m_currentDPI)
|
|
{
|
|
OnDPIChanged();
|
|
}
|
|
break;
|
|
}
|
|
return IntPtr::Zero;
|
|
}
|
|
|
|
System::String^ PerMonitorDPIWindow::GetCurrentDpiConfiguration()
|
|
{
|
|
System::Text::StringBuilder^ stringBuilder = gcnew System::Text::StringBuilder();
|
|
|
|
auto awareness = NativeHelpers::PerMonitorDPIHelper::GetPerMonitorDPIAware();
|
|
|
|
auto systemDpi = NativeHelpers::PerMonitorDPIHelper::GetSystemDPI();
|
|
|
|
switch (awareness)
|
|
{
|
|
case PROCESS_DPI_AWARENESS::PROCESS_DPI_UNAWARE:
|
|
|
|
stringBuilder->AppendFormat(gcnew System::String(L"Application is DPI Unaware. Using {0} DPI."), systemDpi);
|
|
break;
|
|
case PROCESS_DPI_AWARENESS::PROCESS_SYSTEM_DPI_AWARE:
|
|
stringBuilder->AppendFormat(gcnew System::String(L"Application is System DPI Aware. Using System DPI:{0}."), systemDpi);
|
|
break;
|
|
case PROCESS_DPI_AWARENESS::PROCESS_PER_MONITOR_DPI_AWARE:
|
|
stringBuilder->AppendFormat(gcnew System::String(L"Application is Per-Monitor DPI Aware. Using \tmonitor DPI = {0} \t(System DPI = {1})."), m_currentDPI, systemDpi);
|
|
break;
|
|
}
|
|
return stringBuilder->ToString();
|
|
}
|
|
}
|