Exemple #1
0
        /// <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);
        }
Exemple #2
0
        /// <summary>
        /// public wrapper for EnableNonClientDpiScaling, this also checks if the function is available.
        /// </summary>
        /// <param name="hWnd">IntPtr</param>
        /// <returns>true if it worked</returns>
        public static bool TryEnableNonClientDpiScaling(IntPtr hWnd)
        {
            // EnableNonClientDpiScaling is only available on Windows 10 and later
            if (!WindowsVersion.IsWindows10OrLater)
            {
                return(false);
            }

            var result = NativeDpiMethods.EnableNonClientDpiScaling(hWnd);

            if (result.Succeeded())
            {
                return(true);
            }

            var error = Win32.GetLastErrorCode();

            if (Log.IsVerboseEnabled())
            {
                Log.Verbose().WriteLine("Error enabling non client dpi scaling : {0}", Win32.GetMessage(error));
            }

            return(false);
        }
Exemple #3
0
        /// <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);
        }
Exemple #4
0
 /// <summary>
 ///     Create a DpiHandler
 /// </summary>
 public DpiHandler(bool needsListenerWorkaround = false)
 {
     _needsListenerWorkaround         = needsListenerWorkaround;
     _scopedThreadDpiAwarenessContext = NativeDpiMethods.DefaultScopedThreadDpiAwarenessContext();
 }