Repository navigation
Releases: dapplo/Dapplo.Windows
Releases · dapplo/Dapplo.Windows
Release list
Dapplo.Windows 3.14.4
Merge pull request #77 from dapplo/fix/scrollable-areas-cold-edge FindScrollableAreas: the content wait doesn't stop too early for a cold Edge
Dapplo.Windows 3.14.2
Added
UiAutomationScroller.FindScrollableAreas(windowHandle or IInteropWindow, horizontal, timeout, includeScrollBarAreas, contentWait, cancellationToken): Chromium based browsers and Electron apps build their accessibility tree only when a UI Automation client first asks, so the first search after the browser started or a page loaded found no area for the page (in Greenshot the scroll indication was missing on the first capture). When the search finds nothing and a shallow read of the control view shows an element without content covering at least a quarter of the window (the check ofUiAutomationAreas.FindAreasAsync), it searches again with a pause of a quarter of a second, until an area is found, the tree is complete orcontentWaithas passed (null usesUiAutomationAreas.DefaultContentWait, 3 seconds;TimeSpan.Zerosearches once); the last result is returned. All attempts use one UI Automation object, the token is checked during every pause and before every search. A window with nothing to scroll and a complete tree never waits. The existing overloads search once, as before.
Dapplo.Windows 3.13.5
All packages at their latest versions, a build without warnings, and a fix for Start/End/Reset with the mouse wheel in WPF.
Changed
- Dependencies: System.Reactive 7.0.0 (from 6.1.0; Dapplo.Windows uses no UI framework specific Rx APIs), System.Drawing.Common and System.Resources.Extensions 10.0.12, Nerdbank.GitVersioning 3.10.94.
- Tests: xunit.v3 4.0.2 as
xunit.v3.mtp-off(xunit.v3 4 includes Microsoft.Testing.Platform v2, which no longer runs through the VSTest mode ofdotnet teston the .NET 10 SDK; the mtp-off variant keepsdotnet testwith filters, trx and coverlet, and the Visual Studio Test Explorer via xunit.runner.visualstudio 4.0.0), xunit.analyzers 2.2.0, Xunit.StaFact 4.0.24, Microsoft.NET.Test.Sdk 18.10.1, coverlet.msbuild 10.0.1.[assembly: Parallelization(Mode = ParallelMode.None, MaxThreads = 1)](namespaceXunit.v3) replaces theCollectionBehaviorparallelization settings which xunit.v3 4 made obsolete, xunit.runner.json uses"parallelMode": "none". - The build has no warnings anymore (xUnit analyzer findings in the tests, the obsolete
Form.OnClosingin the samples, coverlet couldn't resolve System.Drawing.Common while instrumenting).
Fixed
UiAutomationScrollerinUiAutomationScrollModes.MouseWheel:Start(),End()andReset()stopped far before the target in WPF (e.g. at 14 % forEnd()). A WPF ScrollViewer scrolls one notch per wheel message whatever the delta is, so a wheel input with several notches moved only one; several notches are now sent as that many wheel messages in one input, applications which use the delta end up at the same position.
Dapplo.Windows 3.12.2
Small efficiency and API fixes, found while reviewing 3.11.2 for Greenshot.
Added
ToForegroundAsync(cancellationToken): the token is checked at the start and while waiting for a minimized window to restore (OperationCanceledException). It still returns aValueTask, most calls complete without waiting or allocating. The wait is measured with aStopwatchinstead ofDateTime.UtcNow. After a wait the foreground switch runs on a thread-pool thread (as before),AttachThreadInputworks from there.
Changed
IsVisibleApplicationWindowandIsVisiblePopupcheck cheapest first:IsWindowVisible, then the class name of the ignored classes (GetClassName), then the cloak check (DwmGetWindowAttribute). Most top-level windows are invisible, so an enumeration no longer asks the class name of every top-level window, only of the visible ones. The cloak check was already only made for windows withWS_VISIBLE, it is now also skipped for visible windows with an ignored class (e.g.Progman). The cachedIsVisiblekeeps its meaning (visible and not cloaked).GetParentuses the style of a cachedWindowInfoinstead of readingGWL_STYLEagain (unlessforceUpdate);IsVisibleApplicationWindowandIsVisiblePopupread the info right before.User32Api.GetTextandGetInternalTextread captions up to 255 characters into a buffer on the stack, only longer captions allocate a buffer. The full length is still supported.
Dapplo.Windows 3.11.2
Added
UiAutomationAreas.FindAreasAsync(…, contentWait, cancellationToken): while the tree still has a large area without content, it is read again with a pause of a quarter of a second between the attempts, until the tree is complete orcontentWaithas passed (null uses the newUiAutomationAreas.DefaultContentWait, 3 seconds;TimeSpan.Zeroreads only once); the last result is returned. Before, the tree was read a second time only once, after half a second, which wasn't enough for Edge with Gmail right after Edge started. The condition is unchanged since 3.10.5, a complete tree never waits. The cancellation token is checked during every pause and before every request; each attempt is logged at verbose level. The overloads withoutcontentWaitremain for binary compatibility.
Dapplo.Windows 3.10.5
Merge pull request #71 from dapplo/feature/uia-areas-empty-fix UI Automation areas: read again only for elements without content (Gmail in Edge was read twice)
Dapplo.Windows 3.10.3
Added
- New in Dapplo.Windows.Automation:
UiAutomationAreas.FindAreasAsync(windowHandle or IInteropWindow, maxDepth = 3, minimumSize = 0, timeout, cancellationToken)reads the UI Automation element tree (control view) of a window as immutableUiAutomationAreas (Bounds,ControlType,Name,Children) on a background (MTA) thread. It reads level by level (FindAllBuildCachewithTreeScope_Children, only the children which aren't offscreen), somaxDepthlimits the work;maxDepthcounts the levels of the result after merging, and the token is checked before every request. For snapping a region selection to the parts of windows without child windows (web pages, Electron, WPF and UWP apps, ribbons): offscreen and empty elements are left out, elements belowminimumSizewith their children, rectangles are clipped to their parent, and an element with its parent's rectangle is replaced by its children. When an area whose children were read has nothing visible inside and covers a quarter of the window (Chromium builds its accessibility tree on the first request, the first answer has only the frame), the tree is read once more after half a second. The UI Automation timeouts are set totimeout(default 2 seconds). Measured with Edge: the content of a page starts atmaxDepth: 4. UiAutomationArea.GetAreasAt(point): the areas containing a point, deepest first, the top-most sibling wins on overlap; pure geometry on the snapshot.
Fixed
ToForegroundAsyncreturned early when the window was already the foreground window, before restoring it: a minimized window which is the foreground window stayed minimized. A minimized window is now restored first.
Dapplo.Windows 3.9.2
Read large bitmaps from the clipboard with fewer full-size copies.
Added
DibImage.TryReadInfo(ReadOnlySpan<byte> dib, long maxPixelCount, out int width, out int height, out bool hasAlpha): validates the header exactly likeTryDecodeand tells the size and whether the decoded image would have alpha (for 32 bpp from the alpha values of the pixels), without decoding or allocating the pixels.DibImage.TryDecode(ReadOnlySpan<byte> dib, long maxPixelCount, Span<byte> destination, int destinationStride): decodes into memory of the caller (e.g. a locked bitmap), the same top-down BGRA32 pixels with straight alpha asDibImage.Pixels; false for invalid data or a destination which is too small. The padding of a larger stride is not written.
Changed
- The read-only
MemoryStreams ofClipboardSnapshot.TryGetStreamand ofDataObjectReaderare publicly visible, soMemoryStream.TryGetBufferreturns their array without a copy (still not writable; don't change the buffer, it is the snapshot's data). - The DIB decoder is split into header parsing and decoding into a span;
DibImage.TryDecode(byte[] ...)uses it, its results are unchanged. The palette and the check for repeated masks no longer allocate.
Dapplo.Windows 3.8.2
Found while replacing Greenshot's WindowDetails with IInteropWindow, InteropWindowQuery and WindowsEnumerator.
Changed
GetVisibleApplicationWindows,IsVisibleApplicationWindowandIsVisiblePopupnow include Chromium based browsers (Chrome, Edge, Brave and other windows which render with DirectComposition): windows withWS_EX_NOREDIRECTIONBITMAPwere rejected, so they were also missing fromGetLinkedWindows.GetVisibleApplicationWindows,IsVisibleApplicationWindowandIsVisiblePopupnow exclude cloaked windows (on another virtual desktop, suspended UWP apps): they useIsVisible()(IsWindowVisibleand not cloaked) instead of only theWS_VISIBLEstyle.IsVisibleApplicationWindowandIsVisiblePopupcheckIsVisible()right after the ignored classes, beforeGetInfo(): most top-level windows are invisible and are rejected without the DWM,IsZoomedandFindWindowExcalls.GetInfo()skips the DWM extended frame bounds and theIsApp()/IsMaximized()checks for child windows (WS_CHILD), DWM only answers for top-level windows; child windows are still clipped to their parents.IconExtensions.GetIconForWindowHandle(and soGetIcon) reads the class icon whenWM_GETICONreturns no icon, not only when the message fails: windows which never gotWM_SETICONgot the icon of the executable instead of their class icon. The order is unchanged, the preferred size first.
Added
includeMinimizedforIsVisibleApplicationWindowandGetVisibleApplicationWindows, e.g. for a "capture this window" menu which restores the window first. The overloads without it are kept for binary compatibility.GetChildren(forceUpdate, allLevels): withallLevelsthe whole tree below the window is filled from oneEnumChildWindows, withChildren(empty for leaf windows),ParentandParentWindowof every window, instead of one enumeration per level.FindChildAt(point): the deepest visible child window at a screen point, on the cached tree andGetInfo()values (works on a snapshot, e.g. under a full-screen overlay).
Dapplo.Windows 3.7.2
Added
ClipboardContents.AddDib(ReadOnlyMemory<byte> bgra32, width, height, stride, premultipliedAlpha, formats): CF_DIBV5 / CF_DIB are encoded directly into the clipboard memory when the contents are placed, without the two intermediate arrays (about 33 MB each for a 4K screenshot). Keep the memory valid and unchanged until the contents are placed, as withAddStream; the arguments are checked when it is called. AnAddDib(byte[] ...)overload keeps existing calls with a byte array unambiguous and eager.
Changed
IClipboardAccessToken.SetAsDibencodes directly into the clipboard memory instead of building the DIBs as byte arrays first. The output is unchanged.