init
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.CommonCore/Classes/WinApi/WindowsAPIHelpers.cs
|
||||
generated_at: "2026-04-16T02:41:05.548844+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "74033c59308d77b1"
|
||||
---
|
||||
|
||||
# WinApi
|
||||
|
||||
## Documentation: `WindowsAPIHelpers.cs`
|
||||
|
||||
---
|
||||
|
||||
### 1. **Purpose**
|
||||
|
||||
This module provides low-level Windows API interop helpers for managing window placement and sizing behavior, specifically to ensure that maximized windows align with the *work area* (i.e., excluding taskbar, docked toolbars) of the appropriate monitor in multi-monitor setups. It defines P/Invoke signatures and supporting structures (`POINT`, `RECT`, `MINMAXINFO`, `MONITORINFO`, `WINDOWPOS`) and exposes a helper method `GetMinMaxInfo` that adjusts the `ptMaxSize` and `ptMaxPosition` fields of a `MINMAXINFO` structure during a `WM_GETMINMAXINFO` message. This ensures windows maximize correctly to the visible screen area of the monitor containing the window, rather than the primary monitor’s full screen bounds.
|
||||
|
||||
---
|
||||
|
||||
### 2. **Public Interface**
|
||||
|
||||
#### Structs & Classes
|
||||
|
||||
- **`POINT`**
|
||||
```csharp
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct POINT { public int x; public int y; public POINT(int x, int y); }
|
||||
```
|
||||
Represents a point in screen coordinates. Used as a field in `MINMAXINFO` and elsewhere.
|
||||
|
||||
- **`MINMAXINFO`**
|
||||
```csharp
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MINMAXINFO
|
||||
{
|
||||
public POINT ptReserved;
|
||||
public POINT ptMaxSize;
|
||||
public POINT ptMaxPosition;
|
||||
public POINT ptMinTrackSize;
|
||||
public POINT ptMaxTrackSize;
|
||||
}
|
||||
```
|
||||
Used in `WM_GETMINMAXINFO` to specify minimum/maximum tracking sizes and maximized window geometry. The `ptMaxSize` and `ptMaxPosition` fields are modified 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;
|
||||
}
|
||||
```
|
||||
Container for monitor-specific information. `cbSize` is auto-initialized to the correct size. `rcMonitor` holds the full monitor bounds; `rcWork` holds the work area (usable screen space).
|
||||
|
||||
- **`RECT`**
|
||||
```csharp
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0)]
|
||||
public struct RECT
|
||||
{
|
||||
public int left, top, right, bottom;
|
||||
public static readonly RECT Empty;
|
||||
public int Width => Math.Abs(right - left);
|
||||
public int Height => bottom - top;
|
||||
public bool IsEmpty => left >= right || top >= bottom;
|
||||
// ... constructors, equality, operators ...
|
||||
}
|
||||
```
|
||||
Represents a rectangle in screen coordinates. Includes computed properties (`Width`, `Height`, `IsEmpty`) and value-based equality (`==`, `!=`, `Equals`, `GetHashCode`). Note: `Height` is computed as `bottom - top` (not `Math.Abs`), so negative heights are possible if `bottom < top`.
|
||||
|
||||
- **`WINDOWPOS`**
|
||||
```csharp
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct WINDOWPOS
|
||||
{
|
||||
public IntPtr hwnd;
|
||||
public IntPtr hwndInsertAfter;
|
||||
public int x, y, cx, cy;
|
||||
public int flags;
|
||||
}
|
||||
```
|
||||
Mirrors the Win32 `WINDOWPOS` structure used in `WM_WINDOWPOSCHANGING`/`WM_WINDOWPOSCHANGED`.
|
||||
|
||||
#### Enums
|
||||
|
||||
- **`WM`**
|
||||
```csharp
|
||||
public enum WM
|
||||
{
|
||||
WINDOWMAX = 0x0024,
|
||||
WINDOWPOSCHANGING = 0x0046
|
||||
}
|
||||
```
|
||||
Subset of Windows message constants. *Note:* `WINDOWMAX` is likely a typo/misnomer for `WM_WINDOWMAXIMIZED` (which does not exist); standard `WM_SYSCOMMAND` with `SC_MAXIMIZE` is more common. `WINDOWPOSCHANGING` is correctly `WM_WINDOWPOSCHANGING`.
|
||||
|
||||
- **`SWP`**
|
||||
```csharp
|
||||
public enum SWP
|
||||
{
|
||||
NOMOVE = 0x0002
|
||||
}
|
||||
```
|
||||
Subset of `SetWindowPos` flags. `NOMOVE` preserves current position when resizing.
|
||||
|
||||
#### Methods
|
||||
|
||||
- **`GetMinMaxInfo(IntPtr hwnd, IntPtr lParam)`**
|
||||
```csharp
|
||||
public static void GetMinMaxInfo(IntPtr hwnd, IntPtr lParam)
|
||||
```
|
||||
Reads a `MINMAXINFO` structure from `lParam`, queries the monitor containing `hwnd`, retrieves its work area (`rcWork`) and full monitor area (`rcMonitor`), then updates `mmi.ptMaxPosition` and `mmi.ptMaxSize` to align the maximized window with the work area of the *current* monitor. Writes the modified structure back to `lParam`. This is intended to be called in response to `WM_GETMINMAXINFO` (0x0024).
|
||||
|
||||
- **`GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi)`**
|
||||
```csharp
|
||||
[DllImport("user32")]
|
||||
public static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);
|
||||
```
|
||||
P/Invoke wrapper for `GetMonitorInfoW`. Fills `lpmi` with monitor data. Caller must set `lpmi.cbSize` (handled by `MONITORINFO`’s field initializer).
|
||||
|
||||
- **`MonitorFromWindow(IntPtr handle, int flags)`**
|
||||
```csharp
|
||||
[DllImport("User32")]
|
||||
public static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);
|
||||
```
|
||||
P/Invoke wrapper for `MonitorFromWindow`. Returns `IntPtr.Zero` on failure. Used with `MONITOR_DEFAULTTONEAREST` (`0x00000002`).
|
||||
|
||||
---
|
||||
|
||||
### 3. **Invariants**
|
||||
|
||||
- **`MONITORINFO.cbSize` must be set correctly before calling `GetMonitorInfo`**:
|
||||
The `MONITORINFO` class initializes `cbSize` to `Marshal.SizeOf(typeof(MONITORINFO))` in its field initializer, ensuring correctness for P/Invoke.
|
||||
|
||||
- **`RECT` dimensions assume left ≤ right and top ≤ bottom**:
|
||||
`Width` uses `Math.Abs(right - left)`, but `Height` does *not* (`bottom - top`). If `bottom < top`, `Height` will be negative. No validation enforces non-negative dimensions.
|
||||
|
||||
- **`GetMinMaxInfo` modifies `ptMaxSize` and `ptMaxPosition` only**:
|
||||
Other `MINMAXINFO` fields (`ptReserved`, `ptMinTrackSize`, `ptMaxTrackSize`) are preserved as-is.
|
||||
|
||||
- **Monitor query uses `MONITOR_DEFAULTTONEAREST`**:
|
||||
If `hwnd` is invalid or no monitor contains it, `MonitorFromWindow` returns `IntPtr.Zero`, and `GetMinMaxInfo` skips modification (no crash, but no adjustment either).
|
||||
|
||||
---
|
||||
|
||||
### 4. **Dependencies**
|
||||
|
||||
- **Runtime Dependencies**:
|
||||
- `System.Runtime.InteropServices` (for `StructLayout`, `Marshal`, `DllImport`)
|
||||
- `System.Windows` (though no WPF types are used in this file—likely a legacy/unused reference)
|
||||
- Win32 `user32.dll` (for `GetMonitorInfo`, `MonitorFromWindow`)
|
||||
|
||||
- **Consumers (inferred)**:
|
||||
This module is designed to be used by code handling `WM_GETMINMAXINFO` (e.g., in a WPF/WinForms window procedure). The method `GetMinMaxInfo` is called with the window handle and `lParam` from the message. No other direct dependencies are visible in the source.
|
||||
|
||||
- **Missing Dependencies**:
|
||||
- `RECT` is used but not defined in this file—*this is a contradiction*. The source defines `RECT` here, but the `RECT` used in `MONITORINFO` is initialized as `new RECT()`. This implies `RECT` must be defined *here* (and it is), so no external dependency is needed.
|
||||
- No `using` for `System.Drawing` or other types—`RECT` is self-contained.
|
||||
|
||||
---
|
||||
|
||||
### 5. **Gotchas**
|
||||
|
||||
- **`RECT.Height` is not absolute**:
|
||||
`Height => bottom - top` (not `Math.Abs`). If `bottom < top`, `Height` is negative. This may cause unexpected behavior if consumers assume non-negative height.
|
||||
|
||||
- **`MONITORINFO` is a `class`, not a `struct`**:
|
||||
This is unusual for P/Invoke marshaling (where `struct` is typical). While it works due to `cbSize` initialization and `Marshal.PtrToStructure`/`StructureToPtr`, using a `class` here risks reference-type semantics (e.g., accidental sharing). A `struct` would be safer and more conventional.
|
||||
|
||||
- **`GetMinMaxInfo` silently fails if monitor query fails**:
|
||||
If `MonitorFromWindow` returns `IntPtr.Zero` (e.g., invalid `hwnd`), no adjustment occurs. No error is logged or thrown—consumers must verify behavior.
|
||||
|
||||
- **`WM.WINDOWMAX` is likely incorrect**:
|
||||
`0x0024` is `WM_SYSCOMMAND`, not a maximization message. `WM_GETMINMAXINFO` is `0x0024`—*this is the same value*. The enum name `WINDOWMAX` is misleading; it should be `GETMINMAXINFO`. This is a naming bug.
|
||||
|
||||
- **`RECT.IsEmpty` uses `>=` (not `>`)**:
|
||||
`IsEmpty => left >= right || top >= bottom` correctly handles degenerate rectangles (e.g., `left == right`), but consumers may overlook that empty rectangles have zero area.
|
||||
|
||||
- **No thread-safety guarantees**:
|
||||
`GetMinMaxInfo` mutates a `MINMAXINFO` via `Marshal.PtrToStructure`/`StructureToPtr`. While the operation is read-modify-write on a *copy* (safe), the use of `MONITORINFO` as a `class` (reference type) could introduce issues if reused across threads without copying.
|
||||
|
||||
- **`MONITORINFO.rcMonitor` and `rcWork` are initialized to `new RECT()`**:
|
||||
`RECT()` sets all fields to `0`, so `rcMonitor` and `rcWork` start as `(0,0,0,0)`. This is safe for P/Invoke since `GetMonitorInfo` overwrites them.
|
||||
|
||||
- **No handling of DPI scaling**:
|
||||
All coordinates are in *physical* pixels (Win32 convention). If the application is DPI-aware, callers must ensure `hwnd` corresponds to the correct DPI context. No DPI scaling is applied in `GetMinMaxInfo`.
|
||||
|
||||
---
|
||||
|
||||
*No other issues are apparent from the source alone.*
|
||||
Reference in New Issue
Block a user