docs/architecture/cross-cutting/win32-interop.md
WPF UI v4.2.0 | Cross-Cutting Concern
WPF UI relies heavily on Win32 interop to deliver Fluent Design features that are not natively available through the WPF framework. This includes DWM backdrop effects (Mica, Acrylic, Tabbed), dark mode title bars, window corner preferences, snap layout support, system tray icons, and taskbar progress indicators.
The interop layer follows a strict three-layer architecture that isolates raw platform calls from the rest of the library.
graph TB
subgraph "Layer 3 — High-Level Utilities & Controls"
FluentWindow["FluentWindow
<i>Backdrop, corner prefs</i>"]
TitleBar["TitleBar
<i>Custom chrome, snap layouts</i>"]
STW["SystemThemeWatcher
<i>WndProc hooks</i>"]
WBM["WindowBackgroundManager
<i>DWM backdrop effects</i>"]
AACM["ApplicationAccentColorManager
<i>WinRT UISettings</i>"]
TaskBar["TaskBarService
<i>COM ITaskbarList4</i>"]
NotifyIcon["NotifyIcon (Tray)
<i>Shell_NotifyIcon</i>"]
end
subgraph "Layer 2 — Managed Wrappers (Interop/)"
UNM["UnsafeNativeMethods.cs
<i>Handle validation + safe wrappers</i>"]
PI["PInvoke.cs
<i>Manual DllImport for
SetWindowLongPtr (x86/x64)</i>"]
UR["UnsafeReflection.cs
<i>Enum/struct unsafe casting</i>"]
end
subgraph "Layer 1 — CsWin32 Source Generation"
NMT["NativeMethods.txt
<i>35 function/type declarations</i>"]
CsWin32["CsWin32 Generator
<i>Produces Windows.Win32 namespace</i>"]
DWM["DwmSetWindowAttribute
DwmIsCompositionEnabled"]
User32["SetWindowLong
GetWindowLong
GetDpiForWindow"]
Shell32["Shell_NotifyIcon
ITaskbarList4"]
end
FluentWindow --> UNM
TitleBar --> UNM
STW --> UNM
WBM --> UNM
AACM --> UNM
TaskBar --> UNM
NotifyIcon --> UNM
UNM --> CsWin32
UNM --> PI
UNM --> UR
PI --> User32
NMT --> CsWin32
CsWin32 --> DWM
CsWin32 --> User32
CsWin32 --> Shell32
style FluentWindow fill:#fff4e1,stroke:#f57f17
style TitleBar fill:#fff4e1,stroke:#f57f17
style STW fill:#e8f5e9,stroke:#2e7d32
style WBM fill:#e8f5e9,stroke:#2e7d32
style AACM fill:#e8f5e9,stroke:#2e7d32
style TaskBar fill:#e1f5ff,stroke:#0277bd
style NotifyIcon fill:#e1f5ff,stroke:#0277bd
style UNM fill:#ffebee,stroke:#c62828
style PI fill:#ffebee,stroke:#c62828
style UR fill:#ffebee,stroke:#c62828
style NMT fill:#f3e5f5,stroke:#6a1b9a
style CsWin32 fill:#f3e5f5,stroke:#6a1b9a
style DWM fill:#e0e0e0,stroke:#616161
style User32 fill:#e0e0e0,stroke:#616161
style Shell32 fill:#e0e0e0,stroke:#616161
The project uses Microsoft's CsWin32 source generator to produce type-safe P/Invoke bindings at compile time.
NativeMethods.txt lists the Win32 functions and types needed by the library.Windows.Win32HWND, HRESULT, BOOL from Windows.Win32.FoundationKey generated functions:
| Function | Purpose |
|---|---|
DwmSetWindowAttribute | Apply backdrop effects, dark mode, corner preferences |
DwmIsCompositionEnabled | Check if DWM composition is active |
SetWindowLong / GetWindowLong | Manipulate window styles (32-bit) |
Shell_NotifyIcon | System tray icon management |
ITaskbarList4 | Taskbar progress overlay (COM interface) |
src/Wpf.Ui/Interop/)Managed wrappers provide validated, exception-safe access to native APIs.
UnsafeNativeMethods.cs -- Handle-Validated WrappersEvery method follows a defensive pattern:
IntPtr.ZeroPInvoke.IsWindow()false or nullThis pattern ensures that callers never receive unmanaged exceptions and that invalid window handles are rejected before reaching the OS.
UnsafeReflection.cs -- Unsafe Enum/Struct CastingProvides unsafe casting between managed enums/structs and their Win32 equivalents. Used where direct marshalling is insufficient or where performance-critical paths avoid boxing.
PInvoke.cs -- Custom P/Invoke DeclarationsContains hand-written P/Invoke declarations for functions that CsWin32 does not generate or generates with incompatible signatures. Example: SetWindowLongPtrW requires platform-specific handling (different entry points on 32-bit vs 64-bit Windows).
src/Wpf.Ui/Win32/)Utilities.cs -- OS Version DetectionProvides high-level queries about the running environment:
| Property | Logic |
|---|---|
IsOSWindows11OrNewer | OS build number >= 22000 |
IsCompositionEnabled | Calls DwmIsCompositionEnabled |
These checks gate feature availability so that controls degrade gracefully on older Windows versions.
| API | Usage | Key Functions |
|---|---|---|
| DWM | Backdrop effects (Mica/Acrylic/Tabbed), dark mode, corner preferences | DwmSetWindowAttribute, DwmIsCompositionEnabled |
| User32 | Window style manipulation, message pump interception, snap layouts | SetWindowLong, GetWindowLong, SetWindowLongPtr |
| Shell32 | System tray icons, taskbar progress | Shell_NotifyIcon, ITaskbarList4 COM |
| WinRT UISettings | System accent colors (8-color palette) | IUISettings3 COM interface |
| Registry | Fallback for accent colors, OS version detection | DWM\AccentColor, CurrentVersion |
| WndProc | Theme change detection, title bar hit testing | WM_THEMECHANGED, WM_DWMCOLORIZATIONCOLORCHANGED, WM_NCHITTEST |
The following diagram illustrates the typical call path from a consumer application through the interop layers to the Windows OS.
sequenceDiagram
participant App as Consumer App
participant Control as WPF UI Control
participant Unsafe as UnsafeNativeMethods
participant CsWin32 as CsWin32 PInvoke
participant OS as Windows OS
App->>Control: Set property (e.g., WindowBackdropType = Mica)
Control->>Control: Validate state and OS version
Control->>Unsafe: Call managed wrapper (e.g., ApplyWindowDarkMode)
Unsafe->>Unsafe: Check handle != IntPtr.Zero
Unsafe->>CsWin32: PInvoke.IsWindow(hwnd)
CsWin32->>OS: IsWindow()
OS-->>CsWin32: BOOL result
CsWin32-->>Unsafe: true/false
alt Handle is valid
Unsafe->>CsWin32: DwmSetWindowAttribute(hwnd, attr, value)
CsWin32->>OS: DwmSetWindowAttribute()
OS-->>CsWin32: HRESULT
CsWin32-->>Unsafe: success/failure
Unsafe-->>Control: true
else Handle is invalid or call fails
Unsafe-->>Control: false (exception swallowed)
end
Control-->>App: Property applied (or silently degraded)
The Win32 interop layer follows a deliberate error-swallowing strategy:
Bare catch blocks are intentional. Win32 APIs may fail unpredictably across OS versions, and there is no reliable way to enumerate all failure modes at compile time. Swallowing exceptions ensures the application continues to function, albeit without the requested visual effect.
Graceful degradation is the design goal. If a Mica backdrop cannot be applied (e.g., on Windows 10), the window falls back to a solid background. No exception propagates to the consumer.
Handle validation is mandatory. Every wrapper method must validate that the HWND is non-zero and represents a valid window before calling any native API. This prevents access violations from stale or recycled handles.
Return values signal success. Methods return bool (success/failure) or nullable types rather than throwing. Callers check return values to determine whether the native operation succeeded.
Pattern:
if (handle == IntPtr.Zero) return false;
if (!PInvoke.IsWindow(handle)) return false;
try {
NativeCall(handle, ...);
return true;
} catch {
return false;
}
SetWindowLongPtr does not exist as a distinct entry point on 32-bit Windows. The custom PInvoke.cs handles this by routing to SetWindowLong on x86 and SetWindowLongPtrW on x64.DWMWA_SYSTEMBACKDROP_TYPE) are only available on Windows 11 (build 22000+). The Utilities class gates these calls.ITaskbarList4 and IUISettings3 require COM activation. These are wrapped to handle COMException gracefully.