-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for drag images and drop descriptions (#6576)
* Allow drop targets to display a drag image while the cursor is over the target window and add support for drop description icons and text. *Narrow the scope to drop targets with support for drop icons and text. *Maintain the default DropTarget behavior with a last flag. *If the application specifies a DropIcon greather than DropIcon.Invalid (default), display the drag image, drop icon, and text specified in the DragEventArgs. *Add a DragDropHelper class to interface with the Shell's drag-image manager and provide methods to get and set the drop description. *Add a DragDrop functional test form to WinformsControlsTest with files for testing drag-and-drop operations. * Tweak the drop description icon names. * Cleanup feedback from RussKie * Build fix * Add IDragSourceHelper2 interface, SHDRAGIMAGE structure, and implement DragDropHelper.SetDragImage(). * Add the Control.DoDratgDrop API for specifying the drag image bitmap. Add support for the drag-and-drop helper object calls to IDataObject::SetData and IDataObject::GetDataHere. * Fix naming rule violation. * Implement a CopyDragDropStgMedium function for copying drag-and-drop storage mediums. * Remove unused DragDropHelper methods and add comments. * Add CopyDragDropStgMedium format validation and comments. * Hide the PictureBox default pointer on the test form. * Cleanup feedback from RussKie. * Tweak DragDropHelper return values. * Fix the cursor from getting stuck and fix the cursor offset. * Fix memory leak and add additional formats. * Allow the application to specify the drag image bitmap via GivefeedbackEventArgs. * Add more comments. * Cleanup some feedback from welkante. Implement change detection for drop descriptions in DragEnter and DragOver. Make DragOver symmetrical in API with DragEnter. * Reject SetData calls which have a non-NULL target device pointer. * Add an internal drag and drop format class to hold related private formats and storage mediums. Encapsulate the logic to copy the storage medium when retrieving the private formats. Include a finalizer and call ReleaseStgMedium to free copied storage mediums marked for release. * Handle when the caller retains ownership of the storage medium and make a copy. * Reject incompatible storage medium types in IDataObject::SetData. * Debug assert null target device pointer. * Cleanup the return and let it fall through like previously. * Add the Control.DoDragDrop API surface. -Optimize the drop description change detection in DropTarget. -Add drag image change detection in DropSource. -Set and get the DropTarget state to help support controls which have a complex internal structure. -Make DragEnter/DragOver more symmetrical. -Handle the DragOver edge case when a new drag image is specified in DropSource.GiveFeedback. -Handle the DragOver edge case when the previous DropTarget state was not DragEnter. * Add the ToolStripItem.DoDragDrop API surface. -Add drag image and drop description support for ToolStrip. -Add a ToolStrip control to the test form for testing drag and drop operations. * Add drag image and drop description support for RichTextBox. * Add a RichTextBox demo to load DragAccept.rtf on DragDrop. * Optimize drop description changes in DragLeave and Drop. * Add a comment regarding IDataObject::GetData and when the Windows drag image manager requests formats that are not currently present in the data object. * Improve the RichTextBox and ToolStrip demos. * Add the InShellDragLoop format. * Add data object support for CF_INDRAGLOOP. -Set the flag to true when setting the initial drag image. -Use the flag to check whether the data object is in a drag-and-drop loop. -Set the flag to false when the data has been dropped. * Use Marshal.ReleaseComObject instead of Marshal.FinalReleaseComObject. * Finish adding support CFSTR_INDRAGLOOP. * Add support for dynamic addition of data during the drag loop through SetData. -Expand the scope of CopyDragDropStgMedium to copy all storage medium types and rename it to CopyStgMedium. * Fix the timing of the flag. * Clean up the comments and code. * Free the DragDropFormat storage mediums after they are no longer in use. * Fix the timing of the drag loop flag. * Give the DragDropFormat appropriate method names. * Set InDragLoop in GiveFeedback for good measure. * Wrap the drag loop in a try finally and reset InDragLoop. * Resolve nullable and mark members as static errors. * Track the DropSource last target handle using IDropSourceNotify::DragEnterTarget If a target has already been entered, call IDropTargetHelper::DragEnter to effectively display new drag images that are set during GiveFeedback. * Cleanup feedback from dotnet api review Align the names of DropImageType with Windows terminology including using the term Image over Icon. - Default -> Invalid - NoDropIcon -> NoImage DragEventArgs - DropIcon -> DropImageType - Insert -> MessageReplacementToken - Mark the Message* properties as nullable. GiveFeedbackEventArgs - Match DoDragDrop bitmap nullability and mark the bitmap non-nullable. * Fix typo * Check if the drop description values specified are valid * Review feedback * Review feedback * Move CopyMedium to the DragDropFormat class and rename it to CopyData * Remove unnecessary return and cleanup the demo * Review feedback * Update DropSource CCW to include support for IDropSourceNotify * Review feedback * Fix MessageReplacementToken conditional * Be explicit about the entry indexes * Review feedback * Wrap the methods calls in a try/catch and return HResult of exception * Remove the unnecessary checks in ToolStripDropTargetManager * Simplify the checks in DropTarget * Simplify the checks in RichTextBox.OleCallback * Simplify the checks in DropSource * Review feedback, first round * Remove the unused using * Better way of checking the incoming data object * Have the designer generate the code * Put the update drag image logic in its own method * Review feedback * Review feedback, second round * Add the <returns> tag and describe the DragDropEffects return value * Add GiveFeedbackEventArgs remarks * Review feedback * Review feedback and encapsulate the event argument equality logic * Review feedback * Fix duplicate symbols * Review feedback * Add DragDropFormat unit tests * Supply named arguments for boolean parameters * Cleanup the data source and variable name * Add DragContext test data and generalize the tests * Add DragDropHelper unit tests * Skip test DragDropHelper_SetDragImage_ReturnsExptected Results in Fatal error 0xC0000005 on Windows_x86 Debug and Release when executed from the command line. * Add DragEventArgsTests for newly added properties * Add GiveFeedbackEventArgs unit tests * Add unit tests that verify thrown exceptions * Add UI integration test for DragEnter * Fix the fatal error on x86 * Tune up the test * Unskip the skipped tests * Fix the hard coded delay * Fix SetDragImage tests -Check for null drag image bits * Review feedback * Check for illegal cross-thread calls in DragDropHelper -Attempts to access shell objects from a multithreaded apartment fail with error E_NOINTERFACE. * Skip the problem tests -These are causing other tests to fail so they are going to detention. * Drag two items in the UI test Co-authored-by: Jeremy Kuhne <[email protected]>
- Loading branch information
1 parent
6491a83
commit 180639b
Showing
51 changed files
with
3,480 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
src/System.Windows.Forms.Primitives/src/Interop/Ole32/Interop.IDropSourceNotify.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Runtime.InteropServices; | ||
|
||
internal partial class Interop | ||
{ | ||
internal static partial class Ole32 | ||
{ | ||
[ComImport] | ||
[Guid("0000012B-0000-0000-C000-000000000046")] | ||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] | ||
public interface IDropSourceNotify | ||
{ | ||
[PreserveSig] | ||
HRESULT DragEnterTarget( | ||
IntPtr hwndTarget); | ||
|
||
[PreserveSig] | ||
HRESULT DragLeaveTarget(); | ||
} | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
src/System.Windows.Forms.Primitives/src/Interop/Ole32/Interop.OleDuplicateData.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Runtime.InteropServices; | ||
using static Interop.Kernel32; | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Ole32 | ||
{ | ||
[DllImport(Libraries.Ole32, ExactSpelling = true)] | ||
public static extern IntPtr OleDuplicateData(IntPtr hSrc, short cfFormat, GMEM uiFlags); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
src/System.Windows.Forms.Primitives/src/Interop/Shell32/Interop.DROPDESCRIPTION.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Runtime.InteropServices; | ||
|
||
internal partial class Interop | ||
{ | ||
internal static partial class Shell32 | ||
{ | ||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] | ||
public unsafe struct DROPDESCRIPTION | ||
{ | ||
public DROPIMAGETYPE type; | ||
private fixed char _szMessage[Kernel32.MAX_PATH]; | ||
private fixed char _szInsert[Kernel32.MAX_PATH]; | ||
|
||
private Span<char> szMessage | ||
{ | ||
get { fixed (char* c = _szMessage) { return new Span<char>(c, Kernel32.MAX_PATH); } } | ||
} | ||
|
||
private Span<char> szInsert | ||
{ | ||
get { fixed (char* c = _szInsert) { return new Span<char>(c, Kernel32.MAX_PATH); } } | ||
} | ||
|
||
public ReadOnlySpan<char> Message | ||
{ | ||
get => szMessage.SliceAtFirstNull(); | ||
set => SpanHelpers.CopyAndTerminate(value, szMessage); | ||
} | ||
|
||
public ReadOnlySpan<char> Insert | ||
{ | ||
get => szInsert.SliceAtFirstNull(); | ||
set => SpanHelpers.CopyAndTerminate(value, szInsert); | ||
} | ||
} | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
src/System.Windows.Forms.Primitives/src/Interop/Shell32/Interop.DROPIMAGETYPE.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
internal partial class Interop | ||
{ | ||
internal static partial class Shell32 | ||
{ | ||
public enum DROPIMAGETYPE | ||
{ | ||
DROPIMAGE_INVALID = -1, | ||
DROPIMAGE_NONE = 0, | ||
DROPIMAGE_COPY = 1, | ||
DROPIMAGE_MOVE = 2, | ||
DROPIMAGE_LINK = 4, | ||
DROPIMAGE_LABEL = 6, | ||
DROPIMAGE_WARNING = 7, | ||
DROPIMAGE_NOIMAGE = 8 | ||
} | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
src/System.Windows.Forms.Primitives/src/Interop/Shell32/Interop.IDragSourceHelper2.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Drawing; | ||
using System.Runtime.InteropServices; | ||
using System.Runtime.InteropServices.ComTypes; | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Shell32 | ||
{ | ||
[ComImport] | ||
[Guid("DE5BF786-477A-11D2-839D-00C04FD918D0")] | ||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] | ||
public interface IDragSourceHelper2 | ||
{ | ||
HRESULT InitializeFromBitmap( | ||
in SHDRAGIMAGE pshdi, | ||
IDataObject dataObject); | ||
|
||
HRESULT InitializeFromWindow( | ||
IntPtr hwnd, | ||
in Point ppt, | ||
IDataObject dataObject); | ||
|
||
HRESULT SetFlags( | ||
int dwFlags); | ||
} | ||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
src/System.Windows.Forms.Primitives/src/Interop/Shell32/Interop.IDropTargetHelper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Drawing; | ||
using System.Runtime.InteropServices; | ||
using IComDataObject = System.Runtime.InteropServices.ComTypes.IDataObject; | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Shell32 | ||
{ | ||
[ComImport] | ||
[Guid("4657278B-411B-11D2-839A-00C04FD918D0")] | ||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] | ||
public interface IDropTargetHelper | ||
{ | ||
[PreserveSig] | ||
HRESULT DragEnter( | ||
IntPtr hwndTarget, | ||
IComDataObject pDataObj, | ||
ref Point ppt, | ||
Ole32.DROPEFFECT dwEffect); | ||
|
||
[PreserveSig] | ||
HRESULT DragLeave(); | ||
|
||
[PreserveSig] | ||
HRESULT DragOver( | ||
ref Point ppt, | ||
Ole32.DROPEFFECT dwEffect); | ||
|
||
[PreserveSig] | ||
HRESULT Drop( | ||
IComDataObject pDataObj, | ||
ref Point ppt, | ||
Ole32.DROPEFFECT dwEffect); | ||
|
||
[PreserveSig] | ||
HRESULT Show( | ||
BOOL fShow); | ||
} | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/System.Windows.Forms.Primitives/src/Interop/Shell32/Interop.SHDRAGIMAGE.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Drawing; | ||
using System.Runtime.InteropServices; | ||
using static Interop.Gdi32; | ||
|
||
internal partial class Interop | ||
{ | ||
internal static partial class Shell32 | ||
{ | ||
[StructLayout(LayoutKind.Sequential)] | ||
public struct SHDRAGIMAGE | ||
{ | ||
public Size sizeDragImage; | ||
public Point ptOffset; | ||
public HBITMAP hbmpDragImage; | ||
public COLORREF crColorKey; | ||
} | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
src/System.Windows.Forms.Primitives/src/Interop/WinFormsComWrappers.IDropSourceNotifyVtbl.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
|
||
internal partial class Interop | ||
{ | ||
internal unsafe partial class WinFormsComWrappers | ||
{ | ||
internal static class IDropSourceNotifyVtbl | ||
{ | ||
public static IntPtr Create(IntPtr fpQueryInterface, IntPtr fpAddRef, IntPtr fpRelease) | ||
{ | ||
IntPtr* vtblRaw = (IntPtr*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(IDropSourceNotifyVtbl), IntPtr.Size * 5); | ||
vtblRaw[0] = fpQueryInterface; | ||
vtblRaw[1] = fpAddRef; | ||
vtblRaw[2] = fpRelease; | ||
vtblRaw[3] = (IntPtr)(delegate* unmanaged<IntPtr, IntPtr, HRESULT>)&DragEnterTarget; | ||
vtblRaw[4] = (IntPtr)(delegate* unmanaged<IntPtr, HRESULT>)&DragLeaveTarget; | ||
|
||
return (IntPtr)vtblRaw; | ||
} | ||
|
||
[UnmanagedCallersOnly] | ||
private static HRESULT DragEnterTarget(IntPtr thisPtr, IntPtr hwndTarget) | ||
{ | ||
try | ||
{ | ||
var instance = ComInterfaceDispatch.GetInstance<Ole32.IDropSourceNotify>((ComInterfaceDispatch*)thisPtr); | ||
return instance.DragEnterTarget(hwndTarget); | ||
} | ||
catch (Exception ex) | ||
{ | ||
return (HRESULT)ex.HResult; | ||
} | ||
} | ||
|
||
[UnmanagedCallersOnly] | ||
private static HRESULT DragLeaveTarget(IntPtr thisPtr) | ||
{ | ||
try | ||
{ | ||
var instance = ComInterfaceDispatch.GetInstance<Ole32.IDropSourceNotify>((ComInterfaceDispatch*)thisPtr); | ||
return instance.DragLeaveTarget(); | ||
} | ||
catch (Exception ex) | ||
{ | ||
return (HRESULT)ex.HResult; | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,26 @@ | ||
~override System.Windows.Forms.WebBrowser.CreateAccessibilityInstance() -> System.Windows.Forms.AccessibleObject | ||
System.Windows.Forms.DropImageType | ||
System.Windows.Forms.DropImageType.Invalid = -1 -> System.Windows.Forms.DropImageType | ||
System.Windows.Forms.DropImageType.None = 0 -> System.Windows.Forms.DropImageType | ||
System.Windows.Forms.DropImageType.Copy = 1 -> System.Windows.Forms.DropImageType | ||
System.Windows.Forms.DropImageType.Move = 2 -> System.Windows.Forms.DropImageType | ||
System.Windows.Forms.DropImageType.Link = 4 -> System.Windows.Forms.DropImageType | ||
System.Windows.Forms.DropImageType.Label = 6 -> System.Windows.Forms.DropImageType | ||
System.Windows.Forms.DropImageType.Warning = 7 -> System.Windows.Forms.DropImageType | ||
System.Windows.Forms.DropImageType.NoImage = 8 -> System.Windows.Forms.DropImageType | ||
~System.Windows.Forms.Control.DoDragDrop(object data, System.Windows.Forms.DragDropEffects allowedEffects, System.Drawing.Bitmap dragImage, System.Drawing.Point cursorOffset, bool useDefaultDragImage) -> System.Windows.Forms.DragDropEffects | ||
~System.Windows.Forms.ToolStripItem.DoDragDrop(object data, System.Windows.Forms.DragDropEffects allowedEffects, System.Drawing.Bitmap dragImage, System.Drawing.Point cursorOffset, bool useDefaultDragImage) -> System.Windows.Forms.DragDropEffects | ||
System.Windows.Forms.DragEventArgs.DragEventArgs(System.Windows.Forms.IDataObject? data, int keyState, int x, int y, System.Windows.Forms.DragDropEffects allowedEffect, System.Windows.Forms.DragDropEffects effect, System.Windows.Forms.DropImageType dropImageType, string! message, string! messageReplacementToken) -> void | ||
System.Windows.Forms.DragEventArgs.DropImageType.get -> System.Windows.Forms.DropImageType | ||
System.Windows.Forms.DragEventArgs.DropImageType.set -> void | ||
System.Windows.Forms.DragEventArgs.Message.get -> string? | ||
System.Windows.Forms.DragEventArgs.Message.set -> void | ||
System.Windows.Forms.DragEventArgs.MessageReplacementToken.get -> string? | ||
System.Windows.Forms.DragEventArgs.MessageReplacementToken.set -> void | ||
System.Windows.Forms.GiveFeedbackEventArgs.GiveFeedbackEventArgs(System.Windows.Forms.DragDropEffects effect, bool useDefaultCursors, System.Drawing.Bitmap? dragImage, System.Drawing.Point cursorOffset, bool useDefaultDragImage) -> void | ||
System.Windows.Forms.GiveFeedbackEventArgs.CursorOffset.get -> System.Drawing.Point | ||
System.Windows.Forms.GiveFeedbackEventArgs.CursorOffset.set -> void | ||
System.Windows.Forms.GiveFeedbackEventArgs.DragImage.get -> System.Drawing.Bitmap? | ||
System.Windows.Forms.GiveFeedbackEventArgs.DragImage.set -> void | ||
System.Windows.Forms.GiveFeedbackEventArgs.UseDefaultDragImage.get -> bool | ||
System.Windows.Forms.GiveFeedbackEventArgs.UseDefaultDragImage.set -> void | ||
~override System.Windows.Forms.WebBrowser.CreateAccessibilityInstance() -> System.Windows.Forms.AccessibleObject |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.