//// 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 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(); } } // // These functions are used to initialize and configure the main // application window and message pumps. // HRESULT CSampleDesktopWindow::Initialize( _In_ RECT bounds, _In_ std::wstring title ) { // Create device resources required to render content. m_deviceResources = std::make_shared(); 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; } // // This method checks the current DPI against what the application has stored. // If the DPI has changed, update DPI for D2D resources. // 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; } // // This method is called in response to message handlers and // as part of the main message loop. // 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; } // // These functions will be called as messages are processed by message map // defined in the Desktop Window class. // LRESULT CSampleDesktopWindow::OnCreate( _In_ UINT, _In_ WPARAM, _In_ LPARAM lParam, _Out_ BOOL &bHandled ) { auto cs = reinterpret_cast(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(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(lparam); GetClientRect(&clientRect); if (!(windowPos->flags & SWP_NOSIZE)) { DeviceResources::Size size; size.Width = static_cast(clientRect.right - clientRect.left) / (m_deviceResources->GetDpi() / 96.0F); size.Height = static_cast(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(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(lparam) ; ASSERT(GUID_SESSION_DISPLAY_STATUS == ps->PowerSetting); ASSERT(sizeof(DWORD) == ps->DataLength); ASSERT(ps->Data); m_visible = 0 != *reinterpret_cast(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(pt.x) / (m_deviceResources->GetDpi() / 96.0F); auto localy = static_cast(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(pt.x) / (m_deviceResources->GetDpi() / 96.0F); auto localy = static_cast(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(pt.x) / (m_deviceResources->GetDpi() / 96.0F); auto localY = static_cast(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(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(oldRect.right - oldRect.left); float oldHeight = static_cast(oldRect.bottom - oldRect.top); int newWidth = static_cast(oldWidth * newDpi / oldDpi); int newHeight = static_cast(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(dpix) ; }