528 lines
12 KiB
C++
528 lines
12 KiB
C++
//// 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 "SampleDesktopWindow.h"
|
|
#include <ShellScalingApi.h>
|
|
|
|
CSampleDesktopWindow::CSampleDesktopWindow()
|
|
{
|
|
// Set member variables to zero or NULL defaults.
|
|
m_visible = FALSE;
|
|
m_occlusion = DWORD(0.0);
|
|
}
|
|
|
|
CSampleDesktopWindow::~CSampleDesktopWindow()
|
|
{
|
|
if (m_deviceResources)
|
|
{
|
|
m_deviceResources->SetWindow(nullptr, 96.0F);
|
|
m_deviceResources.reset();
|
|
}
|
|
}
|
|
|
|
// <summary>
|
|
// These functions are used to initialize and configure the main
|
|
// application window and message pumps.
|
|
// </summary>
|
|
HRESULT
|
|
CSampleDesktopWindow::Initialize(
|
|
_In_ RECT bounds,
|
|
_In_ std::wstring title
|
|
)
|
|
{
|
|
// Create device resources required to render content.
|
|
m_deviceResources = std::make_shared<DeviceResources>();
|
|
if (!m_deviceResources)
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
CreateDeviceIndependentResources();
|
|
CreateDeviceResources();
|
|
|
|
// Create main application window.
|
|
m_hWnd = __super::Create(nullptr, bounds, title.c_str());
|
|
if (!m_hWnd)
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
// Initialize member variables with default values.
|
|
m_visible = TRUE;
|
|
m_occlusion = DWORD(0.0);
|
|
|
|
// Enable mouse to act as pointing device for this application.
|
|
if(!EnableMouseInPointer(TRUE))
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// <summary>
|
|
// This method checks the current DPI against what the application has stored.
|
|
// If the DPI has changed, update DPI for D2D resources.
|
|
// </summary>
|
|
void
|
|
CSampleDesktopWindow::SetNewDpi(_In_ float newPerMonitorDpi)
|
|
{
|
|
if (m_deviceResources && m_deviceResources->GetDpi() != newPerMonitorDpi)
|
|
{
|
|
m_deviceResources->SetDpi(newPerMonitorDpi);
|
|
}
|
|
}
|
|
|
|
// Main message loop for application.
|
|
HRESULT
|
|
CSampleDesktopWindow::Run()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
MSG message = { };
|
|
do
|
|
{
|
|
if (m_visible)
|
|
{
|
|
hr = Render();
|
|
}
|
|
else
|
|
{
|
|
WaitMessage();
|
|
}
|
|
|
|
while (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE))
|
|
{
|
|
TranslateMessage(&message);
|
|
|
|
DispatchMessage(&message);
|
|
}
|
|
} while (message.message != WM_QUIT);
|
|
|
|
return hr;
|
|
}
|
|
|
|
// <summary>
|
|
// This method is called in response to message handlers and
|
|
// as part of the main message loop.
|
|
// </summary>
|
|
HRESULT
|
|
CSampleDesktopWindow::Render()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
auto d2dContext = m_deviceResources->GetD2DDeviceContext();
|
|
|
|
d2dContext->BeginDraw();
|
|
|
|
// Draw window background.
|
|
d2dContext->Clear(D2D1::ColorF(0.8764F, 0.8764F, 0.8882F));
|
|
|
|
// Draw client area as implemented by any derived classes.
|
|
Draw();
|
|
|
|
hr = d2dContext->EndDraw();
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
if (!m_deviceResources->Present())
|
|
{
|
|
hr = m_deviceResources->GetDxgiFactory()->RegisterOcclusionStatusWindow(m_hWnd, WM_USER, &m_occlusion);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
m_visible = false;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// <summary>
|
|
// These functions will be called as messages are processed by message map
|
|
// defined in the Desktop Window class.
|
|
// </summary>
|
|
LRESULT
|
|
CSampleDesktopWindow::OnCreate(
|
|
_In_ UINT,
|
|
_In_ WPARAM,
|
|
_In_ LPARAM lParam,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
auto cs = reinterpret_cast<CREATESTRUCT *>(lParam);
|
|
|
|
auto monitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST);
|
|
UINT dpix;
|
|
UINT dpiy;
|
|
if (FAILED(GetDpiForMonitor(monitor, MONITOR_DPI_TYPE::MDT_EFFECTIVE_DPI, &dpix, &dpiy)))
|
|
{
|
|
dpix = 96;
|
|
dpiy = 96;
|
|
}
|
|
auto windowDpi = static_cast<float>(dpix);
|
|
// Store a reference to the hWnd so DirectX can render to this surface.
|
|
m_deviceResources->SetWindow(m_hWnd, windowDpi);
|
|
|
|
// Set styles needed to avoid drawing over any child or sibling windows.
|
|
cs->style |= ( WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
|
|
|
|
// Set styles required to avoid overdraw.
|
|
cs->dwExStyle |= ( WS_EX_LAYERED | WS_EX_NOREDIRECTIONBITMAP );
|
|
|
|
// Apply selected styles.
|
|
SetWindowLong(GWL_STYLE, cs->style);
|
|
SetWindowLong(GWL_EXSTYLE, cs->dwExStyle);
|
|
ASSERT(SetWindowPos(nullptr, 0, 0, 0, 0,
|
|
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER));
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Destroying this window will also quit the application.
|
|
//
|
|
LRESULT
|
|
CSampleDesktopWindow::OnDestroy(
|
|
_In_ UINT,
|
|
_In_ WPARAM,
|
|
_In_ LPARAM,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
PostQuitMessage(0);
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT
|
|
CSampleDesktopWindow::OnWindowPosChanged(
|
|
_In_ UINT,
|
|
_In_ WPARAM,
|
|
_In_ LPARAM lparam,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
RECT clientRect;
|
|
auto windowPos = reinterpret_cast<WINDOWPOS *>(lparam);
|
|
GetClientRect(&clientRect);
|
|
if (!(windowPos->flags & SWP_NOSIZE))
|
|
{
|
|
DeviceResources::Size size;
|
|
size.Width = static_cast<float>(clientRect.right - clientRect.left) / (m_deviceResources->GetDpi() / 96.0F);
|
|
size.Height = static_cast<float>(clientRect.bottom - clientRect.top) / (m_deviceResources->GetDpi() / 96.0F);
|
|
m_deviceResources->SetLogicalSize(size);
|
|
Render();
|
|
}
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT
|
|
CSampleDesktopWindow::OnDisplayChange(
|
|
_In_ UINT,
|
|
_In_ WPARAM,
|
|
_In_ LPARAM,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
Render();
|
|
OnDisplayChange();
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT
|
|
CSampleDesktopWindow::OnGetMinMaxInfo(
|
|
_In_ UINT,
|
|
_In_ WPARAM,
|
|
_In_ LPARAM lparam,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
auto minMaxInfo = reinterpret_cast<MINMAXINFO *>(lparam) ;
|
|
|
|
minMaxInfo->ptMinTrackSize.y = 200;
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
|
|
LRESULT
|
|
CSampleDesktopWindow::OnActivate(
|
|
_In_ UINT,
|
|
_In_ WPARAM wparam,
|
|
_In_ LPARAM,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
m_visible = !HIWORD(wparam);
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT
|
|
CSampleDesktopWindow::OnPowerBroadcast(
|
|
_In_ UINT,
|
|
_In_ WPARAM,
|
|
_In_ LPARAM lparam,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
if (lparam > 0)
|
|
{
|
|
ASSERT(lparam);
|
|
auto const ps = reinterpret_cast<POWERBROADCAST_SETTING *>(lparam) ;
|
|
ASSERT(GUID_SESSION_DISPLAY_STATUS == ps->PowerSetting);
|
|
|
|
ASSERT(sizeof(DWORD) == ps->DataLength);
|
|
ASSERT(ps->Data);
|
|
m_visible = 0 != *reinterpret_cast<DWORD const *>(ps->Data);
|
|
}
|
|
|
|
if (m_visible)
|
|
{
|
|
PostMessage(WM_NULL);
|
|
}
|
|
|
|
bHandled = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT
|
|
CSampleDesktopWindow::OnOcclusion(
|
|
_In_ UINT,
|
|
_In_ WPARAM,
|
|
_In_ LPARAM,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
ASSERT(m_occlusion);
|
|
|
|
if (S_OK == m_deviceResources->GetSwapChain()->Present(0, DXGI_PRESENT_TEST))
|
|
{
|
|
m_deviceResources->GetDxgiFactory()->UnregisterOcclusionStatus(m_occlusion);
|
|
m_occlusion = 0;
|
|
m_visible = true;
|
|
}
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT
|
|
CSampleDesktopWindow::OnPointerDown(
|
|
_In_ UINT,
|
|
_In_ WPARAM wparam,
|
|
_In_ LPARAM lparam,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
auto x = GET_X_LPARAM(lparam);
|
|
auto y = GET_Y_LPARAM(lparam);
|
|
|
|
POINT pt;
|
|
pt.x = x;
|
|
pt.y = y;
|
|
|
|
ScreenToClient(&pt);
|
|
|
|
auto localx = static_cast<float>(pt.x) / (m_deviceResources->GetDpi() / 96.0F);
|
|
auto localy = static_cast<float>(pt.y) / (m_deviceResources->GetDpi() / 96.0F);
|
|
|
|
// Call handler implemented by derived class for WindowPosChanging message.
|
|
OnPointerDown(localx, localy, GET_POINTERID_WPARAM(wparam));
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT
|
|
CSampleDesktopWindow::OnPointerUpdate(
|
|
_In_ UINT,
|
|
_In_ WPARAM wparam,
|
|
_In_ LPARAM lparam,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
auto x = GET_X_LPARAM(lparam);
|
|
auto y = GET_Y_LPARAM(lparam);
|
|
|
|
POINT pt;
|
|
pt.x = x;
|
|
pt.y = y;
|
|
|
|
ScreenToClient(&pt);
|
|
|
|
auto localx = static_cast<float>(pt.x) / (m_deviceResources->GetDpi() / 96.0F);
|
|
auto localy = static_cast<float>(pt.y) / (m_deviceResources->GetDpi() / 96.0F);
|
|
|
|
// Call handler implemented by derived class for WindowPosChanging message.
|
|
OnPointerUpdate(localx, localy, GET_POINTERID_WPARAM(wparam));
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT
|
|
CSampleDesktopWindow::OnPointerUp(
|
|
_In_ UINT,
|
|
_In_ WPARAM wparam,
|
|
_In_ LPARAM lparam,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
auto x = GET_X_LPARAM(lparam);
|
|
auto y = GET_Y_LPARAM(lparam);
|
|
|
|
POINT pt;
|
|
pt.x = x;
|
|
pt.y = y;
|
|
|
|
ScreenToClient(&pt);
|
|
|
|
auto localX = static_cast<float>(pt.x) / (m_deviceResources->GetDpi() / 96.0F);
|
|
auto localY = static_cast<float>(pt.y) / (m_deviceResources->GetDpi() / 96.0F);
|
|
|
|
// Call handler implemented by derived class for WindowPosChanging message.
|
|
OnPointerUp(localX, localY, GET_POINTERID_WPARAM(wparam));
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CSampleDesktopWindow::OnPointerWheel(
|
|
_In_ UINT,
|
|
_In_ WPARAM wparam,
|
|
_In_ LPARAM lparam,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
// Call handler implemented by derived class for PointerWheel message.
|
|
OnPointerWheel(GET_POINTERID_WPARAM(wparam));
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CSampleDesktopWindow::OnPointerHWheel(
|
|
_In_ UINT,
|
|
_In_ WPARAM wparam,
|
|
_In_ LPARAM lparam,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
// Call handler implemented by derived class for PointerHWheel message.
|
|
OnPointerHWheel(GET_POINTERID_WPARAM(wparam));
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
|
|
LRESULT CSampleDesktopWindow::OnPointerCaptureChange(_In_ UINT, _In_ WPARAM wparam, _In_ LPARAM lparam, _Out_ BOOL &bHandled)
|
|
{
|
|
// Call handler implemented by derived class for PointerCaptureChange message.
|
|
OnPointerCaptureChange(GET_POINTERID_WPARAM(wparam));
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CSampleDesktopWindow::OnTimerUpdate(_In_ UINT, _In_ WPARAM wparam, _In_ LPARAM lparam, _Out_ BOOL &bHandled)
|
|
{
|
|
// Call handler implemented by derived class for TimerUpdate message.
|
|
OnTimerUpdate(wparam);
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT
|
|
CSampleDesktopWindow::OnEnterSizeMove(
|
|
_In_ UINT,
|
|
_In_ WPARAM,
|
|
_In_ LPARAM,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
// Call handler implemented by derived class for WindowPosChanging message.
|
|
OnEnterSizeMove();
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT
|
|
CSampleDesktopWindow::OnExitSizeMove(
|
|
_In_ UINT,
|
|
_In_ WPARAM,
|
|
_In_ LPARAM,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
// Call handler implemented by derived class for WindowPosChanging message.
|
|
OnExitSizeMove();
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT
|
|
CSampleDesktopWindow::OnDpiChange(
|
|
_In_ UINT,
|
|
_In_ WPARAM wparam,
|
|
_In_ LPARAM lparam,
|
|
_Out_ BOOL &bHandled
|
|
)
|
|
{
|
|
auto lprcNewScale = reinterpret_cast<LPRECT>(lparam);
|
|
|
|
// Call handler implemented by derived class for WM_DPICHANGED message.
|
|
OnDpiChange(LOWORD(wparam), lprcNewScale);
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
RECT
|
|
CSampleDesktopWindow::CalcWindowRectNewDpi(
|
|
_In_ RECT oldRect,
|
|
_In_ float oldDpi,
|
|
_In_ float newDpi
|
|
)
|
|
{
|
|
float oldWidth = static_cast<float>(oldRect.right - oldRect.left);
|
|
float oldHeight = static_cast<float>(oldRect.bottom - oldRect.top);
|
|
|
|
int newWidth = static_cast<int>(oldWidth * newDpi / oldDpi);
|
|
int newHeight = static_cast<int>(oldHeight * newDpi / oldDpi);
|
|
|
|
RECT newRect = { oldRect.left, oldRect.top, newWidth, oldRect.top + newHeight };
|
|
return newRect;
|
|
}
|
|
|
|
float
|
|
CSampleDesktopWindow::GetDpiForWindow()
|
|
{
|
|
auto monitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST);
|
|
|
|
UINT dpix;
|
|
UINT dpiy;
|
|
if (FAILED(GetDpiForMonitor(monitor, MONITOR_DPI_TYPE::MDT_EFFECTIVE_DPI, &dpix, &dpiy)))
|
|
{
|
|
dpix = 96;
|
|
dpiy = 96;
|
|
}
|
|
return static_cast<float>(dpix) ;
|
|
} |