/// <summary> /// 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) /// See /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn312083(v=vs.85).aspx">WM_DPICHANGED message</a> /// </summary> /// <param name="hWnd">IntPtr with the hWnd</param> /// <param name="msg">The Windows message</param> /// <param name="wParam">IntPtr</param> /// <param name="lParam">IntPtr</param> /// <param name="handled">ref bool</param> /// <returns>IntPtr</returns> internal IntPtr HandleWindowMessages(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if (HandleWindowMessages(WindowMessageInfo.Create(hWnd, msg, wParam, lParam))) { handled = true; } return(IntPtr.Zero); }
/// <summary> /// Override the WndProc to make sure the DpiHandler is informed of the WM_NCCREATE message /// </summary> /// <param name="m">Message</param> protected override void WndProc(ref Message m) { bool handled = FormDpiHandler.HandleWindowMessages(WindowMessageInfo.Create(m.HWnd, m.Msg, m.WParam, m.LParam)); if (!handled) { base.WndProc(ref m); } }
/// <summary> /// Message handler of the DPI Aware ContextMenuStrip, this is simplified compared to the normal /// 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) /// See /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn312083(v=vs.85).aspx">WM_DPICHANGED message</a> /// </summary> /// <param name="windowMessageInfo">WindowMessageInfo</param> /// <returns>IntPtr</returns> internal IntPtr HandleContextMenuMessages(WindowMessageInfo windowMessageInfo) { var currentDpi = DefaultScreenDpi; bool isDpiMessage = false; switch (windowMessageInfo.Message) { // Handle the WM_CREATE, this is where we can get the DPI via system calls case WindowsMessages.WM_SHOWWINDOW: isDpiMessage = true; if (Log.IsVerboseEnabled()) { Log.Verbose().WriteLine("Processing {0} event, retrieving DPI for ContextMenuStrip {1}", windowMessageInfo.Message, windowMessageInfo.Handle); } currentDpi = NativeDpiMethods.GetDpi(windowMessageInfo.Handle); break; case WindowsMessages.WM_DESTROY: // If the window is destroyed, we complete the subject _onDpiChanged.OnCompleted(); break; } // Check if the DPI was changed, if so call the action (if any) if (!isDpiMessage) { return(IntPtr.Zero); } if (Dpi != currentDpi) { var beforeDpi = Dpi; if (Log.IsVerboseEnabled()) { Log.Verbose().WriteLine("DPI changed from {0} to {1}", beforeDpi, currentDpi); } _onDpiChanged.OnNext(new DpiChangeInfo(beforeDpi, currentDpi)); Dpi = currentDpi; } else if (Log.IsVerboseEnabled()) { Log.Verbose().WriteLine("DPI was unchanged from {0}", Dpi); } return(IntPtr.Zero); }
/// <summary> /// 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) /// See /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn312083(v=vs.85).aspx">WM_DPICHANGED message</a> /// </summary> /// <param name="windowMessageInfo">WindowMessageInfo</param> /// <returns>IntPtr</returns> internal bool HandleWindowMessages(WindowMessageInfo windowMessageInfo) { bool handled = false; var currentDpi = DefaultScreenDpi; bool isDpiMessage = false; switch (windowMessageInfo.Message) { // Handle the WM_NCCREATE for Forms / controls, for WPF this is done differently case WindowsMessages.WM_NCCREATE: if (Log.IsVerboseEnabled()) { Log.Verbose().WriteLine("Processing {0} event, enabling DPI scaling for window {1}", windowMessageInfo.Message, windowMessageInfo.Handle); } TryEnableNonClientDpiScaling(windowMessageInfo.Handle); break; // Handle the WM_CREATE, this is where we can get the DPI via system calls case WindowsMessages.WM_CREATE: isDpiMessage = true; if (Log.IsVerboseEnabled()) { Log.Verbose().WriteLine("Processing {0} event, retrieving DPI for window {1}", windowMessageInfo.Message, windowMessageInfo.Handle); } currentDpi = NativeDpiMethods.GetDpi(windowMessageInfo.Handle); _scopedThreadDpiAwarenessContext.Dispose(); break; // Handle the DPI change message, this is where it's supplied case WindowsMessages.WM_DPICHANGED: isDpiMessage = true; if (Log.IsVerboseEnabled()) { Log.Verbose().WriteLine("Processing {0} event, resizing / positioning window {1}", windowMessageInfo.Message, windowMessageInfo.Handle); } // Retrieve the adviced location var lprNewRect = (NativeRect)Marshal.PtrToStructure(windowMessageInfo.LongParam, typeof(NativeRect)); // Move the window to it's location, and resize User32Api.SetWindowPos(windowMessageInfo.Handle, IntPtr.Zero, lprNewRect.Left, lprNewRect.Top, lprNewRect.Width, lprNewRect.Height, WindowPos.SWP_NOZORDER | WindowPos.SWP_NOOWNERZORDER | WindowPos.SWP_NOACTIVATE); currentDpi = (uint)windowMessageInfo.WordParam & 0xFFFF; // specify that the message was handled handled = true; break; case WindowsMessages.WM_PAINT: // This is a workaround for non DPI aware applications, these don't seem to get a WM_CREATE if (Dpi == 0) { isDpiMessage = true; currentDpi = NativeDpiMethods.GetDpi(windowMessageInfo.Handle); } break; case WindowsMessages.WM_SETICON: // This is a workaround for handling WinProc outside of the class if (_needsListenerWorkaround) { isDpiMessage = true; // disable workaround _needsListenerWorkaround = false; currentDpi = NativeDpiMethods.GetDpi(windowMessageInfo.Handle); } break; case WindowsMessages.WM_DPICHANGED_BEFOREPARENT: if (Log.IsVerboseEnabled()) { Log.Verbose().WriteLine("Dpi changed on {0} before parent", windowMessageInfo.Handle); } break; case WindowsMessages.WM_DPICHANGED_AFTERPARENT: if (Log.IsVerboseEnabled()) { Log.Verbose().WriteLine("Dpi changed on {0} after parent", windowMessageInfo.Handle); } break; case WindowsMessages.WM_DESTROY: if (Log.IsVerboseEnabled()) { Log.Verbose().WriteLine("Completing the observable for {0}", windowMessageInfo.Handle); } // If the window is destroyed, we complete the subject _onDpiChanged.OnCompleted(); // Dispose all resources Dispose(); break; } // Check if the DPI was changed, if so call the action (if any) if (!isDpiMessage) { return(false); } if (Dpi != currentDpi) { var beforeDpi = Dpi; if (Log.IsVerboseEnabled()) { Log.Verbose().WriteLine("Changing DPI from {0} to {1}", beforeDpi, currentDpi); } Dpi = currentDpi; _onDpiChanged.OnNext(new DpiChangeInfo(beforeDpi, currentDpi)); } else if (Log.IsVerboseEnabled()) { Log.Verbose().WriteLine("DPI was unchanged from {0}", Dpi); } return(handled); }