dotnet / winforms

Windows Forms is a .NET UI framework for building Windows desktop applications.
MIT License
4.41k stars 980 forks source link

A drag image remnant remains when an exception is unhandled in DragLeave or DragDrop #10504

Closed willibrandon closed 1 month ago

willibrandon commented 10 months ago

.NET version

8.0

Did it work in .NET Framework?

Not tested/verified

Did it work in any of the earlier releases of .NET Core or .NET 5+?

No response

Issue description

A drag image remnant remains when the application fails to handle an exception in DragLeave or DragDrop.

I've created a minimal repro which can be found here. DragDrop.zip

Here is an example DragDrop implementation that causes the issue to occur.

private void ListBox1_MouseDown(object sender, MouseEventArgs e)
{
    int index = listBox1.IndexFromPoint(e.X, e.Y);

    if (index >= 0)
    {
        listBox1.DoDragDrop(
            data: listBox1.Items[index],
            allowedEffects: DragDropEffects.Copy,
            dragImage: _nyanCatBmp,
            cursorOffset: new Point(0, 96),
            useDefaultDragImage: true);
    }
}

private void TextBox1_DragEnter(object sender, DragEventArgs e)
{
    if (e.Data?.GetDataPresent(DataFormats.Text) ?? false)
    {
        e.DropImageType = DropImageType.Copy;
        e.Effect = DragDropEffects.Copy;
        e.Message = "Drop it like it's %1";
        e.MessageReplacementToken = "hot!";
    }
}

private void TextBox1_DragDrop(object sender, DragEventArgs e)
{
    throw new Exception("Kaboom!");
}

A video demonstrating the issue.

https://github.com/dotnet/winforms/assets/5017479/04263ce0-992f-48b2-9752-d75d19b59cb0

I'm pretty sure this would be considered a bug by most users, please correct me if I'm wrong.

I believe the fix here would be to notify the drag image manager in DragLeave and DragDrop prior to having the application handle the related events. That way, even if the application fails to handle an exception, the drag image manager would be notified first, alleviating the possibility of this even happening.

Steps to reproduce

Perform a drag and drop operation using the drag image API and throw or generate an unhandled exception in DragLeave or DragDrop.

merriemcgaw commented 10 months ago

@lonitra @JeremyKuhne you were going to be looking into this area in the not too distant future - can you take a look at this while you're there?

willibrandon commented 10 months ago

Up to this point I’ve been testing the drag image API naively using mostly best case scenarios. Now I’m trying to put this API to use in the real world and I see that I forgot to even consider what happens when an unhandled exception occurs during one of the drag events. Unfortunately the consequence results in this drag image remnant which I feel terrible about.

I believe the fix should be straightforward and is just a matter of changing the order in which the drag image manager is notified during the drag events. If I can be of any assistance please let me know.

JeremyKuhne commented 3 months ago

@willibrandon if you're able to help resolve this in .NET 10 that would be great. We've opened the branch for that work.

willibrandon commented 3 months ago

@willibrandon if you're able to help resolve this in .NET 10 that would be great. We've opened the branch for that work.

@JeremyKuhne - Thanks for the heads up, I'll take a look now.

willibrandon commented 1 month ago

Now that the Ole32 drag and drop related functions have been converted to CsWin32, things look good to me when testing drag and drop using WinformsControlsTest within the same process, however, when testing drag and drop between 2 test processes I see the following exceptions being thrown in output and wonder if these are expected?

Exception thrown at 0x00007FF83E4E6D9A (KernelBase.dll) in WinFormsControlsTest.exe: WinRT originate error - 0x80040155 : 'Failed to find proxy registration for IID: {5C13E51C-4F32-4726-A3FD-F3EDD63DA3A0}.'.
Exception thrown at 0x00007FF83E4E6D9A (KernelBase.dll) in WinFormsControlsTest.exe: 0x40080202: WinRT transform error (parameters: 0x0000000080040155, 0x0000000080004002, 0x000000000000001D, 0x000000BFFDBFC3E0).
Exception thrown at 0x00007FF83E4E6D9A (KernelBase.dll) in WinFormsControlsTest.exe: WinRT originate error - 0x80040155 : 'Failed to find proxy registration for IID: {5C13E51C-4F32-4726-A3FD-F3EDD63DA3A0}.'.
Exception thrown at 0x00007FF83E4E6D9A (KernelBase.dll) in WinFormsControlsTest.exe: 0x40080202: WinRT transform error (parameters: 0x0000000080040155, 0x0000000080004002, 0x000000000000001D, 0x000000BFFDBFC3E0).
Exception thrown at 0x00007FF83E4E6D9A (KernelBase.dll) in WinFormsControlsTest.exe: WinRT originate error - 0x80040155 : 'Failed to find proxy registration for IID: {5C13E51C-4F32-4726-A3FD-F3EDD63DA3A0}.'.
Exception thrown at 0x00007FF83E4E6D9A (KernelBase.dll) in WinFormsControlsTest.exe: 0x40080202: WinRT transform error (parameters: 0x0000000080040155, 0x0000000080004002, 0x000000000000001D, 0x000000BFFDBFC3D0).
MelonWang1 commented 1 month ago

Verified this issue in the latest .Net 9.0 RC2 SDK build: 9.0.100-rc.2.24468.2 + binaries built from Winforms repo main branch, it was fixed. Now no drag-image remnant on the screen after a drag.

https://github.com/user-attachments/assets/dd990700-48bb-4cae-a219-6eeff77dc6fe