Visitar URL original
fix(win32): Read drag bitmaps and contain async drop errors (backport #23924) by mikernet · Pull Request #25865 · unoplatform/uno · GitHub
Skip to content

fix(win32): Read drag bitmaps and contain async drop errors (backport #23924) - #25865

Open
mikernet wants to merge 3 commits into
unoplatform:servicing/6.8from
mikernet:dev/mikernet/68-win32-drag-bitmap-sv
Open

mikernet wants to merge 3 commits into
unoplatform:servicing/6.8from
mikernet:dev/mikernet/68-win32-drag-bitmap-sv

Conversation

@mikernet

@mikernet mikernet commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

GitHub Issue: backport of #23924 (closes #25863 on 6.8)

PR Type:

🐞 Bugfix

What changed? 🚀

Manual backport to servicing/6.8 of two Skia Win32 (Windows desktop) drag-and-drop fixes that master got in #23924. That's a RichEditBox feature PR, so it wasn't backported, and the two fixes are a small part of its commits, so Mergify's cherry-pick can't be used.

A CF_DIB drag's bitmap can't be read in DragOver or Drop (#25863). When an external drag enters the window, DragEnter reads each standard format offered as TYMED_HGLOBAL with IDataObject::GetData and releases every medium (ReleaseStgMedium) before it returns. Text and file lists are copied right away. The CF_DIB reader, though, only registered a data provider that kept the raw HGLOBAL and locked it later, when the app called DataPackageView.GetBitmapAsync(), typically from its DragOver or Drop handler. The handle is usually freed by then, so GetBitmapAsync throws InvalidOperationException ("Failed to asynchronously load the data of id 'Bitmap'") for the Bitmap format of any CF_DIB drag, after logging "GlobalLock failed: The handle is invalid.". This matters most for a drag that offers a picture without a file. Files dropped from Explorer, and files that only exist in the source app (copied to a temporary folder at DragEnter), aren't affected. The reader now builds the BMP (the DIB behind a file header) and calls SetBitmap before DragEnter releases the handle, as on master. The package then holds a buffer the size of the bitmap for the whole drag, about 33 MB for a 3840×2160, 32-bit bitmap. Reading the bitmap twice, for example in DragOver and again in Drop, depends on the RandomAccessStreamReference.CreateFromStream fix in #25867.

Async file drops: defensive hardening and completion ordering. When the drag source supports asynchronous data extraction (IDataObjectAsyncCapability), the drop target reads the file list (HDROP) on a worker thread after Drop. On 6.8, a read that fails (the list can't be read) already faults the task behind GetStorageItemsAsync(). But an exception thrown on that thread, while reading the list or during the cleanup (releasing the medium and calling EndOperation), would escape the thread and end the process. No known input makes it throw on 6.8, so this part is defensive. Also, the task completed before that cleanup, and its continuations could run inline on the worker, before the cleanup. Now the worker completes the task only after the cleanup, with continuations run asynchronously, and faults it with any non-fatal exception: GetStorageItemsAsync now throws (the cause is logged) instead of the process ending.

The backport has three commits:

  • fix(win32): Read drag bitmaps (backport #23924): the GetBitmap part of eb508ad, by Dominik Titl. The method is identical to master's, including the removed System.Threading.Tasks using. The rest of eb508ad is RichEditBox work, plus drag-drop input hardening in ReadContentIntoPackage that this backport leaves out: a limit on the number of formats, size budgets per format and per drag, a check that dragged text is null-terminated within its allocation, and size checks on the HDROP. That hardening uses constants and helpers (MaxClipboardFormatBytes, GetUnicodeString and others) that b2be67e, also in feat(richeditbox): implement Skia support #23924, added to Win32ClipboardExtension.cs, and 6.8 doesn't have them. As a result, the new copy of the bitmap has no size limit on 6.8, while master ignores a format over 256 MB.
  • fix(win32): Contain async drop errors (backport #23924): de8bb7e, by morning4coffe-dev, with its two tests in a new Given_Win32DragDrop.skia.cs. The cherry-pick had two conflicts. In Win32DragDropExtension.cs, master's context was b2be67e's in-between version of the worker thread code (a try/catch around it), which 6.8 doesn't have; the result takes de8bb7e's version. The test file moved from master's Windows/ApplicationModel/DataTransfer folder to 6.8's Tests/Windows_ApplicationModel/DataTransfer. Apart from the 6.8 namespace (Uno.UI.Runtime.Skia.Win32), the result matches master's file except at the end: 6.8's file keeps the trailing blank line that b2be67e removed on master.
  • test(win32): Cover reading a DIB after release: a regression test for the bitmap bug, Given_Win32DragDrop.When_Bitmap_Drop_Read_After_Medium_Released. It builds a 2×3, 32-bit BI_RGB CF_DIB in an HGLOBAL, passes it to ReadContentIntoPackage, frees the handle as ReleaseStgMedium does, then reads the bitmap with GetBitmapAsync. It checks the BMP file header (BM, bfSize equal to the length, bfOffBits of 54) and that the DIB bytes are unchanged. master has no test for this; test(win32): Cover reading a DIB after release #25864 adds the same test there.

Tests: on Skia Desktop (Windows), Given_Win32DragDrop, on servicing/6.8 at 6951c2c:

Test This PR, with the bitmap fix locally reverted This PR
When_Bitmap_Drop_Read_After_Medium_Released fails passes
When_File_Drop_Failure_Completes_Task (2 rows) pass pass
When_File_Drop_Completes_Only_After_Cleanup passes passes

Without the bitmap fix, GetBitmapAsync throws InvalidOperationException with an inner TaskCanceledException, because DataPackage swallows the provider's error: it logs it and completes the request without data. The two file drop tests come with the async drop fix and call its new CompleteFileDrop method, so they can't run without it.

PR Checklist ✅

@agneszitte

Copy link
Copy Markdown
Member

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
1 pipeline(s) were filtered out due to trigger conditions.

@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your WebAssembly Sample App stage site is ready! Visit it here:

@nventive-devops

Copy link
Copy Markdown
Contributor

The build 244750 did not find any UI Test snapshots differences.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/skia ✏️ Categorizes an issue or PR as relevant to Skia

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants