Skip to content

Releases: dapplo/Dapplo.Windows

Dapplo.Windows 3.14.4

Choose a tag to compare

@github-actions github-actions released this 11 Oct 07:21
5c92076
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

Choose a tag to compare

@github-actions github-actions released this 10 Oct 20:49
048208b

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 of UiAutomationAreas.FindAreasAsync), it searches again with a pause of a quarter of a second, until an area is found, the tree is complete or contentWait has passed (null uses UiAutomationAreas.DefaultContentWait, 3 seconds; TimeSpan.Zero searches 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

Choose a tag to compare

@github-actions github-actions released this 10 Oct 07:58
2f11847

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 of dotnet test on the .NET 10 SDK; the mtp-off variant keeps dotnet test with 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)] (namespace Xunit.v3) replaces the CollectionBehavior parallelization 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.OnClosing in the samples, coverlet couldn't resolve System.Drawing.Common while instrumenting).

Fixed

  • UiAutomationScroller in UiAutomationScrollModes.MouseWheel: Start(), End() and Reset() stopped far before the target in WPF (e.g. at 14 % for End()). 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

Choose a tag to compare

@github-actions github-actions released this 09 Oct 21:43
e499639

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 a ValueTask, most calls complete without waiting or allocating. The wait is measured with a Stopwatch instead of DateTime.UtcNow. After a wait the foreground switch runs on a thread-pool thread (as before), AttachThreadInput works from there.

Changed

  • IsVisibleApplicationWindow and IsVisiblePopup check 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 with WS_VISIBLE, it is now also skipped for visible windows with an ignored class (e.g. Progman). The cached IsVisible keeps its meaning (visible and not cloaked).
  • GetParent uses the style of a cached WindowInfo instead of reading GWL_STYLE again (unless forceUpdate); IsVisibleApplicationWindow and IsVisiblePopup read the info right before.
  • User32Api.GetText and GetInternalText read 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

Choose a tag to compare

@github-actions github-actions released this 09 Oct 14:40
e8c56ec

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 or contentWait has passed (null uses the new UiAutomationAreas.DefaultContentWait, 3 seconds; TimeSpan.Zero reads 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 without contentWait remain for binary compatibility.

Dapplo.Windows 3.10.5

Choose a tag to compare

@github-actions github-actions released this 09 Oct 13:16
1ac7839
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

Choose a tag to compare

@github-actions github-actions released this 09 Oct 11:18
30cbd2b

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 immutable UiAutomationAreas (Bounds, ControlType, Name, Children) on a background (MTA) thread. It reads level by level (FindAllBuildCache with TreeScope_Children, only the children which aren't offscreen), so maxDepth limits the work; maxDepth counts 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 below minimumSize with 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 to timeout (default 2 seconds). Measured with Edge: the content of a page starts at maxDepth: 4.
  • UiAutomationArea.GetAreasAt(point): the areas containing a point, deepest first, the top-most sibling wins on overlap; pure geometry on the snapshot.

Fixed

  • ToForegroundAsync returned 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

Choose a tag to compare

@github-actions github-actions released this 08 Oct 19:17
da07b7c

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 like TryDecode and 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 as DibImage.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 of ClipboardSnapshot.TryGetStream and of DataObjectReader are publicly visible, so MemoryStream.TryGetBuffer returns 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

Choose a tag to compare

@github-actions github-actions released this 08 Oct 19:10
9592a34

Found while replacing Greenshot's WindowDetails with IInteropWindow, InteropWindowQuery and WindowsEnumerator.

Changed

  • GetVisibleApplicationWindows, IsVisibleApplicationWindow and IsVisiblePopup now include Chromium based browsers (Chrome, Edge, Brave and other windows which render with DirectComposition): windows with WS_EX_NOREDIRECTIONBITMAP were rejected, so they were also missing from GetLinkedWindows.
  • GetVisibleApplicationWindows, IsVisibleApplicationWindow and IsVisiblePopup now exclude cloaked windows (on another virtual desktop, suspended UWP apps): they use IsVisible() (IsWindowVisible and not cloaked) instead of only the WS_VISIBLE style.
  • IsVisibleApplicationWindow and IsVisiblePopup check IsVisible() right after the ignored classes, before GetInfo(): most top-level windows are invisible and are rejected without the DWM, IsZoomed and FindWindowEx calls.
  • GetInfo() skips the DWM extended frame bounds and the IsApp() / 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 so GetIcon) reads the class icon when WM_GETICON returns no icon, not only when the message fails: windows which never got WM_SETICON got the icon of the executable instead of their class icon. The order is unchanged, the preferred size first.

Added

  • includeMinimized for IsVisibleApplicationWindow and GetVisibleApplicationWindows, 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): with allLevels the whole tree below the window is filled from one EnumChildWindows, with Children (empty for leaf windows), Parent and ParentWindow of every window, instead of one enumeration per level.
  • FindChildAt(point): the deepest visible child window at a screen point, on the cached tree and GetInfo() values (works on a snapshot, e.g. under a full-screen overlay).

Dapplo.Windows 3.7.2

Choose a tag to compare

@github-actions github-actions released this 08 Oct 17:04
045d14a

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 with AddStream; the arguments are checked when it is called. An AddDib(byte[] ...) overload keeps existing calls with a byte array unambiguous and eager.

Changed

  • IClipboardAccessToken.SetAsDib encodes directly into the clipboard memory instead of building the DIBs as byte arrays first. The output is unchanged.