169 lines
8.4 KiB
Markdown
169 lines
8.4 KiB
Markdown
|
|
---
|
|||
|
|
source_files:
|
|||
|
|
- Common/DTS.Common/Classes/WinApi/WindowsAPIHelpers.cs
|
|||
|
|
generated_at: "2026-04-16T03:16:58.945801+00:00"
|
|||
|
|
model: "Qwen/Qwen3-Coder-Next-FP8"
|
|||
|
|
schema_version: 1
|
|||
|
|
sha256: "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 window’s 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`**
|
|||
|
|
```csharp
|
|||
|
|
[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`**
|
|||
|
|
```csharp
|
|||
|
|
[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`**
|
|||
|
|
```csharp
|
|||
|
|
[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`**
|
|||
|
|
```csharp
|
|||
|
|
[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`**
|
|||
|
|
```csharp
|
|||
|
|
[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`**
|
|||
|
|
```csharp
|
|||
|
|
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`**
|
|||
|
|
```csharp
|
|||
|
|
public enum SWP { NOMOVE = 0x0002; }
|
|||
|
|
```
|
|||
|
|
Flags for `SetWindowPos`. `NOMOVE` preserves current position.
|
|||
|
|
|
|||
|
|
#### Methods
|
|||
|
|
|
|||
|
|
- **`GetMinMaxInfo(IntPtr hwnd, IntPtr lParam)`**
|
|||
|
|
```csharp
|
|||
|
|
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`**
|
|||
|
|
```csharp
|
|||
|
|
[DllImport("user32")]
|
|||
|
|
public static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);
|
|||
|
|
```
|
|||
|
|
Retrieves monitor information. Caller must initialize `MONITORINFO.cbSize` before calling.
|
|||
|
|
|
|||
|
|
- **`MonitorFromWindow`**
|
|||
|
|
```csharp
|
|||
|
|
[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 monitor’s 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.
|