Files
2026-04-17 14:55:32 -04:00

8.4 KiB
Raw Permalink Blame History

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
Common/DTS.Common/Classes/WinApi/WindowsAPIHelpers.cs
2026-04-16T03:16:58.945801+00:00 Qwen/Qwen3-Coder-Next-FP8 1 32ac28362ec2b57c

WinApi

Documentation: WindowsAPIHelpers.cs


1. Purpose

This module provides interoperability helpers for Windows API integration, specifically to support custom window sizing and positioning behavior in WPF applications. It defines P/Invoke-compatible structures (POINT, RECT, MINMAXINFO, MONITORINFO, WINDOWPOS, WM, SWP) and exposes two Win32 functions (GetMonitorInfo, MonitorFromWindow) to enable accurate adjustment of a windows maximized size and position to match the work area of the monitor on which the window resides—rather than the full screen (which may include taskbars or other non-client areas). This is typically used in response to the WM_GETMINMAXINFO message to prevent maximized windows from overlapping system UI elements.


2. Public Interface

Structs

  • POINT

    [StructLayout(LayoutKind.Sequential)]
    public struct POINT { public int x; public int y; public POINT(int x, int y); }
    

    Represents a point in 2D space with integer coordinates. Used as a field in other structures.

  • RECT

    [StructLayout(LayoutKind.Sequential, Pack = 0)]
    public struct RECT
    {
        public int left, top, right, bottom;
        public static readonly RECT Empty;
        public int Width { get; }
        public int Height { get; }
        public RECT(int left, int top, int right, int bottom);
        public bool IsEmpty { get; }
        public override string ToString();
        public override bool Equals(object obj);
        public override int GetHashCode();
        public static bool operator ==(RECT, RECT);
        public static bool operator !=(RECT, RECT);
    }
    

    Represents a rectangle with integer coordinates. Includes computed Width and Height properties, equality operators, and an IsEmpty check (true if left >= right or top >= bottom). Note: Height is computed as bottom - top (not Math.Abs), so negative heights are possible if bottom < top.

  • MINMAXINFO

    [StructLayout(LayoutKind.Sequential)]
    public struct MINMAXINFO
    {
        public POINT ptReserved;
        public POINT ptMaxSize;
        public POINT ptMaxPosition;
        public POINT ptMinTrackSize;
        public POINT ptMaxTrackSize;
    }
    

    Used to convey minimum/maximum tracking and maximized window geometry. Populated by GetMinMaxInfo.

  • MONITORINFO

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public class MONITORINFO
    {
        public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));
        public RECT rcMonitor = new RECT();
        public RECT rcWork = new RECT();
        public int dwFlags = 0;
    }
    

    Contains monitor-specific information. cbSize is auto-initialized to the unmanaged size of the struct. rcMonitor is the full monitor rectangle; rcWork is the work area (excluding taskbars, etc.).

  • WINDOWPOS

    [StructLayout(LayoutKind.Sequential)]
    public struct WINDOWPOS
    {
        public IntPtr hwnd;
        public IntPtr hwndInsertAfter;
        public int x, y, cx, cy;
        public int flags;
    }
    

    Used in WM_WINDOWPOSCHANGING/WM_WINDOWPOSCHANGED messages. Not used directly in this file but defined for completeness.

Enums

  • WM

    public enum WM { WINDOWMAX = 0x0024, WINDOWPOSCHANGING = 0x0046; }
    

    Windows message constants. WINDOWMAX is likely a typo or nonstandard alias (standard is WM_SYSCOMMAND with SC_MAXIMIZE, or WM_SIZE with SIZE_MAXIMIZED). WINDOWPOSCHANGING is WM_WINDOWPOSCHANGING.

  • SWP

    public enum SWP { NOMOVE = 0x0002; }
    

    Flags for SetWindowPos. NOMOVE preserves current position.

Methods

  • GetMinMaxInfo(IntPtr hwnd, IntPtr lParam)
    public static void GetMinMaxInfo(IntPtr hwnd, IntPtr lParam)
    
    Handles the WM_GETMINMAXINFO message by adjusting ptMaxSize and ptMaxPosition in the MINMAXINFO structure to fit the work area of the monitor containing hwnd. Uses MonitorFromWindow with MONITOR_DEFAULTTONEAREST (0x00000002) to locate the monitor, then calls GetMonitorInfo to retrieve monitor geometry. Writes the modified MINMAXINFO back to lParam.

P/Invoke Exports

  • GetMonitorInfo

    [DllImport("user32")]
    public static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);
    

    Retrieves monitor information. Caller must initialize MONITORINFO.cbSize before calling.

  • MonitorFromWindow

    [DllImport("User32")]
    public static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);
    

    Returns a handle to the monitor that contains the window. flags is typically MONITOR_DEFAULTTONEAREST (0x00000002).


3. Invariants

  • MONITORINFO.cbSize must be set to Marshal.SizeOf(typeof(MONITORINFO)) before calling GetMonitorInfo; otherwise, the call will fail (returns false).
  • RECT.IsEmpty is defined as left >= right || top >= bottom. This implies a rectangle with left == right or top == bottom is considered empty.
  • RECT.Height is computed as bottom - top (not Math.Abs(bottom - top)), so if bottom < top, Height is negative. This may indicate an inverted rectangle (e.g., from drag-select), but the code does not enforce non-negative height.
  • GetMinMaxInfo assumes the window is on a valid monitor. If MonitorFromWindow returns IntPtr.Zero, no adjustment is made, and the original MINMAXINFO values are preserved.
  • The ptMaxPosition values are computed as absolute offsets from the monitors left/top edge (Math.Abs(rcWorkArea.left - rcMonitorArea.left)), which correctly yields the top-left corner of the work area relative to the monitor.

4. Dependencies

Dependencies on this module:

  • WPF/Win32 interop layer: This module is intended for use in WPF applications (evidenced by System.Windows namespace usage, though not directly referenced in this file). Likely consumed by window message handlers (e.g., Window.SourceInitialized or OnSourceInitialized overrides) to subclass window procedures and handle WM_GETMINMAXINFO.
  • System.Runtime.InteropServices: Required for StructLayout, DllImport, Marshal.PtrToStructure, and Marshal.StructureToPtr.

Dependencies of this module:

  • user32.dll: For GetMonitorInfo and MonitorFromWindow.
  • No external libraries beyond .NET Framework core types (no NuGet dependencies implied).

Known consumers (inferred):

  • Any class handling WM_GETMINMAXINFO (e.g., via HwndSource.AddHook) will call WindowsAPIHelpers.GetMinMaxInfo.
  • Likely used in custom window management logic (e.g., MainWindow.xaml.cs or a base window class).

5. Gotchas

  • RECT.Height is not absolute: Height => bottom - top (not Math.Abs). This may cause unexpected negative heights if rectangles are inverted. Use Math.Abs externally if needed.
  • MONITORINFO is a class, not a struct: This is unusual for P/Invoke marshaling (typically struct is preferred). While it works due to StructLayout, it introduces heap allocation and reference semantics. Ensure the instance is not reused across threads without synchronization.
  • WINDOWMAX enum value is nonstandard: The Win32 constant for maximization is WM_SYSCOMMAND with SC_MAXIMIZE (0xF030), not 0x0024. 0x0024 is WM_USER + 36 in some contexts but not a standard system message. This may be a typo or internal alias.
  • rcMonitor vs rcWork semantics: rcMonitor is the full monitor bounds; rcWork excludes taskbars, etc. The code correctly uses rcWork for ptMaxSize/ptMaxPosition, but callers must understand this distinction.
  • No validation of lParam in GetMinMaxInfo: Assumes lParam points to a valid MINMAXINFO structure. Passing IntPtr.Zero or invalid memory will cause a crash.
  • Missing WM constants: Only two WM values are defined (WINDOWMAX, WINDOWPOSCHANGING). Other common messages (e.g., WM_SIZE, WM_GETMINMAXINFO) are not included, suggesting this is a partial set.
  • MONITOR_DEFAULTTONEAREST flag is hardcoded: The MonitorFromWindow call uses 0x00000002 directly instead of a named constant (e.g., MONITOR_DEFAULTTONEAREST = 2). While correct, it reduces readability.

None identified beyond these.