You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Breaking: the Windows message types are unambiguous: WindowMessage lives in Dapplo.Windows.Messages and is also what the Forms/WPF WinProcMessages() and DpiHandler use (WindowMessageInfo is gone); WindowsMessage is now RegisteredWindowMessages (Register, GetName); Dapplo.Windows.Messages.Enumerations is now .Enums; Msg.wParam / lParam are WParam / LParam.
Breaking: the Forms WinProcFormsMessages() is renamed to WinProcMessages(), the same name as in WPF.
Breaking:IsTopLevel / GetTopLevelWindows / IsPopup are renamed to IsVisibleApplicationWindow / GetVisibleApplicationWindows / IsVisiblePopup, after what they check (no parent, visible, has a title, not a tool window, not minimized, …); owned windows are accepted.
Breaking: consistent WinMm names: PlayResource, PlayFile, PlayWave(byte[]), PlayWave(IntPtr, SoundSettings) and PlaySystemSound all return bool; PlayResource no longer plays the default sound for a missing resource.
Breaking:RmShutdownType is a [Flags] enum with Graceful, Force and OnlyRegistered.
Breaking:DrawIconExFlags moved to Dapplo.Windows.Icons.Enums; misspellings fixed: GdiExtensions.AreRectangleCornersVisible, CieXyzTriple; SystemStateApi.CloseHandle is removed.
Breaking:KeyCombinationHandler.TriggerOnKeyUp is replaced by TriggerMode (KeyDown, FirstKeyUp, AllKeysUp).
Breaking:InteropWindowQuery.GetTopWindows() / GetTopWindows(parent) take a snapshot with EnumWindows / EnumChildWindows and return IReadOnlyList<IInteropWindow>, so they can no longer skip, repeat or loop over windows when the Z-order changes during the walk. GetVisibleApplicationWindows() takes its snapshot when called.
Breaking:GetChildren() returns the direct children in Z-order; GetZOrderedChildren(), HasZOrderedChildren, InteropWindowRetrieveSettings.ZOrderedChildren and CacheAllChildZorder are removed.
Breaking: the clipboard Set* methods throw InvalidOperationException when the content belongs to another window (you forgot ClearContents), instead of mixing your formats into another application's content.
Breaking: once the process is exiting and the shared window is gone, using SharedMessageWindow throws ObjectDisposedException.
Breaking: the file and folder dialogs throw InvalidOperationException on a non-STA thread instead of failing inside COM.
KeyCombinationHandler and KeySequenceHandler ignore VK_PACKET events, so typed text never interrupts a combination or sequence.
Breaking: targets are net480 and net10.0-windows only; netstandard2.0 and net8.0-windows are dropped (F-11).
Breaking: the core packages no longer depend on WinForms or WPF. WinForms helpers moved to the new Dapplo.Windows.Forms package, WPF helpers to the new Dapplo.Windows.Wpf package, under the Dapplo.Windows.Forms.* / Dapplo.Windows.Wpf.* namespaces (F-05, F-12).
Breaking: conversions between the native structs and WPF types are extension methods (ToRect(), ToNativeRect(), ToSize(), ToInt32Rect(), …) in Dapplo.Windows.Wpf.
Breaking:WinProcListener (now in Dapplo.Windows.Forms) takes a WinProcHook delegate instead of the WPF HwndSourceHook.
Breaking:InteropWindowExtensions.PrintWindow() returns a Bitmap; PrintWindowAsBitmapSource() is in Dapplo.Windows.Wpf.
Breaking: icon helpers support Icon and Bitmap only and throw NotSupportedException for other types instead of returning null; use ToBitmapSource() from Dapplo.Windows.Wpf.
Breaking:DwmApi.ColorizationColor returns a System.Drawing.Color (the WPF Color version and the duplicate ColorizationDrawingColor / ColorizationSystemDrawingColor are gone); convert with ToMediaColor() from Dapplo.Windows.Wpf. It returns white instead of throwing when the registry value isn't a DWORD.
Breaking:BitmapScaleHandler.AddTarget(Button / ToolStripItem) moved to Dapplo.Windows.Forms extension methods; the core has AddTargetAction.
Breaking:Parent / HasParent / GetParent() mean the real parent (child windows only, GetAncestor(GA_PARENT)), never the owner; new Owner / HasOwner / GetOwner() and InteropWindowRetrieveSettings.Owner. GetInfo(autoCorrect) no longer crops owned dialogs to their owner (A-06).
Breaking:GetChildren() returns direct children only; new GetDescendants() returns all descendants (A-14).
Breaking:SafeCurrentInputDesktopHandle is replaced by SafeDesktopHandle.OpenInputDesktop() and ThreadDesktopScope.SwitchToInputDesktop() (A-18).
Breaking:TrySendMessage(hWnd, msg, wParam, lParam, out result, timeout); AttachThreadInput takes and returns bool; MapWindowPoints has ref NativePoint, ref NativeRect and NativePoint[] overloads; FillRect returns bool; DisplayInfo.Index is int (A-22, A-36, A-41, A-48).
Breaking:DesktopAccessRight.GENERIC_ALL is the real 0x10000000 (the old value is DESKTOP_ALL_SPECIFIC); ObjectStates.STATE_SYSTEM_VALID is 0x7FFFFFFF (A-30, A-38).
Breaking:InteropWindow conversions to and from IntPtr are explicit and Equals is symmetric; InteropWindowQuery.IgnoreClasses is read-only (use AddIgnoreClass / RemoveIgnoreClass); WinEventInfo is a readonly struct with 32-bit fields; WndClassEx.LpfnWndProc is a function pointer; the sync window enumerators return IReadOnlyList (A-39, A-42, A-43, A-46, A-47).
Breaking: the IInteropWindow icon extensions (GetIcon, GetIconFromWindow, GetAppLogo) moved from Dapplo.Windows.Icons to the Dapplo.Windows package (same namespace); IconHelper.GetAppLogo<T> takes the executable path (F-28).
Breaking:Win32.GetHResult returns HResult and maps success to S_OK; ColorSpace profile values are corrected and the rendering intent is the new ColorSpaceIntent enum; BitfieldColorMask has the correct layout (Rgb888, Rgb565, Rgb555 presets) (C-29, C-30, C-31).
Breaking:IsEmpty of the rectangle and size structs is true for zero or negative width or height, like Win32 IsRectEmpty (C-35).
Breaking:Bgra32.AlphaBlend uses Porter-Duff "over" for non-opaque targets; new AlphaBlendPremultiplied, ToPremultiplied, ToStraight (C-12).
Breaking:DpiAwareForm no longer swallows WM_DPICHANGED: WinForms' own Per Monitor v2 scaling and Form.DpiChanged run; without it only the window bounds follow the suggested rectangle (D-21). The WPF AttachDpiHandler no longer double-scales (D-22).
Breaking: DPI scaling rounds instead of truncating; DpiHandler.Dpi is 96 until known, see IsDpiKnown (D-32).
Breaking:Kernel32Api.GlobalSize returns UIntPtr; PackageInfo.IsRunningOnUwp is renamed to HasPackageIdentity; Ole32Api.ClassIdFromProgId returns Guid?; IOleCommandTarget takes IntPtr pguidCmdGroup; ComWrapper no longer force-releases the RCW (D-28, D-30, D-36, D-37, D-38).
Breaking:MonitorDpiType and WindowsProductTypes are no longer [Flags] (D-39).
Breaking: clipboard GetAsStream / TryGetAsStream return a copy of the data that stays valid after the token is disposed (D-34).
Breaking: the Restart Manager types moved from Kernel32 to Dapplo.Windows.InstallerManager (RestartManagerApi, Enums, Structs), with readable field names (AppName, ProcessId, IsRestartable, …); the duplicate Kernel32 RestartManager is removed (F-38).
Breaking:InstallerRestartManager.Shutdown() defaults to the new RmShutdownType.Graceful; forcing is opt-in (E-16).
Breaking:Shell32Api.ExtractIconEx takes IntPtr[] arrays (new CountIcons); AppBarData.lParam is pointer-sized; Shell32Api.TaskbarPosition is replaced by TryGetTaskbarPosition (new GetTaskbarState) (E-19, E-26).
Breaking: Citrix EventMask is a 32-bit enum, SessionTime exposes UTC DateTime? (E-15, E-23); Advapi32Api.CurrentSessionId is renamed to CurrentLogonSid (E-27); WaitableTimer APIs use SafeWaitHandle (E-28).
Breaking: Input and Messages enums lost their duplicate-value aliases and misspellings: VirtualKeyCode.Snapshot → PrintScreen, Hangul → Kana, Kanji → Hanja; MouseButtonStates.Button* aliases removed, Buttonx1Up → ButtonX1Up; LowerIntegretyInjected → LowerIntegrityInjected; WM_KEYFIRST / WM_KEYLAST / WM_MOUSEFIRST removed (B-32).
Breaking:KeyboardHookExtensions.Where(handler) rejects a handler already used by another active subscription; use the new Where(() => handler) factory overload for observables subscribed more than once (B-33).
Breaking: all assemblies are strong-named for every target framework and configuration (F-26).
Breaking: removed ApplicationRestartManager.MaxCommandLineLength (use RestartMaxCmdLine), PowerBroadcastEvent values that can't arrive, and undocumented DWM ordinals (DwmpStartOrStopFlip3D, GetSharedSurface, UpdateWindowShared) (E-31, E-35, E-36).
Debug builds no longer enable checked arithmetic, so Debug and Release behave the same (F-25, F-37).
The documentation, README and wiki use the real API, list every package with its dependencies, and every code sample is compiled in Dapplo.Windows.Example.DocSamples; the package project URL points to the documentation site (F-03, F-17, B-29, D-42, F-33).
Every package contains a README; builds are deterministic and use ContinuousIntegrationBuild on CI; unnecessary dependencies (Dapplo.Log in Advapi32, Microsoft.SourceLink.GitHub) are gone and no empty .dll.config is shipped (F-27, F-29, F-30).
DpiHandler.HandleWindowMessages, HandleContextMenuMessages and MessageHandler are public, so other UI frameworks can feed messages to a DpiHandler.
User32Api.GetCursorLocation() falls back to GetCursorPos instead of WinForms Cursor.Position.
Packages are published to NuGet only from version tags (v*), each with a GitHub Release built from this changelog; other builds are prereleases. The API reference is generated again with docfx as a dotnet tool, and the wiki mirror removes deleted pages (F-02, F-07, F-16, F-19).
The tests also run on .NET Framework 4.8, and CI runs only the non-interactive tests (F-10). global.json is in the repository root.
Breaking:InteropWindowExtensions.Fill() now respects ForceUpdate, AutoCorrectValues and Maximized. Before, it always re-read every value, always auto-corrected and always queried the maximized state, so caching never worked (A-02).
Breaking:WindowScroller.ScrollWheelLinesFromRegistry is replaced by WindowScroller.ScrollWheelLines, read with SystemParametersInfo(SPI_GETWHEELSCROLLLINES); the wheel delta is calculated by the new WindowScroller.CalculateWheelDelta (A-17).
Breaking: removed NativeRectExtensions.Intersect2, which returned wrong results; use Intersect (C-05).
Breaking: corrected ProcessAccessRights.QueryLimitedInformation (0x1000) and All (0x1FFFFF), and added CreateProcess, SetQuota and SuspendResume (D-12).
Breaking:WinMm.PlayWave(byte[]) (was Play(byte[])) copies the wave data to unmanaged memory that stays alive until the next PlayWave or StopPlaying(), and returns bool (E-04).
Breaking:HResult is a signed int enum. Failed(), Succeeded() and ThrowOnFailure() now detect failures; before, every HRESULT counted as success, so failure branches that never ran now run (C-01).
Breaking:IconInfo / IconInfoEx expose the bitmaps as non-owning IntPtr properties (ColorBitmap, BitmaskBitmap); take ownership once with TakeBitmaps() or free them with DeleteBitmaps(). Every property read used to create a new owning SafeHandle, so the same HBITMAPs were deleted several times (C-02).
Breaking:NativeSizeTypeConverter writes and reads Width,Height; it used to swap them (C-06).
Breaking:IsDockedToLeftOf / IsDockedToRightOf treat flush rectangles (Right == Left, exclusive Right) as docked instead of requiring a 1-pixel gap (C-13).
Breaking:HasOverlap returns false for rectangles that only touch and true when one contains the other, the same as IntersectsWith (C-14).
Breaking:WindowsVersion uses RtlGetVersion, so it reports the real OS version without an application manifest. IsWindowsVista and IsWindows10 now mean exactly that version; use the …OrLater properties (C-17).
Breaking:NativeSize / NativeSizeFloat.CompareTo order by ascending area; it was reversed (C-23).
Breaking: lossy float-to-int conversions of the Native* structs are explicit. Points floor, sizes round up, and rectangles become the containing integer rectangle (C-24).
Breaking:MonitorFrom values match winuser.h (DefaultToNull = 0, DefaultToPrimary = 1, DefaultToNearest = 2) and the enum is no longer [Flags]; "nearest" lookups used to return NULL (A-01).
Breaking:SysColorIndexes.Color3Dface is 15 (A-09).
Breaking:ScrollBarInfo.ThumbTop / ThumbBottom were swapped; ThumbSize (really the arrow-button size) is renamed to LineButtonSize (A-10).
Breaking: WPARAM, LPARAM and LRESULT are pointer-sized in every User32Api.SendMessage overload; the int overload is removed (A-20).
Breaking:DpiAwarenessContext is a pointer-sized struct instead of an int enum, so the DPI-context APIs work on x64. Compare contexts with NativeDpiMethods.AreDpiAwarenessContextsEqual (D-07).
Breaking:IDispatch has a correct vtable on every target and GetTypeInfo returns ComTypes.ITypeInfo; the unusable IUnknown interface is removed (D-11).
Breaking:NativeDpiMethods.GetWindowDpiHostingBehavior takes the window handle it requires (D-13).
Breaking:DialogDpiChangeBehaviors.DisableControlRelayout is 4 (D-14).
Breaking:NativeDpiMethods.EnableNonClientDpiScaling returns bool instead of HResult (D-15).
Breaking:WindowMessage is a sealed class, so Handled and Result set by a subscriber reach Windows. Result is nint (signed LRESULT) and WndProc returns nint (B-01).
Breaking:SharedMessageWindow is created on first use and lives for the whole process. Handle blocks until the window exists and never returns 0; new Invoke, IsWindowThread and SubscriberErrors. Listen(onSetup, onTeardown) runs both callbacks on the window thread (B-02, B-16, B-17, D-02).
Breaking:EndSessionMessage is a class in Dapplo.Windows.AppRestartManager that answers WM_QUERYENDSESSION through CanEndSession / Veto(reason). ListenForEndSession() takes no callbacks and works for every subscriber (E-01, E-02, E-03).
Breaking:ApplicationRestartManager.WasRestartRequested(string restartArgument) checks the argument you registered (E-17).
Breaking:KeyboardHook and MouseHook are static classes whose hooks run on their own message-loop thread; subscribers are called on that thread. New SubscriberErrors, KeyboardEventsNonBlocking and MouseEventsNonBlocking (B-06, B-09).
Breaking: new pseudo key VirtualKeyCode.Win matches either Windows key in key combinations; "win" parses to it; KeyboardHookEventArgs.IsModifier is computed from Key (B-22).
Breaking:RawHID is the 8-byte header only; HID reports are in RawInputEventArgs.HidData, read with RawInputApi.TryGetRawInputData (B-08).
Breaking: clipboard delayed rendering uses ClipboardNative.RegisterDelayedRenderer(format, renderer); OnRenderFormat is removed. WM_RENDERFORMAT is answered on the window thread without opening the clipboard, WM_RENDERALLFORMATS checks ownership first (D-06).
Breaking:ClipboardNative.OnUpdate no longer opens the clipboard; ClipboardUpdateInformation.Create() has no hWnd parameter and every subscriber gets the current state first (D-04).
Breaking:AccessAsync() opens the clipboard on the thread that continues after the await; a token used on another thread reports no access. Cancelling throws OperationCanceledException (D-03).
Breaking:SetCloudClipboardOptions(bool? canIncludeInHistory, bool? canUploadToCloud, bool excludeFromMonitoring) places only the options you pass; SetExcludeClipboardContentFromMonitorProcessing is replaced by ExcludeFromMonitorProcessing() (D-05).
Breaking:SystemStateApi.PreventSleep() / PreventSystemSleep() return a disposable SleepBlocker (a power request that works across threads); AllowSleep() is removed (E-13).
WinEventHook, raw input and session-notification registrations happen on the SharedMessageWindow thread, so events arrive there (A-12, B-02, B-11).
RawInputMonitor and RawInputDeviceMonitor are available for netstandard2.0 too (B-31).
In the key-up trigger modes (TriggerMode.FirstKeyUp / AllKeysUp), key events are never marked as handled, so IsPassThrough has no effect there (B-05).
Tests that send input, replace the clipboard or write to the registry are tagged Category=Interactive and are excluded from default runs (F-06).
Added
WinMm.PlayFile(string path) plays a WAV file asynchronously and returns false when the file doesn't exist.
KeyboardInputGenerator.TypeText(string) types text as Unicode characters (KEYEVENTF_UNICODE), whatever the keyboard layout; line breaks become Enter, \t becomes Tab, other control characters are skipped. KeyboardInput.ForText, ForUnicodeKeyDown and ForUnicodeKeyUp build the input.
KeyboardState with IsDown, IsAnyDown, IsDownForCurrentThread and IsToggled.
TriggerMode.AllKeysUp: a KeyCombinationHandler can fire once all keys of the combination are released; another key pressed in between cancels it.
KeyboardHookEventArgs.IsPacket, PacketCharacter and Packet(char, bool) for VK_PACKET (Unicode) events.
ClipboardContents builder with ClipboardNative.ReplaceContents / ReplaceContentsAsync, IClipboardAccessToken.ReplaceContents (always clears first, all or nothing) and AddToCurrentContents (only while we own the content).
SharedMessageWindow.Shutdown(timeout), IsProcessExiting and ProcessExitShutdownTimeout; the window is destroyed automatically on process exit.
WindowHandles with HWND_TOP, HWND_BOTTOM, HWND_TOPMOST, HWND_NOTOPMOST, HWND_MESSAGE and HWND_BROADCAST.
User32Api.PostMessage / PostThreadMessage and IInteropWindow.PostMessage(...).
tools/build-runner: a local build and test runner driven by request files.
WindowsSessionListener.IsRegistered and RegistrationFailed; DevBroadcastDeviceInterface.TryGetDevBroadcastPort / TryGetDevBroadcastHandle; PowerManagementApi.EnableShutdownPrivilege().
Fixed
CI collects code coverage only on .NET 10 and runs the .NET Framework 4.8 tests without coverlet, whose version 8 injects a System.Runtime 8.0 reference that breaks every instrumented call on .NET Framework.
KeyHelper.VirtualKeyCodeFromString still parses the removed alias names Snapshot, Hangul, Hangeul and Kanji, so hotkeys stored by 2.x keep working.
Delayed-rendered clipboard formats survive process exit: the shared window is destroyed on exit, so Windows sends WM_RENDERALLFORMATS.
The children of the desktop window no longer get the desktop as parent, so IsVisibleApplicationWindow() is correct for them.
Window information: GetCaption works for the calling thread's own windows without deadlocks (A-11); GetTopWindows no longer yields handle 0 (A-13); GetInfo no longer overwrites Children as a side effect (A-15); GetText no longer truncates at 259 characters (A-21); GetAppLauncher, AppVisible and IsLauncherVisible give correct answers (A-23..A-25); MonitorInfoEx.DeviceName stays in its buffer (A-26); GetVisibleLocation returns the working-area origin (A-32); InstalledSoftware() reads both registry views and HKCU (A-33); GetInfo doesn't cache failures (A-34); ToForegroundAsync really waits for the restore (A-22); WPF GetHandle() works before the window is shown (A-45).
PrintWindow crops to the visible bounds instead of shifting the capture and uses PW_RENDERFULLCONTENT on Windows 8.1+, so DirectComposition, Chromium and UWP content is no longer black (A-16, A-27).
ToBitmapSource keeps the alpha channel (A-28, C-25).
Cursor capture: TryGetCurrentCursor returns a Size / HotSpot that match the captured layers at every DPI and pointer size; drawing respects the Graphics transform, handles non-square and premultiplied cursors, and no longer leaks handles on errors (C-10, C-11, C-12, C-34).
SafeWindowDcHandle.FromWindowClientArea returns a client-area DC (C-15); GDI SafeHandles no longer touch finalized objects (C-26).
DIB header factories compute correct image sizes, pixel offsets and file sizes (C-19); the ICO/CUR writer scales images above 256 pixels instead of truncating them (C-20); ExtractVistaIcon returns a Bitmap that outlives the stream (C-21); the app logo lookup finds scaled logos (C-33); GetIcon no longer leaks Process objects (C-36).
The GDI+ blur works again on .NET 10 (C-22).
NativeRect.Union(NativeRect.Empty) no longer includes (0,0) (C-27); Transform(Matrix) uses all four corners, so rotation and mirroring work (C-28); float struct equality is consistent with GetHashCode and reflexive for NaN (C-32).
DpiHandler keeps working after a WinForms handle recreate (D-20); BitmapScaleHandler no longer leaks bitmaps or touches UI from its finalizer (D-23).
GetProcessPath returns correct paths for more processes and long paths (D-25); PreventDllHijacking handles non-ANSI paths and reports failures (D-29); PackageInfo.CurrentPackageFullName is correct (D-30); Restart Manager callbacks no longer unbalance the stack on x86 (D-31).
The EmbeddedBrowser registers the real executable name and keeps page scripts running after a script error (E-30).
File open, save and folder dialogs keep the default options and no longer change the current directory (E-08).
DwmApi.IsDwmEnabled is true on every Windows 8+; IsWindowCloaked reads a DWORD; added DwmWindowAttributes.SystemBackdropType (E-20, E-21).
Citrix ClientDisplay.ColorDepth maps high values correctly (E-22).
InstallerRestartManager retries when the process list grows, ends leaked sessions and keeps callbacks alive (E-29).
WinMm.PlayResource plays WAVE resources from the given module (E-34); SetLastError usage matches the native APIs (A-40, E-32).
The InstallerExample finds the FormsExample for any build configuration; the WpfExample only swallows PrintScreen while active (F-34).
dotnet pack of a single project no longer fails on the missing icon; package release notes point to this changelog (F-09).
Benchmarks target the runtimes the project builds for (F-04); FormsExample embeds its app.manifest, so the DPI demos run Per Monitor v2 (F-18).
Reading a window's text (GetTextFromWindow, GetText(), Fill()) no longer crashes the process with a StackOverflowException when a control holds a very large text; texts over 1M characters are truncated (A-03).
Getting a window's text or title-bar info no longer blocks forever on a hung application; it times out after 500 ms (A-04).
WindowScroller.End() and Start() in MouseWheel mode can no longer loop forever; they stop when the position stops changing or after MaxMouseWheelSteps, and only return true when the end or start was reached (A-05).
A wheel-lines setting of 0 or "one page" no longer causes a DivideByZeroException, a negative or a zero wheel delta (A-17).
Mouse moves and clicks at a given location land on the right pixel, including on monitors left of or above the primary one (B-03).
LastInputTimeSpan, LastInputDateTime, KeyboardHookEventArgs.EventTime and Msg.Time are correct after 24.9 days of uptime and when the tick count wraps (B-04).
A KeyCombinationHandler that triggers on key-up fires, and no longer swallows the key-up, which left a stuck key (B-05, F-01).
Injected arrow, navigation, right Ctrl/Alt, Windows and media keys are sent as extended keys, so they are no longer seen as numpad keys or the left modifier (B-15).
KeyboardInputGenerator.KeyCombinationPress releases keys in reverse order.
Input generation no longer throws an OverflowException in Debug builds after 24.9 days of uptime (B-28).
IconHelper methods that return an Icon return an icon that owns its own copy of the handle, instead of one wrapping a destroyed HICON (C-03).
NativePoint.Offset, NativePointFloat.Offset and NativeRectFloat.Offset no longer reset X or Y to 0 when that offset is omitted (C-04).
HResult.E_ACCESSDENIED has the correct value 0x80070005 (C-07).
NativeIconMethods.GetIconInfoEx(SafeIconHandle, ...) calls the Unicode export that matches the IconInfoEx layout (C-08).
Loading a cursor from a path with non-ANSI characters works (C-09).
Setting BitmapV4Header.GammaGreen / BitmapV5Header.GammaGreen no longer overwrites GammaRed (C-18).
The clipboard no longer stays locked for the rest of the process after an open timeout, a cancellation or an exception in ClipboardNative.Access() / AccessAsync() (D-01).
Disposing a clipboard access token more than once no longer closes the clipboard again or breaks the lock (D-26).
Kernel32Api.LoadLibrary works; it passed an ANSI string to LoadLibraryW (D-10).
DpiApi.GetSystemParametersInfo / GetSystemParametersInfoForWindow work for NONCLIENTMETRICS and ICONMETRICS (D-24).
DwmApi.GetWindowCornerPreference / SetWindowCornerPreference no longer throw on Windows 11 (E-05).
Citrix detection reads the connect state correctly on x64 (E-06).
WinMm.PlaySystemSound plays the requested system sound (E-09).
ApplicationRestartManager.ListenForEndSession answers WM_QUERYENDSESSION with TRUE/FALSE; it answered S_OK (0), which blocks shutdown (E-01, part of it: the reply reaches Windows only after the message pipeline fix in pass 3).
Type converters write with the invariant culture, so negative values round-trip under cultures such as sv-SE; float converters accept exponent notation (C-16).
Converting a non-normalised rectangle to a WPF Rect no longer throws (C-24).
User32 imports that handle text always call the Unicode (W) entry points; SendMessage, Get/SetWindowLong(Ptr) and GetClassLongPtr used to resolve to the ANSI versions (A-07).
SetWindowStyle / SetExtendedWindowStyle no longer throw an OverflowException in 32-bit processes or Debug builds for styles such as WS_POPUP (A-08).
WindowScroller scrolls scroll-bar controls (ScrollBarTypes.Control) and no longer overflows for positions above 32767 on 32-bit (A-20).
Creating a DpiAwareForm or DpiHandler, or calling AttachDpiHandler, no longer leaves the UI thread in Per Monitor v2 awareness (D-08).
NativeDpiMethods.EnableDpiAware falls back to Per Monitor v1 and SetProcessDpiAwareness, and returns whether the process is actually DPI aware (D-09).
DpiHandler.TryEnableNonClientDpiScaling reports failures and no longer throws on Windows 10 before 1607 (D-15).
An exception in a SharedMessageWindow, keyboard-hook or mouse-hook subscriber no longer crashes the process; it is published on SubscriberErrors (B-06).
Disposing a Window.WinProcMessages() subscription no longer destroys the WPF window (B-07).
WinProcListener returns the handling hook's result to Windows; the Forms WinProcMessages() survives handle recreation and completes when the control is disposed (B-10, B-18).
WinProcHandler no longer recreates its window during disposal (B-25); MessageLoop.ProcessMessages throws on a GetMessage error (B-26).
Raw-input monitors register when you subscribe and unregister when you dispose, and no longer overwrite each other's registrations (B-02, B-13); RawInputDeviceMonitor no longer throws for unknown devices (B-12).
F10 and the Alt key-up no longer report a phantom Alt (B-14); lock-key state is not flipped by auto-repeat (B-23).
KeyHelper display names are correct for extended keys and no longer throw for numpad * and / (B-19).
A KeySequenceHandler resets after a wrong combination regardless of the order in which its keys are released; before, releasing the modifier last left the sequence stuck on the failed stage.
Key combinations no longer stay blocked after a missed key-up (B-20); after a KeySequenceHandler timeout the first press restarts the sequence (B-21).
The clipboard is no longer left with partial data or leaked memory after a failed write (D-16); format-name caches are thread-safe and case-insensitive (D-17); GetAsUnicodeString has no trailing garbage (D-18); GetFileNames supports long paths (D-19); read errors are reported correctly (D-27); SetAsStream honours size (D-35).
WindowsSessionListener no longer crashes when WTSRegisterSessionNotification fails early at logon; it retries (B-11).
Device notification events can be used after ObserveOn and have full-length names (E-07, E-25); DisplayName is fixed (E-10); DeviceInterfaceClass.Keyboard / BluetoothLeDevice GUIDs are correct (E-11); DevBroadcastHandle has the native layout (E-24).
PowerManagementApi.Shutdown() / Restart() work for normal desktop apps, Shutdown powers off, and the event log records a planned shutdown (E-14).
RegistryMonitor no longer fires phantom notifications and reports the real error (E-12).
WinEventHook works when subscribed from any thread, unhooks reliably and traces subscriber exceptions (A-12).
DisplayInfo.AllDisplayInfos never returns null and follows display, work-area and DPI changes (A-19).
DpiHandler.ScaleWithCurrentDpi(NativePointFloat) / UnscaleWithCurrentDpi(NativePointFloat) no longer round to integers, and unscaling no longer scales.