using System; using System.Runtime.InteropServices; namespace Vanara.PInvoke { public static partial class User32 { /// /// Describes per-monitor DPI scaling behavior overrides for child windows within dialogs. The values in this enumeration are /// bitfields and can be combined. /// /// /// /// This enum is used with SetDialogControlDpiChangeBehavior in order to override the default per-monitor DPI scaling behavior for a /// child window within a dialog. /// /// /// These settings only apply to individual controls within dialogs. The dialog-wide per-monitor DPI scaling behavior of a dialog is /// controlled by DIALOG_DPI_CHANGE_BEHAVIORS. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ne-winuser-dialog_control_dpi_change_behaviors typedef enum // DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS { DCDC_DEFAULT, DCDC_DISABLE_FONT_UPDATE, DCDC_DISABLE_RELAYOUT } ; [PInvokeData("winuser.h", MSDNShortId = "B368D997-F409-491A-8578-004C7408A160")] [Flags] public enum DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS { /// /// The default behavior of the dialog manager. The dialog managed will update the font, size, and position of the child window /// on DPI changes. /// DCDC_DEFAULT = 0, /// /// Prevents the dialog manager from sending an updated font to the child window via WM_SETFONT in response to a DPI change. /// DCDC_DISABLE_FONT_UPDATE = 1, /// Prevents the dialog manager from resizing and repositioning the child window in response to a DPI change. DCDC_DISABLE_RELAYOUT = 2, } /// /// /// In Per Monitor v2 contexts, dialogs will automatically respond to DPI changes by resizing themselves and re-computing the /// positions of their child windows (here referred to as re-layouting). This enum works in conjunction with /// SetDialogDpiChangeBehavior in order to override the default DPI scaling behavior for dialogs. /// /// /// This does not affect DPI scaling behavior for the child windows of dialogs (beyond re-layouting), which is controlled by DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ne-winuser-dialog_dpi_change_behaviors typedef enum // DIALOG_DPI_CHANGE_BEHAVIORS { DDC_DEFAULT, DDC_DISABLE_ALL, DDC_DISABLE_RESIZE, DDC_DISABLE_CONTROL_RELAYOUT } ; [PInvokeData("winuser.h", MSDNShortId = "26248777-E95F-49BE-82D6-7237FAEE0627")] [Flags] public enum DIALOG_DPI_CHANGE_BEHAVIORS { /// /// The default behavior of the dialog manager. In response to a DPI change, the dialog manager will re-layout each control, /// update the font on each control, resize the dialog, and update the dialog's own font. /// DDC_DEFAULT = 0, /// /// Prevents the dialog manager from responding to WM_GETDPISCALEDSIZE and WM_DPICHANGED, disabling all default DPI scaling behavior. /// DDC_DISABLE_ALL = 1, /// Prevents the dialog manager from resizing the dialog in response to a DPI change. DDC_DISABLE_RESIZE = 2, /// /// Prevents the dialog manager from re-layouting all of the dialogue's immediate children HWNDs in response to a DPI change. /// DDC_DISABLE_CONTROL_RELAYOUT = 4, } /// /// Identifies the dots per inch (dpi) setting for a thread, process, or window. /// /// /// /// In previous versions of Windows, DPI values were only set once for an entire application. For those apps, the /// PROCESS_DPI_AWARENESS type determined the type of DPI awareness for the entire application. Currently, the DPI awareness is /// defined on an individual thread, window, or process level and is indicated by the DPI_AWARENESS type. While the focus /// shifted from a process level to a thread level, the different kinds of DPI awareness are the same: unaware, system aware, and per /// monitor aware. For detailed descriptions and some examples of the different DPI kinds, see PROCESS_DPI_AWARENESS. /// /// /// The old recommendation was to define the DPI awareness level in the application manifest using the setting dpiAware as explained /// in PROCESS_DPI_AWARENESS. Now that the DPI awareness is tied to threads and windows instead of an entire application, a new /// windows setting is added to the app manifest. This setting is dpiAwareness and will override any dpiAware setting if both of them /// are present in the manifest. While it is still recommended to use the manifest, you can now change the DPI awareness while the /// app is running by using SetThreadDpiAwarenessContext. /// /// /// It is important to note that if your application has a DPI_AWARENESS_PER_MONITOR_AWARE window, you are responsible for /// keeping track of the DPI by responding to WM_DPICHANGED messages. /// /// Examples /// This snippet demonstrates how to set a value of DPI_AWARENESS_SYSTEM_AWARE in your application manifest. /// This snippet demonstrates how to set a value of DPI_AWARENESS_PER_MONITOR_AWARE in your application manifest. /// // https://docs.microsoft.com/en-us/windows/desktop/api/windef/ne-windef-dpi_awareness typedef enum DPI_AWARENESS { // DPI_AWARENESS_INVALID, DPI_AWARENESS_UNAWARE, DPI_AWARENESS_SYSTEM_AWARE, DPI_AWARENESS_PER_MONITOR_AWARE } ; [PInvokeData("windef.h", MSDNShortId = "0E7EB331-7D72-4853-8785-03F30263C323")] public enum DPI_AWARENESS { /// Invalid DPI awareness. This is an invalid DPI awareness value. DPI_AWARENESS_INVALID = -1, /// /// DPI unaware. This process does not scale for DPI changes and is always assumed to have a scale factor of 100% (96 DPI). It /// will be automatically scaled by the system on any other DPI setting. /// DPI_AWARENESS_UNAWARE = 0, /// /// System DPI aware. This process does not scale for DPI changes. It will query for the DPI once and use that value for the /// lifetime of the process. If the DPI changes, the process will not adjust to the new DPI value. It will be automatically /// scaled up or down by the system when the DPI changes from the system value. /// DPI_AWARENESS_SYSTEM_AWARE = 1, /// /// Per monitor DPI aware. This process checks for the DPI when it is created and adjusts the scale factor whenever the DPI /// changes. These processes are not automatically scaled by the system. /// DPI_AWARENESS_PER_MONITOR_AWARE = 2, } /// /// Identifies the DPI hosting behavior for a window. This behavior allows windows created in the thread to host child windows with a /// different DPI_AWARENESS_CONTEXT /// /// /// /// DPI_HOSTING_BEHAVIOR enables a mixed content hosting behavior, which allows parent windows created in the thread to host /// child windows with a different DPI_AWARENESS_CONTEXT value. This property only effects new windows created within this thread /// while the mixed hosting behavior is active. A parent window with this hosting behavior is able to host child windows with /// different DPI_AWARENESS_CONTEXT values, regardless of whether the child windows have mixed hosting behavior enabled. /// /// /// This hosting behavior does not allow for windows with per-monitor DPI_AWARENESS_CONTEXT values to be hosted until windows /// with DPI_AWARENESS_CONTEXT values of system or unaware. /// /// /// To avoid unexpected outcomes, a thread's DPI_HOSTING_BEHAVIOR should be changed to support mixed hosting behaviors only /// when creating a new window which needs to support those behaviors. Once that window is created, the hosting behavior should be /// switched back to its default value. /// /// /// Enabling mixed hosting behavior will not automatically adjust the thread's DPI_AWARENESS_CONTEXT to be compatible with /// legacy content. The thread's awareness context must still be manually changed before new windows are created to host such content. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/windef/ne-windef-dpi_hosting_behavior typedef enum DPI_HOSTING_BEHAVIOR { // DPI_HOSTING_BEHAVIOR_INVALID, DPI_HOSTING_BEHAVIOR_DEFAULT, DPI_HOSTING_BEHAVIOR_MIXED } ; [PInvokeData("windef.h", MSDNShortId = "4BFBF485-1AD2-4460-A4EE-CB76EF62B8C4")] public enum DPI_HOSTING_BEHAVIOR { /// /// Invalid DPI hosting behavior. This usually occurs if the previous SetThreadDpiHostingBehavior call used an invalid parameter. /// DPI_HOSTING_BEHAVIOR_INVALID = -1, /// /// Default DPI hosting behavior. The associated window behaves as normal, and cannot create or re-parent child windows with a /// different DPI_AWARENESS_CONTEXT. /// DPI_HOSTING_BEHAVIOR_DEFAULT = 0, /// /// Mixed DPI hosting behavior. This enables the creation and re-parenting of child windows with different DPI_AWARENESS_CONTEXT. /// These child windows will be independently scaled by the OS. /// DPI_HOSTING_BEHAVIOR_MIXED = 1, } /// /// Calculates the required size of the window rectangle, based on the desired size of the client rectangle and the provided DPI. /// This window rectangle can then be passed to the CreateWindowEx function to create a window with a client area of the desired size. /// /// /// A pointer to a RECT structure that contains the coordinates of the top-left and bottom-right corners of the desired client /// area. When the function returns, the structure contains the coordinates of the top-left and bottom-right corners of the window to /// accommodate the desired client area. /// /// /// The Window Style of the window whose required size is to be calculated. Note that you cannot specify the WS_OVERLAPPED style. /// /// Indicates whether the window has a menu. /// The Extended Window Style of the window whose required size is to be calculated. /// The DPI to use for scaling. /// /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero. To get extended error information, call GetLastError. /// /// /// This function returns the same result as AdjustWindowRectEx but scales it according to an arbitrary DPI you provide if appropriate. /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-adjustwindowrectexfordpi BOOL AdjustWindowRectExForDpi( // LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi ); [DllImport(Lib.User32, SetLastError = true, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "C7126165-1D64-4C04-9B8D-4F90AC2F2C67")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool AdjustWindowRectExForDpi(ref RECT lpRect, WindowStyles dwStyle, [MarshalAs(UnmanagedType.Bool)] bool bMenu, WindowStylesEx dwExStyle, uint dpi); /// Determines whether two DPI_AWARENESS_CONTEXT values are identical. /// The first value to compare. /// The second value to compare. /// Returns TRUE if the values are equal, otherwise FALSE. /// /// A DPI_AWARENESS_CONTEXT contains multiple pieces of information. For example, it includes both the current and the /// inherited DPI_AWARENESS values. AreDpiAwarenessContextsEqual ignores informational flags and determines if the values are /// equal. You can't use a direct bitwise comparison because of these informational flags. /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-aredpiawarenesscontextsequal BOOL // AreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT dpiContextA, DPI_AWARENESS_CONTEXT dpiContextB ); [DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "77660CAB-97ED-4DAC-A95E-A149F1A479FD")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool AreDpiAwarenessContextsEqual(DPI_AWARENESS_CONTEXT dpiContextA, DPI_AWARENESS_CONTEXT dpiContextB); /// /// In high-DPI displays, enables automatic display scaling of the non-client area portions of the specified top-level window. Must /// be called during the initialization of that window. /// /// The window that should have automatic scaling enabled. /// /// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error /// information, call GetLastError. /// /// /// /// Calling this function will enable non-client scaling for an individual top-level window with DPI_AWARENESS_CONTEXT of /// DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE. If instead you are not using per-window awareness, and your entire process is /// running in DPI_AWARENESS_PER_MONITOR_AWARE mode, calling this function will enable non-client scaling in top-level windows /// in your process. /// /// /// If neither of those are true, or if you call this method from any other window, then it will fail and return a value of zero. /// /// /// Non-client scaling for top-level windows is not enabled by default. You must call this API to enable it for each individual /// top-level window for which you wish to have the non-client area scale automatically. Once you do, there is no way to disable it. /// Enabling non-client scaling means that all the areas drawn by the system for the window will automatically scale in response to /// DPI changes on the window. That includes areas like the caption bar, the scrollbars, and the menu bar. You want to call /// EnableNonClientDpiScaling when you want the operating system to be responsible for rendering these areas automatically at /// the correct size based on the API of the monitor. /// /// Calling this function enables non-client scaling for top-level windows only. Child windows are unaffected. /// /// This function must be called from WM_NCCREATE during the initialization of a new window. An example call might look like this: /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-enablenonclientdpiscaling BOOL EnableNonClientDpiScaling( // HWND hwnd ); [DllImport(Lib.User32, SetLastError = true, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "3459B040-B73F-4581-BA29-0B2F0241801E")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool EnableNonClientDpiScaling(HWND hwnd); /// Retrieves the DPI_AWARENESS value from a DPI_AWARENESS_CONTEXT. /// The DPI_AWARENESS_CONTEXT you want to examine. /// The DPI_AWARENESS. If the provided value is null or invalid, this method will return DPI_AWARENESS_INVALID. /// /// A DPI_AWARENESS_CONTEXT contains multiple pieces of information. For example, it includes both the current and the inherited /// DPI_AWARENESS. This method retrieves the DPI_AWARENESS from the structure. /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getawarenessfromdpiawarenesscontext DPI_AWARENESS // GetAwarenessFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT value ); [DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "BE4DC6B9-BCD6-4E27-81F8-E3CF054CFBE9")] public static extern DPI_AWARENESS GetAwarenessFromDpiAwarenessContext(DPI_AWARENESS_CONTEXT value); /// Retrieves and per-monitor DPI scaling behavior overrides of a child window in a dialog. /// The handle for the window to examine. /// /// The flags set on the given window. If passed an invalid handle, this function will return zero, and set its last error to ERROR_INVALID_HANDLE. /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getdialogcontroldpichangebehavior // DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS GetDialogControlDpiChangeBehavior( HWND hWnd ); [DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "1651353F-5823-41B8-AE52-016AEBA6C4F0")] public static extern DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS GetDialogControlDpiChangeBehavior(HWND hWnd); /// /// Returns the flags that might have been set on a given dialog by an earlier call to SetDialogDpiChangeBehavior. /// If that function was never called on the dialog, the return value will be zero. /// /// The handle for the dialog to examine. /// /// The flags set on the given dialog. If passed an invalid handle, this function will return zero, and set its last error to ERROR_INVALID_HANDLE. /// /// /// It can be difficult to distinguish between a return value of DDC_DEFAULT and the error case, which is zero. To determine /// between the two, it is recommended that you call GetLastError() to check the error. /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getdialogdpichangebehavior DIALOG_DPI_CHANGE_BEHAVIORS // GetDialogDpiChangeBehavior( HWND hDlg ); [DllImport(Lib.User32, SetLastError = true, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "8ED61C77-36C8-453B-BAB1-505CE4974D63")] public static extern DIALOG_DPI_CHANGE_BEHAVIORS GetDialogDpiChangeBehavior(HWND hDlg); /// Returns the dots per inch (dpi) value for the associated window. /// The window you want to get information about. /// /// The DPI for the window which depends on the DPI_AWARENESS of the window. See the Remarks for more information. An invalid hwnd /// value will result in a return value of 0. /// /// /// The following table indicates the return value of GetDpiForWindow based on the DPI_AWARENESS of the provided hwnd. /// /// /// DPI_AWARENESS /// Return value /// /// /// DPI_AWARENESS_UNAWARE /// 96 /// /// /// DPI_AWARENESS_SYSTEM_AWARE /// The system DPI. /// /// /// DPI_AWARENESS_PER_MONITOR_AWARE /// The DPI of the monitor where the window is located. /// /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getdpiforwindow UINT GetDpiForWindow( HWND hwnd ); [DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "E9F7BCFA-4215-44C0-95FB-57C28325720C")] public static extern uint GetDpiForWindow(HWND hwnd); /// /// Retrieves the DPI from a given DPI_AWARENESS_CONTEXT handle. This enables you to determine the DPI of a thread without needed to /// examine a window created within that thread. /// /// The DPI_AWARENESS_CONTEXT handle to examine. /// The DPI value associated with the DPI_AWARENESS_CONTEXT handle. /// /// DPI_AWARENESS_CONTEXT handles associated with values of DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE and /// DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 will return a value of 0 for their DPI. This is because the DPI of a /// per-monitor-aware window can change, and the actual DPI cannot be returned without the window's HWND. /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getdpifromdpiawarenesscontext UINT // GetDpiFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT value ); [DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "E47A7A12-AE11-4E66-AE49-463C9F4A6330")] public static extern uint GetDpiFromDpiAwarenessContext(DPI_AWARENESS_CONTEXT value); /// Gets the DPI_AWARENESS_CONTEXT for the current thread. /// The current DPI_AWARENESS_CONTEXT for the thread. /// /// This method will return the latest DPI_AWARENESS_CONTEXT sent to SetThreadDpiAwarenessContext. If /// SetThreadDpiAwarenessContext was never called for this thread, then the return value will equal the default /// DPI_AWARENESS_CONTEXT for the process. /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getthreaddpiawarenesscontext DPI_AWARENESS_CONTEXT // GetThreadDpiAwarenessContext( ); [DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "DE86D551-974F-4A03-BDBE-348592CAB81F")] public static extern DPI_AWARENESS_CONTEXT GetThreadDpiAwarenessContext(); /// Retrieves the DPI_HOSTING_BEHAVIOR from the current thread. /// The DPI_HOSTING_BEHAVIOR of the current thread. /// /// This API returns the hosting behavior set by an earlier call of SetThreadDpiHostingBehavior, or /// DPI_HOSTING_BEHAVIOR_DEFAULT if no earlier call has been made. /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getthreaddpihostingbehavior DPI_HOSTING_BEHAVIOR // GetThreadDpiHostingBehavior( ); [DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "B9500745-9B53-47FF-9F45-0BFF3A66FD46")] public static extern DPI_HOSTING_BEHAVIOR GetThreadDpiHostingBehavior(); /// Returns the DPI_AWARENESS_CONTEXT associated with a window. /// The window to query. /// The DPI_AWARENESS_CONTEXT for the provided window. If the window is not valid, the return value is NULL. /// /// Important The return value of GetWindowDpiAwarenessContext is not affected by the DPI_AWARENESS of the current /// thread. It only indicates the context of the window specified by the hwnd input parameter. /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowdpiawarenesscontext DPI_AWARENESS_CONTEXT // GetWindowDpiAwarenessContext( HWND hwnd ); [DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "BCBC6EC7-9792-43C0-BE0E-D94F00A7CAFD")] public static extern DPI_AWARENESS_CONTEXT GetWindowDpiAwarenessContext(HWND hwnd); /// Returns the DPI_HOSTING_BEHAVIOR of the specified window. /// The handle for the window to examine. /// The DPI_HOSTING_BEHAVIOR of the specified window. /// /// This API allows you to examine the hosting behavior of a window after it has been created. A window's hosting behavior is the /// hosting behavior of the thread in which the window was created, as set by a call to SetThreadDpiHostingBehavior. This is a /// permanent value and cannot be changed after the window is created, even if the thread's hosting behavior is changed. /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowdpihostingbehavior DPI_HOSTING_BEHAVIOR // GetWindowDpiHostingBehavior( HWND hwnd ); [DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "BD16F545-54A1-479A-BA4B-F54834043EB2")] public static extern DPI_HOSTING_BEHAVIOR GetWindowDpiHostingBehavior(HWND hwnd); /// Determines if a specified DPI_AWARENESS_CONTEXT is valid and supported by the current system. /// The context that you want to determine if it is supported. /// TRUE if the provided context is supported, otherwise FALSE. /// /// /// IsValidDpiAwarenessContext determines the validity of any provided DPI_AWARENESS_CONTEXT. You should make sure a /// context is valid before using SetThreadDpiAwarenessContext to that context. /// /// An input value of NULL is considered to be an invalid context and will result in a return value of FALSE. /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-isvaliddpiawarenesscontext BOOL // IsValidDpiAwarenessContext( DPI_AWARENESS_CONTEXT value ); [DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "66F48B95-DEF4-4422-BF4F-5EBA3C713A80")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool IsValidDpiAwarenessContext(DPI_AWARENESS_CONTEXT value); /// /// Converts a point in a window from logical coordinates into physical coordinates, regardless of the dots per inch (dpi) awareness /// of the caller. For more information about DPI awareness levels, see PROCESS_DPI_AWARENESS. /// /// A handle to the window whose transform is used for the conversion. /// /// A pointer to a POINT structure that specifies the logical coordinates to be converted. The new physical coordinates are copied /// into this structure if the function succeeds. /// /// Returns TRUE if successful, or FALSE otherwise. /// /// /// In Windows 8, system–DPI aware applications translated between physical and logical space using PhysicalToLogicalPoint and /// LogicalToPhysicalPoint. In Windows 8.1, the additional virtualization of the system and inter-process communications means that /// for the majority of applications, you do not need these APIs. As a result, in Windows 8.1, these APIs no longer transform points. /// The system returns all points to an application in its own coordinate space. This behavior preserves functionality for the /// majority of applications, but there are some exceptions in which you must make changes to ensure that the application works as expected. /// /// /// For example, an application might need to walk the entire window tree of another process and ask the system for DPI-dependent /// information about the window. By default, the system will return the information based on the DPI awareness of the caller. This /// is ideal for most applications. However, the caller might need the information based on the DPI awareness of the application /// associated with the window. This might be necessary because the two applications send DPI-dependent information between each /// other directly. In this case, the application can use LogicalToPhysicalPointForPerMonitorDPI to get physical coordinates /// and then use PhysicalToLogicalPointForPerMonitorDPI to convert the physical coordinates into logical coordinates based on the /// DPI-awareness of the provided HWND. /// /// /// Consider two applications, one has a PROCESS_DPI_AWARENESS value of PROCESS_DPI_UNAWARE and the other has a value of /// PROCESS_PER_MONITOR_AWARE. The PROCESS_DPI_UNAWARE app creates a window on a single monitor where the scale factor /// is 200% (192 DPI). If both apps call GetWindowRect on this window, they will receive different values. The /// PROCESS_DPI_UNAWARE app will receive a rect based on 96 DPI coordinates, while the PROCESS_PER_MONITOR_AWARE app /// will receive coordinates matching the actual DPI of the monitor. If the PROCESS_PER_MONITOR_AWARE needs the rect that the /// system returned to the PROCESS_DPI_UNAWARE app, it could call LogicalToPhysicalPointForPerMonitorDPI for the /// corners of its rect and pass in the handle to the PROCESS_DPI_UNAWARE app's window. This will return points based on the /// other app's awareness that can be used to create a rect. /// /// /// Tip Since an application with a PROCESS_DPI_AWARENESS value of PROCESS_PER_MONITOR_AWARE uses the actual DPI of the /// monitor, physical and logical coordinates are the same for this app. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-logicaltophysicalpointforpermonitordpi BOOL // LogicalToPhysicalPointForPerMonitorDPI( HWND hWnd, LPPOINT lpPoint ); [DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "C9ABDC73-1E96-42F1-B34D-3A649DDF02A6")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool LogicalToPhysicalPointForPerMonitorDPI(HWND hWnd, ref POINT lpPoint); /// /// Converts a point in a window from logical coordinates into physical coordinates, regardless of the dots per inch (dpi) awareness /// of the caller. For more information about DPI awareness levels, see PROCESS_DPI_AWARENESS. /// /// A handle to the window whose transform is used for the conversion. /// /// A pointer to a POINT structure that specifies the physical/screen coordinates to be converted. The new logical coordinates are /// copied into this structure if the function succeeds. /// /// Returns TRUE if successful, or FALSE otherwise. /// /// /// In Windows 8, system–DPI aware applications translate between physical and logical space using PhysicalToLogicalPoint and /// LogicalToPhysicalPoint. In Windows 8.1, the additional virtualization of the system and inter-process communications means that /// for the majority of applications, you do not need these APIs. As a result, in Windows 8.1, these APIs no longer transform points. /// The system returns all points to an application in its own coordinate space. This behavior preserves functionality for the /// majority of applications, but there are some exceptions in which you must make changes to ensure that the application works as expected. /// /// /// For example, an application might need to walk the entire window tree of another process and ask the system for DPI-dependent /// information about the window. By default, the system will return the information based on the DPI awareness of the caller. This /// is ideal for most applications. However, the caller might need the information based on the DPI awareness of the application /// associated with the window. This might be necessary because the two applications send DPI-dependent information between each /// other directly. In this case, the application can use LogicalToPhysicalPointForPerMonitorDPI to get physical coordinates and then /// use PhysicalToLogicalPointForPerMonitorDPI to convert the physical coordinates into logical coordinates based on the /// DPI-awareness of the provided HWND. /// /// /// Consider two applications, one has a PROCESS_DPI_AWARENESS value of PROCESS_DPI_UNAWARE and the other has a value of /// PROCESS_PER_MONITOR_AWARE. The PROCESS_PER_MONITOR_AWARE app creates a window on a single monitor where the scale /// factor is 200% (192 DPI). If both apps call GetWindowRect on this window, they will receive different values. The /// PROCESS_DPI_UNAWARE app will receive a rect based on 96 DPI coordinates, while the PROCESS_PER_MONITOR_AWARE app /// will receive coordinates matching the actual DPI of the monitor. If the PROCESS_DPI_UNAWARE needs the rect that the system /// returned to the PROCESS_PER_MONITOR_AWARE app, it could call LogicalToPhysicalPointForPerMonitorDPI for the corners of its /// rect and pass in a handle to the PROCESS_PER_MONITOR_AWARE app's window. This will return points based on the other app's /// awareness that can be used to create a rect. This works because since a PROCESS_PER_MONITOR_AWARE uses the actual DPI of /// the monitor, logical and physical coordinates are identical. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-physicaltologicalpointforpermonitordpi BOOL // PhysicalToLogicalPointForPerMonitorDPI( HWND hWnd, LPPOINT lpPoint ); [DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "DC744BFC-4410-4878-BEA7-382550DDF9E3")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool PhysicalToLogicalPointForPerMonitorDPI(HWND hWnd, ref POINT lpPoint); /// Overrides the default per-monitor DPI scaling behavior of a child window in a dialog. /// A handle for the window whose behavior will be modified. /// A mask specifying the subset of flags to be changed. /// The desired value to be set for the specified subset of flags. /// /// /// This function returns TRUE if the operation was successful, and FALSE otherwise. To get extended error information, call GetLastError. /// /// /// Possible errors are ERROR_INVALID_HANDLE if passed an invalid HWND, and ERROR_ACCESS_DENIED if the windows belongs /// to another process. /// /// /// /// /// The behaviors are specified as values from the DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS enum. This function follows the typical /// two-parameter approach to setting flags, where a mask specifies the subset of the flags to be changed. /// /// /// It is valid to set these behaviors on any window. It does not matter if the window is currently a child of a dialog at the point /// in time that SetDialogControlDpiChangeBehavior is called. The behaviors are retained and will take effect only when the window is /// an immediate child of a dialog that has per-monitor DPI scaling enabled. /// /// /// This API influences individual controls within dialogs. The dialog-wide per-monitor DPI scaling behavior is controlled by SetDialogDpiChangeBehavior. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setdialogcontroldpichangebehavior BOOL // SetDialogControlDpiChangeBehavior( HWND hWnd, DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS mask, DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS values ); [DllImport(Lib.User32, SetLastError = true, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "52BB557B-0D70-4189-9BD0-EB94188EA4E7")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetDialogControlDpiChangeBehavior(HWND hWnd, DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS mask, DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS values); /// /// Dialogs in Per-Monitor v2 contexts are automatically DPI scaled. This method lets you customize their DPI change behavior. /// /// This function works in conjunction with the DIALOG_DPI_CHANGE_BEHAVIORS enum in order to override the default DPI scaling /// behavior for dialogs. This function is called on a specified dialog, for which the specified flags are individually saved. /// /// /// This function does not affect the DPI scaling behavior for the child windows of the dialog in question - that is done with SetDialogControlDpiChangeBehavior. /// /// /// A handle for the dialog whose behavior will be modified. /// A mask specifying the subset of flags to be changed. /// The desired value to be set for the specified subset of flags. /// /// /// This function returns TRUE if the operation was successful, and FALSE otherwise. To get extended error information, call GetLastError. /// /// /// Possible errors are ERROR_INVALID_HANDLE if passed an invalid dialog HWND, and ERROR_ACCESS_DENIED if the dialog /// belongs to another process. /// /// /// /// /// For extensibility, DIALOG_DPI_CHANGE_BEHAVIORS was modeled as a set of bit-flags representing separate behaviors. This function /// follows the typical two-parameter approach to setting flags, where a mask specifies the subset of the flags to be changed. /// /// /// It is not an error to call this API outside of Per Monitor v2 contexts, though the flags will have no effect on the behavior of /// the specified dialog until the context is changed to Per Monitor v2. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setdialogdpichangebehavior BOOL // SetDialogDpiChangeBehavior( HWND hDlg, DIALOG_DPI_CHANGE_BEHAVIORS mask, DIALOG_DPI_CHANGE_BEHAVIORS values ); [DllImport(Lib.User32, SetLastError = true, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "48A13F57-9D82-4F79-962B-FBD02FFF9B39")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetDialogDpiChangeBehavior(HWND hDlg, DIALOG_DPI_CHANGE_BEHAVIORS mask, DIALOG_DPI_CHANGE_BEHAVIORS values); /// /// /// It is recommended that you set the process-default DPI awareness via application manifest. See Setting the default DPI awareness /// for a process for more information. Setting the process-default DPI awareness via API call can lead to unexpected application behavior. /// /// /// Sets the current process to a specified dots per inch (dpi) awareness context. The DPI awareness contexts are from the /// DPI_AWARENESS_CONTEXT value. /// /// /// A DPI_AWARENESS_CONTEXT handle to set. /// /// /// This function returns TRUE if the operation was successful, and FALSE otherwise. To get extended error information, call GetLastError. /// /// /// Possible errors are ERROR_INVALID_PARAMETER for an invalid input, and ERROR_ACCESS_DENIED if the default API /// awareness mode for the process has already been set (via a previous API call or within the application manifest). /// /// /// /// /// This API is a more advanced version of the previously existing SetProcessDpiAwareness API, allowing for the process default to be /// set to the finer-grained DPI_AWARENESS_CONTEXT values. Most importantly, this allows you to programmatically set Per Monitor /// v2 as the process default value, which is not possible with the previous API. /// /// /// This method sets the default DPI_AWARENESS_CONTEXT for all threads within an application. Individual threads can have their DPI /// awareness changed from the default with the SetThreadDpiAwarenessContext method. /// /// /// Important In general, it is recommended to not use SetProcessDpiAwarenessContext to set the DPI awareness for your /// application. If possible, you should declare the DPI awareness for your application in the application manifest. For more /// information, see Setting the default DPI awareness for a process. /// /// /// You must call this API before you call any APIs that depend on the DPI awareness (including before creating any UI in your /// process). Once API awareness is set for an app, any future calls to this API will fail. This is true regardless of whether you /// set the DPI awareness in the manifest or by using this API. /// /// If the DPI awareness level is not set, the default value is DPI_AWARENESS_CONTEXT_UNAWARE. /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setprocessdpiawarenesscontext BOOL // SetProcessDpiAwarenessContext( DPI_AWARENESS_CONTEXT value ); [DllImport(Lib.User32, SetLastError = true, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "EACD1784-BEFF-46C1-8665-CBC86A65833C")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT value); /// Set the DPI awareness for the current thread to the provided value. /// The new DPI_AWARENESS_CONTEXT for the current thread. This context includes the DPI_AWARENESS value. /// /// The old DPI_AWARENESS_CONTEXT for the thread. If the dpiContext is invalid, the thread will not be updated and the return value /// will be NULL. You can use this value to restore the old DPI_AWARENESS_CONTEXT after overriding it with a predefined value. /// /// Use this API to change the DPI_AWARENESS_CONTEXT for the thread from the default value for the app. // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setthreaddpiawarenesscontext DPI_AWARENESS_CONTEXT // SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT dpiContext ); [DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "95531BDC-3D45-4BB6-8C63-0D845C66B88F")] public static extern DPI_AWARENESS_CONTEXT SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT dpiContext); /// /// Sets the thread's DPI_HOSTING_BEHAVIOR. This behavior allows windows created in the thread to host child windows with a different DPI_AWARENESS_CONTEXT. /// /// The new DPI_HOSTING_BEHAVIOR value for the current thread. /// /// The previous DPI_HOSTING_BEHAVIOR for the thread. If the hosting behavior passed in is invalid, the thread will not be updated /// and the return value will be DPI_HOSTING_BEHAVIOR_INVALID. You can use this value to restore the old /// DPI_HOSTING_BEHAVIOR after overriding it with a predefined value. /// /// /// /// DPI_HOSTING_BEHAVIOR enables a mixed content hosting behavior, which allows parent windows created in the thread to host child /// windows with a different DPI_AWARENESS_CONTEXT value. This property only effects new windows created within this thread while the /// mixed hosting behavior is active. A parent window with this hosting behavior is able to host child windows with different /// DPI_AWARENESS_CONTEXT values, regardless of whether the child windows have mixed hosting behavior enabled. /// /// /// This hosting behavior does not allow for windows with per-monitor DPI_AWARENESS_CONTEXT values to be hosted until windows /// with DPI_AWARENESS_CONTEXT values of system or unaware. /// /// /// To avoid unexpected outcomes, a thread's DPI_HOSTING_BEHAVIOR should be changed to support mixed hosting behaviors only /// when creating a new window which needs to support those behaviors. Once that window is created, the hosting behavior should be /// switched back to its default value. /// /// /// This API is used to change the thread's DPI_HOSTING_BEHAVIOR from its default value. This is only necessary if your app /// needs to host child windows from plugins and third-party components that do not support per-monitor-aware context. This is most /// likely to occur if you are updating complex applications to support per-monitor DPI_AWARENESS_CONTEXT behaviors. /// /// /// Enabling mixed hosting behavior will not automatically adjust the thread's DPI_AWARENESS_CONTEXT to be compatible with /// legacy content. The thread's awareness context must still be manually changed before new windows are created to host such content. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setthreaddpihostingbehavior DPI_HOSTING_BEHAVIOR // SetThreadDpiHostingBehavior( DPI_HOSTING_BEHAVIOR value ); [DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)] [PInvokeData("winuser.h", MSDNShortId = "CF31D96A-EC84-4911-81A2-82EC90D417B9")] public static extern DPI_HOSTING_BEHAVIOR SetThreadDpiHostingBehavior(DPI_HOSTING_BEHAVIOR value); /// Provides a handle to a DPI awareness context. [StructLayout(LayoutKind.Sequential)] public struct DPI_AWARENESS_CONTEXT : IHandle { private IntPtr handle; /// Initializes a new instance of the struct. /// An object that represents the pre-existing handle to use. public DPI_AWARENESS_CONTEXT(IntPtr preexistingHandle) => handle = preexistingHandle; /// Returns an invalid handle by instantiating a object with . public static DPI_AWARENESS_CONTEXT NULL => new DPI_AWARENESS_CONTEXT(IntPtr.Zero); /// Gets a value indicating whether this instance is a null handle. public bool IsNull => handle == IntPtr.Zero; /// Performs an explicit conversion from to . /// The handle. /// The result of the conversion. public static explicit operator IntPtr(DPI_AWARENESS_CONTEXT h) => h.handle; /// Performs an implicit conversion from to . /// The pointer to a handle. /// The result of the conversion. public static implicit operator DPI_AWARENESS_CONTEXT(IntPtr h) => new DPI_AWARENESS_CONTEXT(h); /// Implements the operator !=. /// The first handle. /// The second handle. /// The result of the operator. public static bool operator !=(DPI_AWARENESS_CONTEXT h1, DPI_AWARENESS_CONTEXT h2) => !(h1 == h2); /// Implements the operator ==. /// The first handle. /// The second handle. /// The result of the operator. public static bool operator ==(DPI_AWARENESS_CONTEXT h1, DPI_AWARENESS_CONTEXT h2) => h1.Equals(h2); /// public override bool Equals(object obj) => obj is DPI_AWARENESS_CONTEXT h ? handle == h.handle : false; /// public override int GetHashCode() => handle.GetHashCode(); /// public IntPtr DangerousGetHandle() => handle; } } }