From b2b2634059e24e73d8927cdac14ef83aa4017cb6 Mon Sep 17 00:00:00 2001 From: johna-ms <63807693+johna-ms@users.noreply.github.com> Date: Mon, 21 Oct 2024 14:15:58 -0700 Subject: [PATCH 1/8] Create DragStartingEvent.md Start API review for DragStarting event on the CompositionController --- specs/DragStartingEvent.md | 194 +++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 specs/DragStartingEvent.md diff --git a/specs/DragStartingEvent.md b/specs/DragStartingEvent.md new file mode 100644 index 00000000..fdad2da9 --- /dev/null +++ b/specs/DragStartingEvent.md @@ -0,0 +1,194 @@ +DragStarting +=== + +# Background +The WebView2 team has been asked to provide a way to override the default drag drop behavior when running in visual hosting mode. This event allows you to know when a drag is initiated in WebView2 and provides the state necessary to override the default WebView2 drag operation with your own logic. + +# Examples +## DragStarting +Users can use `add_DragStarting` on the CompositionController to add an event handler +that is invoked when drag is starting. They can use the event args to start their own +drag or they can just set `Handled` to `FALSE` to ignore the drag. + +```C++ +CHECK_FAILURE(m_compControllerStaging->add_DragStarting( + Callback( + [this](ICoreWebView2CompositionController* sender, ICoreWebView2StagingDragStartingEventArgs* args) + { + if (m_dragOverrideMode != DragOverrideMode::OVERRIDE) + { + // If the event is marked handled, WebView2 will not execute its drag logic. + args->put_Handled(m_dragOverrideMode == DragOverrideMode::NOOP); + return S_OK; + } + + COREWEBVIEW2_DRAG_EFFECTS allowedEffects; + POINT dragPosition; + wil::com_ptr dragData; + wil::com_ptr deferral; + + args->get_DragAllowedOperations(&allowedEffects); + args->get_DragPosition(&dragPosition); + args->get_DragData(&dragData); + args->GetDeferral(&deferral); + + HRESULT hr = S_OK; + if (!m_oleInitialized) + { + hr = OleInitialize(nullptr); + if (SUCCEEDED(hr)) + { + m_oleInitialized = true; + } + } + + if (!m_dropSource) + { + m_dropSource = Make(); + } + + if (SUCCEEDED(hr)) + { + DWORD effect; + DWORD okEffects = DROPEFFECT_NONE; + if (allowedEffects & COREWEBVIEW2_DRAG_EFFECTS_COPY) + { + okEffects |= DROPEFFECT_COPY; + } + if (allowedEffects & COREWEBVIEW2_DRAG_EFFECTS_MOVE) + { + okEffects |= DROPEFFECT_MOVE; + } + if (allowedEffects & COREWEBVIEW2_DRAG_EFFECTS_LINK) + { + okEffects |= DROPEFFECT_LINK; + } + + hr = DoDragDrop(dragData.get(), m_dropSource.get(), okEffects, &effect); + } + + deferral->Complete(); + args->put_Handled(TRUE); + + return hr; + }) + .Get(), + &m_dragStartingToken)); +``` + +# API Details +```C++ +/// Flags enum that represents the effects that a given WebView2 drag drop operation can have. +[v1_enum] +typedef enum COREWEBVIEW2_DRAG_EFFECTS { + /// Drag operation supports no effect. + COREWEBVIEW2_DRAG_EFFECTS_NONE = 0x0, + /// Drag operation supports copying data. + COREWEBVIEW2_DRAG_EFFECTS_COPY = 0x1, + /// Drag operation supports moving data. + COREWEBVIEW2_DRAG_EFFECTS_MOVE = 0x2, + /// Drag operation supports linking data. + COREWEBVIEW2_DRAG_EFFECTS_LINK = 0x4, +} COREWEBVIEW2_DRAG_EFFECTS; +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(COREWEBVIEW2_DRAG_EFFECTS)") + +/// Event args for the `DragStarting` event. +[uuid(edb6b243-334f-59d0-b3b3-de87dd401adc), object, pointer_default(unique)] +interface ICoreWebView2StagingDragStartingEventArgs : IUnknown { + /// The operations this drag data supports. + [propget] HRESULT DragAllowedOperations([out, retval] COREWEBVIEW2_DRAG_EFFECTS* value); + + + /// The data being dragged. + [propget] HRESULT DragData([out, retval] IDataObject** value); + + /// The position at which drag was detected. + [propget] HRESULT DragPosition([out, retval] POINT* value); + + + /// Gets the `Handled` property. + [propget] HRESULT Handled([out, retval] BOOL* value); + + + /// Indicates whether this event has been handled by the app. If the + /// app handles this event, WebView2 will not initiate drag drop. If + /// the app does not handle the event, WebView2 will initiate its own + /// drag drop logic. + [propput] HRESULT Handled([in] BOOL value); + + + + /// Returns an `ICoreWebView2Deferral` object. Use this operation to complete + /// the CoreWebView2DragStartingEventArgs. + /// + /// Until the deferral is completed, subsequent attempts to initiate drag + /// in the WebView2 will fail and if the cursor was changed as part of + /// drag it will not restore. + HRESULT GetDeferral( + [out, retval] ICoreWebView2Deferral** value); + + +} + +/// Receives `DragStarting` events. +[uuid(3b149321-83c3-5d1f-b03f-a42899bc1c15), object, pointer_default(unique)] +interface ICoreWebView2StagingDragStartingEventHandler : IUnknown { + /// Provides the event args for the corresponding event. + HRESULT Invoke( + [in] ICoreWebView2CompositionController* sender, + [in] ICoreWebView2StagingDragStartingEventArgs* args); +} + +/// A continuation of the ICoreWebView2CompositionController4 interface. +/// This interface includes an API which exposes the DragStarting event. +[uuid(975d6824-6a02-5e98-ab7c-e4679d5357f4), object, pointer_default(unique)] +interface ICoreWebView2StagingCompositionController : IUnknown { + /// Adds an event handler for the `DragStarting` event. + /// Adds an event handler for the `DragStarting` event. `DragStarting` is + /// raised when the WebView2 detects a drag started within the WebView2. + /// This event can be used to override WebView2's default drag starting + /// logic. + HRESULT add_DragStarting( + [in] ICoreWebView2StagingDragStartingEventHandler* eventHandler, + [out] EventRegistrationToken* token); + + /// Removes an event handler previously added with `add_DragStarting`. + HRESULT remove_DragStarting( + [in] EventRegistrationToken token); + + +} +``` +```c# (but really MIDL3) + runtimeclass CoreWebView2DragStartingEventArgs + { + + Windows.ApplicationModel.DataTransfer.DataPackageOperation DragAllowedOperations { get; }; + + Windows.ApplicationModel.DataTransfer.DataPackage DragData { get; }; + + Windows.Foundation.Point DragPosition { get; }; + + Boolean Handled { get; set; }; + + + Windows.Foundation.Deferral GetDeferral(); + + + + } + + runtimeclass CoreWebView2CompositionController : CoreWebView2Controller + { + // ... + [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2StagingCompositionController")] + { + + event Windows.Foundation.TypedEventHandler DragStarting; + + + + } + // ... + } +``` From 74e7ca023b02fb1ff2905b155f1e2c0e242a358f Mon Sep 17 00:00:00 2001 From: "John An (from Dev Box)" Date: Mon, 21 Oct 2024 14:29:41 -0700 Subject: [PATCH 2/8] Changing file name, changing branch name, and making examples description a little more descriptive --- specs/{DragStartingEvent.md => DragStarting.md} | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) rename specs/{DragStartingEvent.md => DragStarting.md} (95%) diff --git a/specs/DragStartingEvent.md b/specs/DragStarting.md similarity index 95% rename from specs/DragStartingEvent.md rename to specs/DragStarting.md index fdad2da9..939c5f28 100644 --- a/specs/DragStartingEvent.md +++ b/specs/DragStarting.md @@ -7,8 +7,10 @@ The WebView2 team has been asked to provide a way to override the default drag d # Examples ## DragStarting Users can use `add_DragStarting` on the CompositionController to add an event handler -that is invoked when drag is starting. They can use the event args to start their own -drag or they can just set `Handled` to `FALSE` to ignore the drag. +that is invoked when drag is starting. They can use the the event args to start their own +drag. Notably the `Deferral` can be used to execute any async drag logic and call back into +the WebView at a later time. The `Handled` property lets the WebView2 know whether to +exercise its own drag logic or not. ```C++ CHECK_FAILURE(m_compControllerStaging->add_DragStarting( From ec4af35a0590b428eb4f7da005fba25d423026ae Mon Sep 17 00:00:00 2001 From: "John An (from Dev Box)" Date: Wed, 23 Oct 2024 18:39:36 -0700 Subject: [PATCH 3/8] Responding to comments made on spec. --- specs/DragStarting.md | 154 ++++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 73 deletions(-) diff --git a/specs/DragStarting.md b/specs/DragStarting.md index 939c5f28..c71d390b 100644 --- a/specs/DragStarting.md +++ b/specs/DragStarting.md @@ -2,85 +2,87 @@ DragStarting === # Background -The WebView2 team has been asked to provide a way to override the default drag drop behavior when running in visual hosting mode. This event allows you to know when a drag is initiated in WebView2 and provides the state necessary to override the default WebView2 drag operation with your own logic. +The WebView2 team has been asked to provide a way to override the default drag +drop behavior when running in visual hosting mode. This event allows you to know +when a drag is initiated in WebView2 and provides the state necessary to override +the default WebView2 drag operation with your own logic. # Examples ## DragStarting -Users can use `add_DragStarting` on the CompositionController to add an event handler -that is invoked when drag is starting. They can use the the event args to start their own -drag. Notably the `Deferral` can be used to execute any async drag logic and call back into -the WebView at a later time. The `Handled` property lets the WebView2 know whether to -exercise its own drag logic or not. +Users can use `add_DragStarting` on the CompositionController to add an event +handler that is invoked when drag is starting. They can use the the event args +to start their own drag. Notably the `Deferral` can be used to execute any async +drag logic and call back into the WebView at a later time. The `Handled` +property lets the WebView2 know whether to exercise its own drag logic or not. ```C++ -CHECK_FAILURE(m_compControllerStaging->add_DragStarting( - Callback( - [this](ICoreWebView2CompositionController* sender, ICoreWebView2StagingDragStartingEventArgs* args) +// Using DragStarting to simply make a synchronous DoDragDrop call instead of +// having WebView2 do it. +CHECK_FAILURE(m_compController5->add_DragStarting( + Callback( + [this](ICoreWebView2CompositionController5* sender, + ICoreWebView2DragStartingEventArgs* args) { - if (m_dragOverrideMode != DragOverrideMode::OVERRIDE) - { - // If the event is marked handled, WebView2 will not execute its drag logic. - args->put_Handled(m_dragOverrideMode == DragOverrideMode::NOOP); - return S_OK; - } - - COREWEBVIEW2_DRAG_EFFECTS allowedEffects; - POINT dragPosition; + COREWEBVIEW2_DRAG_EFFECTS allowedEffects = + COREWEBVIEW2_DRAG_EFFECTS_NONE; + POINT dragPosition = {0, 0}; wil::com_ptr dragData; - wil::com_ptr deferral; - args->get_DragAllowedOperations(&allowedEffects); - args->get_DragPosition(&dragPosition); - args->get_DragData(&dragData); - args->GetDeferral(&deferral); - - HRESULT hr = S_OK; - if (!m_oleInitialized) - { - hr = OleInitialize(nullptr); - if (SUCCEEDED(hr)) - { - m_oleInitialized = true; - } - } + CHECK_FAILURE(args->get_AllowedOperations(&allowedEffects)); + CHECK_FAILURE(args->get_Position(&dragPosition)); + CHECK_FAILURE(args->get_Data(&dragData)); if (!m_dropSource) { m_dropSource = Make(); } - if (SUCCEEDED(hr)) + DWORD effect; + DWORD okEffects = DROPEFFECT_NONE; + if (allowedEffects & COREWEBVIEW2_DRAG_EFFECTS_COPY) + { + okEffects |= DROPEFFECT_COPY; + } + if (allowedEffects & COREWEBVIEW2_DRAG_EFFECTS_MOVE) + { + okEffects |= DROPEFFECT_MOVE; + } + if (allowedEffects & COREWEBVIEW2_DRAG_EFFECTS_LINK) { - DWORD effect; - DWORD okEffects = DROPEFFECT_NONE; - if (allowedEffects & COREWEBVIEW2_DRAG_EFFECTS_COPY) - { - okEffects |= DROPEFFECT_COPY; - } - if (allowedEffects & COREWEBVIEW2_DRAG_EFFECTS_MOVE) - { - okEffects |= DROPEFFECT_MOVE; - } - if (allowedEffects & COREWEBVIEW2_DRAG_EFFECTS_LINK) - { - okEffects |= DROPEFFECT_LINK; - } - - hr = DoDragDrop(dragData.get(), m_dropSource.get(), okEffects, &effect); + okEffects |= DROPEFFECT_LINK; } - deferral->Complete(); - args->put_Handled(TRUE); + HRESULT hr = DoDragDrop( + dragData.get(), m_dropSource.get(), okEffects, &effect); + + args->put_Handled(SUCCEEDED(hr)); return hr; }) .Get(), &m_dragStartingToken)); + +// Using DragStarting to no-op a drag operation. +CHECK_FAILURE(m_compController5->add_DragStarting( + Callback( + [this](ICoreWebView2CompositionController5* sender, + ICoreWebView2DragStartingEventArgs* args) + { + // If the event is marked handled, WebView2 will not execute its + // drag logic. + args->put_Handled(m_dragOverrideMode == DragOverrideMode::NOOP); + return S_OK; + }) + .Get(), + &m_dragStartingToken)); ``` # API Details ```C++ -/// Flags enum that represents the effects that a given WebView2 drag drop operation can have. +/// Flags enum that represents the effects that a given WebView2 drag drop +/// operation can have. The values of this enum align with the ole DROPEFFECT +/// constant with the exception of DROPEFFECT_SCROLL which is only relevant for +/// drop and therefore unsupported. [v1_enum] typedef enum COREWEBVIEW2_DRAG_EFFECTS { /// Drag operation supports no effect. @@ -96,16 +98,18 @@ cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(COREWEBVIEW2_DRAG_EFFECTS)") /// Event args for the `DragStarting` event. [uuid(edb6b243-334f-59d0-b3b3-de87dd401adc), object, pointer_default(unique)] -interface ICoreWebView2StagingDragStartingEventArgs : IUnknown { +interface ICoreWebView2DragStartingEventArgs : IUnknown { /// The operations this drag data supports. - [propget] HRESULT DragAllowedOperations([out, retval] COREWEBVIEW2_DRAG_EFFECTS* value); + [propget] HRESULT AllowedOperations( + [out, retval] COREWEBVIEW2_DRAG_EFFECTS* value); /// The data being dragged. - [propget] HRESULT DragData([out, retval] IDataObject** value); + [propget] HRESULT Data([out, retval] IDataObject** value); - /// The position at which drag was detected. - [propget] HRESULT DragPosition([out, retval] POINT* value); + /// The position at which drag was detected. This position is given in + /// screen pixel coordinates as opposed to WebView2 relative coordinates. + [propget] HRESULT Position([out, retval] POINT* value); /// Gets the `Handled` property. @@ -134,24 +138,25 @@ interface ICoreWebView2StagingDragStartingEventArgs : IUnknown { /// Receives `DragStarting` events. [uuid(3b149321-83c3-5d1f-b03f-a42899bc1c15), object, pointer_default(unique)] -interface ICoreWebView2StagingDragStartingEventHandler : IUnknown { +interface ICoreWebView2DragStartingEventHandler : IUnknown { /// Provides the event args for the corresponding event. HRESULT Invoke( - [in] ICoreWebView2CompositionController* sender, - [in] ICoreWebView2StagingDragStartingEventArgs* args); + [in] ICoreWebView2CompositionController5* sender, + [in] ICoreWebView2DragStartingEventArgs* args); } /// A continuation of the ICoreWebView2CompositionController4 interface. /// This interface includes an API which exposes the DragStarting event. [uuid(975d6824-6a02-5e98-ab7c-e4679d5357f4), object, pointer_default(unique)] -interface ICoreWebView2StagingCompositionController : IUnknown { - /// Adds an event handler for the `DragStarting` event. +interface ICoreWebView2CompositionController5 : IUnknown { /// Adds an event handler for the `DragStarting` event. `DragStarting` is /// raised when the WebView2 detects a drag started within the WebView2. - /// This event can be used to override WebView2's default drag starting - /// logic. + /// WebView2's default drag behavior is to synchronously call DoDragDrop when + /// it detects drag. This event's args expose the data WebView2 uses to call + /// DoDragDrop to allow users to implement their own drag logic and override + /// WebView2's. HRESULT add_DragStarting( - [in] ICoreWebView2StagingDragStartingEventHandler* eventHandler, + [in] ICoreWebView2DragStartingEventHandler* eventHandler, [out] EventRegistrationToken* token); /// Removes an event handler previously added with `add_DragStarting`. @@ -162,14 +167,16 @@ interface ICoreWebView2StagingCompositionController : IUnknown { } ``` ```c# (but really MIDL3) +namespace Microoft.Web.WebView2 { runtimeclass CoreWebView2DragStartingEventArgs { - Windows.ApplicationModel.DataTransfer.DataPackageOperation DragAllowedOperations { get; }; + Windows.ApplicationModel.DataTransfer.DataPackageOperation + AllowedOperations { get; }; - Windows.ApplicationModel.DataTransfer.DataPackage DragData { get; }; + Windows.ApplicationModel.DataTransfer.DataPackage Data { get; }; - Windows.Foundation.Point DragPosition { get; }; + Windows.Foundation.Point Position { get; }; Boolean Handled { get; set; }; @@ -183,14 +190,15 @@ interface ICoreWebView2StagingCompositionController : IUnknown { runtimeclass CoreWebView2CompositionController : CoreWebView2Controller { // ... - [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2StagingCompositionController")] + [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2CompositionController5")] { - - event Windows.Foundation.TypedEventHandler DragStarting; - + event Windows.Foundation.TypedEventHandler< + CoreWebView2CompositionController, + CoreWebView2DragStartingEventArgs> DragStarting; } // ... } +} ``` From d7bfa124b347d529cbe28cae6056eaa04cc6bfb7 Mon Sep 17 00:00:00 2001 From: "John An (from Dev Box)" Date: Fri, 25 Oct 2024 17:33:38 -0700 Subject: [PATCH 4/8] Adding interop interface, removing C#/midl 3 declaration. Adding note why .NET and WinRT will not be done --- specs/DragStarting.md | 85 +++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/specs/DragStarting.md b/specs/DragStarting.md index c71d390b..c9643cbd 100644 --- a/specs/DragStarting.md +++ b/specs/DragStarting.md @@ -7,6 +7,12 @@ drop behavior when running in visual hosting mode. This event allows you to know when a drag is initiated in WebView2 and provides the state necessary to override the default WebView2 drag operation with your own logic. +## Note about .NET/WinRT projection +The work to project this API to .NET and WinRT are yet to be completed. Overall +usage of this API is expected to be uncommon. There are no known public asks for +this. Further, this API is exposed on the CompositionController which is very +rarely used in .NET apps. + # Examples ## DragStarting Users can use `add_DragStarting` on the CompositionController to add an event @@ -124,6 +130,49 @@ interface ICoreWebView2DragStartingEventArgs : IUnknown { + /// Returns an `ICoreWebView2Deferral` object. Use this operation to complete + /// the CoreWebView2DragStartingEventArgs. + /// + /// Until the deferral is completed, subsequent attempts to initiate drag + /// in the WebView2 will fail and if the cursor was changed as part of + /// drag it will not restore. + HRESULT GetDeferral( + [out, retval] ICoreWebView2Deferral** value); + + +} + +/// Interop interface for the CoreWebView2DragStartingEventArgs WinRT object to +/// allow WinRT end developers to be able to access the COM interface arguments. +/// This interface is implemented by the +/// Microsoft.Web.WebView2.Core.CoreWebView2DragStartingEventArgs runtime class. +[uuid(7a4daef9-1701-463f-992d-2136460cf76e), object, pointer_default(unique)] +interface ICoreWebView2StagingDragStartingEventArgsInterop : IUnknown { + /// The operations this drag data supports. + [propget] HRESULT AllowedOperations( + [out, retval] COREWEBVIEW2_DRAG_EFFECTS* value); + + + /// The data being dragged. + [propget] HRESULT Data([out, retval] IDataObject** value); + + /// The position at which drag was detected. This position is given in + /// screen pixel coordinates as opposed to WebView2 relative coordinates. + [propget] HRESULT Position([out, retval] POINT* value); + + + /// Gets the `Handled` property. + [propget] HRESULT Handled([out, retval] BOOL* value); + + + /// Indicates whether this event has been handled by the app. If the + /// app handles this event, WebView2 will not initiate drag drop. If + /// the app does not handle the event, WebView2 will initiate its own + /// drag drop logic. + [propput] HRESULT Handled([in] BOOL value); + + + /// Returns an `ICoreWebView2Deferral` object. Use this operation to complete /// the CoreWebView2DragStartingEventArgs. /// @@ -166,39 +215,3 @@ interface ICoreWebView2CompositionController5 : IUnknown { } ``` -```c# (but really MIDL3) -namespace Microoft.Web.WebView2 { - runtimeclass CoreWebView2DragStartingEventArgs - { - - Windows.ApplicationModel.DataTransfer.DataPackageOperation - AllowedOperations { get; }; - - Windows.ApplicationModel.DataTransfer.DataPackage Data { get; }; - - Windows.Foundation.Point Position { get; }; - - Boolean Handled { get; set; }; - - - Windows.Foundation.Deferral GetDeferral(); - - - - } - - runtimeclass CoreWebView2CompositionController : CoreWebView2Controller - { - // ... - [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2CompositionController5")] - { - event Windows.Foundation.TypedEventHandler< - CoreWebView2CompositionController, - CoreWebView2DragStartingEventArgs> DragStarting; - - - } - // ... - } -} -``` From 58f65968217d7cbf89c85bf763e93a71fd0ebd05 Mon Sep 17 00:00:00 2001 From: "John An (from Dev Box)" Date: Tue, 29 Oct 2024 18:51:01 -0700 Subject: [PATCH 5/8] Changing interop interface to be controller instead of args --- specs/DragStarting.md | 64 ++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 43 deletions(-) diff --git a/specs/DragStarting.md b/specs/DragStarting.md index c9643cbd..04a89c5d 100644 --- a/specs/DragStarting.md +++ b/specs/DragStarting.md @@ -130,49 +130,6 @@ interface ICoreWebView2DragStartingEventArgs : IUnknown { - /// Returns an `ICoreWebView2Deferral` object. Use this operation to complete - /// the CoreWebView2DragStartingEventArgs. - /// - /// Until the deferral is completed, subsequent attempts to initiate drag - /// in the WebView2 will fail and if the cursor was changed as part of - /// drag it will not restore. - HRESULT GetDeferral( - [out, retval] ICoreWebView2Deferral** value); - - -} - -/// Interop interface for the CoreWebView2DragStartingEventArgs WinRT object to -/// allow WinRT end developers to be able to access the COM interface arguments. -/// This interface is implemented by the -/// Microsoft.Web.WebView2.Core.CoreWebView2DragStartingEventArgs runtime class. -[uuid(7a4daef9-1701-463f-992d-2136460cf76e), object, pointer_default(unique)] -interface ICoreWebView2StagingDragStartingEventArgsInterop : IUnknown { - /// The operations this drag data supports. - [propget] HRESULT AllowedOperations( - [out, retval] COREWEBVIEW2_DRAG_EFFECTS* value); - - - /// The data being dragged. - [propget] HRESULT Data([out, retval] IDataObject** value); - - /// The position at which drag was detected. This position is given in - /// screen pixel coordinates as opposed to WebView2 relative coordinates. - [propget] HRESULT Position([out, retval] POINT* value); - - - /// Gets the `Handled` property. - [propget] HRESULT Handled([out, retval] BOOL* value); - - - /// Indicates whether this event has been handled by the app. If the - /// app handles this event, WebView2 will not initiate drag drop. If - /// the app does not handle the event, WebView2 will initiate its own - /// drag drop logic. - [propput] HRESULT Handled([in] BOOL value); - - - /// Returns an `ICoreWebView2Deferral` object. Use this operation to complete /// the CoreWebView2DragStartingEventArgs. /// @@ -213,5 +170,26 @@ interface ICoreWebView2CompositionController5 : IUnknown { [in] EventRegistrationToken token); +} + +/// Interop interface for the CoreWebView2CompositionController WinRT object to +/// allow WinRT end developers to be able to access the COM interface arguments. +/// This interface is implemented by the +/// Microsoft.Web.WebView2.Core.CoreWebView2CompositionController runtime class. +[uuid(7a4daef9-1701-463f-992d-2136460cf76e), object, pointer_default(unique)] +interface ICoreWebView2StagingCompositionControllerInterop : IUnknown { + /// Adds an event handler for the `DragStarting` event. `DragStarting` is + /// raised when the WebView2 detects a drag started within the WebView2. + /// This event can be used to override WebView2's default drag starting + /// logic. + HRESULT add_DragStarting( + [in] ICoreWebView2StagingDragStartingEventHandler* eventHandler, + [out] EventRegistrationToken* token); + + /// Removes an event handler previously added with `add_DragStarting`. + HRESULT remove_DragStarting( + [in] EventRegistrationToken token); + + } ``` From 042c2b4130657184c76d67d84d10fcd3d7e7654a Mon Sep 17 00:00:00 2001 From: "John An (from Dev Box)" Date: Wed, 30 Oct 2024 14:18:24 -0700 Subject: [PATCH 6/8] Addressing feedback --- specs/DragStarting.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/specs/DragStarting.md b/specs/DragStarting.md index 04a89c5d..a50dbbcd 100644 --- a/specs/DragStarting.md +++ b/specs/DragStarting.md @@ -21,6 +21,7 @@ to start their own drag. Notably the `Deferral` can be used to execute any async drag logic and call back into the WebView at a later time. The `Handled` property lets the WebView2 know whether to exercise its own drag logic or not. +## Override drag and drop ```C++ // Using DragStarting to simply make a synchronous DoDragDrop call instead of // having WebView2 do it. @@ -67,7 +68,10 @@ CHECK_FAILURE(m_compController5->add_DragStarting( }) .Get(), &m_dragStartingToken)); +``` +## Disable drag and drop +```C++ // Using DragStarting to no-op a drag operation. CHECK_FAILURE(m_compController5->add_DragStarting( Callback( @@ -76,7 +80,7 @@ CHECK_FAILURE(m_compController5->add_DragStarting( { // If the event is marked handled, WebView2 will not execute its // drag logic. - args->put_Handled(m_dragOverrideMode == DragOverrideMode::NOOP); + args->put_Handled(TRUE); return S_OK; }) .Get(), @@ -125,7 +129,7 @@ interface ICoreWebView2DragStartingEventArgs : IUnknown { /// Indicates whether this event has been handled by the app. If the /// app handles this event, WebView2 will not initiate drag drop. If /// the app does not handle the event, WebView2 will initiate its own - /// drag drop logic. + /// drag drop logic. The default value is FALSE. [propput] HRESULT Handled([in] BOOL value); From b3dc1e30233ef254bfdbb44582c7c5c16f741a95 Mon Sep 17 00:00:00 2001 From: "John An (from Dev Box)" Date: Tue, 5 Nov 2024 19:47:48 -0800 Subject: [PATCH 7/8] Responding to feedback --- specs/DragStarting.md | 76 +++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/specs/DragStarting.md b/specs/DragStarting.md index a50dbbcd..bed9ea23 100644 --- a/specs/DragStarting.md +++ b/specs/DragStarting.md @@ -16,7 +16,7 @@ rarely used in .NET apps. # Examples ## DragStarting Users can use `add_DragStarting` on the CompositionController to add an event -handler that is invoked when drag is starting. They can use the the event args +handler that is invoked when drag is starting. They can use the event args to start their own drag. Notably the `Deferral` can be used to execute any async drag logic and call back into the WebView at a later time. The `Handled` property lets the WebView2 know whether to exercise its own drag logic or not. @@ -30,37 +30,24 @@ CHECK_FAILURE(m_compController5->add_DragStarting( [this](ICoreWebView2CompositionController5* sender, ICoreWebView2DragStartingEventArgs* args) { - COREWEBVIEW2_DRAG_EFFECTS allowedEffects = - COREWEBVIEW2_DRAG_EFFECTS_NONE; + DWORD allowedEffects = COREWEBVIEW2_DROP_EFFECTS_NONE; POINT dragPosition = {0, 0}; wil::com_ptr dragData; - CHECK_FAILURE(args->get_AllowedOperations(&allowedEffects)); + CHECK_FAILURE(args->get_AllowedDropEffects(&allowedEffects)); CHECK_FAILURE(args->get_Position(&dragPosition)); CHECK_FAILURE(args->get_Data(&dragData)); + // This member refers to an implementation of IDropSource. It is an + // OLE interface that is necessary to initiate drag in an application. + // https://learn.microsoft.com/en-us/windows/win32/api/oleidl/nn-oleidl-idropsource if (!m_dropSource) { m_dropSource = Make(); } - DWORD effect; - DWORD okEffects = DROPEFFECT_NONE; - if (allowedEffects & COREWEBVIEW2_DRAG_EFFECTS_COPY) - { - okEffects |= DROPEFFECT_COPY; - } - if (allowedEffects & COREWEBVIEW2_DRAG_EFFECTS_MOVE) - { - okEffects |= DROPEFFECT_MOVE; - } - if (allowedEffects & COREWEBVIEW2_DRAG_EFFECTS_LINK) - { - okEffects |= DROPEFFECT_LINK; - } - HRESULT hr = DoDragDrop( - dragData.get(), m_dropSource.get(), okEffects, &effect); + dragData.get(), m_dropSource.get(), allowedEffects, &effect); args->put_Handled(SUCCEEDED(hr)); @@ -89,36 +76,29 @@ CHECK_FAILURE(m_compController5->add_DragStarting( # API Details ```C++ -/// Flags enum that represents the effects that a given WebView2 drag drop -/// operation can have. The values of this enum align with the ole DROPEFFECT -/// constant with the exception of DROPEFFECT_SCROLL which is only relevant for -/// drop and therefore unsupported. -[v1_enum] -typedef enum COREWEBVIEW2_DRAG_EFFECTS { - /// Drag operation supports no effect. - COREWEBVIEW2_DRAG_EFFECTS_NONE = 0x0, - /// Drag operation supports copying data. - COREWEBVIEW2_DRAG_EFFECTS_COPY = 0x1, - /// Drag operation supports moving data. - COREWEBVIEW2_DRAG_EFFECTS_MOVE = 0x2, - /// Drag operation supports linking data. - COREWEBVIEW2_DRAG_EFFECTS_LINK = 0x4, -} COREWEBVIEW2_DRAG_EFFECTS; -cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(COREWEBVIEW2_DRAG_EFFECTS)") +/// DWORD constants that represent the effects that a given WebView2 drag drop +/// operation can have. The values of this enum align with the +/// [OLE DROPEFFECT constant](https://learn.microsoft.com/en-us/windows/win32/com/dropeffect-constants) +/// with the exception of DROPEFFECT_SCROLL which is unused in WebView2 drag +/// drop scenarios. +const DWORD COREWEBVIEW2_DROP_EFFECTS_NONE = 0; +const DWORD COREWEBVIEW2_DROP_EFFECTS_COPY = 1; +const DWORD COREWEBVIEW2_DROP_EFFECTS_MOVE = 2; +const DWORD COREWEBVIEW2_DROP_EFFECTS_LINK = 4; /// Event args for the `DragStarting` event. [uuid(edb6b243-334f-59d0-b3b3-de87dd401adc), object, pointer_default(unique)] interface ICoreWebView2DragStartingEventArgs : IUnknown { /// The operations this drag data supports. - [propget] HRESULT AllowedOperations( - [out, retval] COREWEBVIEW2_DRAG_EFFECTS* value); + [propget] HRESULT AllowedDropEffects( + [out, retval] COREWEBVIEW2_DROP_EFFECTS* value); /// The data being dragged. [propget] HRESULT Data([out, retval] IDataObject** value); - /// The position at which drag was detected. This position is given in - /// screen pixel coordinates as opposed to WebView2 relative coordinates. + /// The position at which drag was detected given in WebView2 relative + /// coordinates. [propget] HRESULT Position([out, retval] POINT* value); @@ -160,11 +140,21 @@ interface ICoreWebView2DragStartingEventHandler : IUnknown { [uuid(975d6824-6a02-5e98-ab7c-e4679d5357f4), object, pointer_default(unique)] interface ICoreWebView2CompositionController5 : IUnknown { /// Adds an event handler for the `DragStarting` event. `DragStarting` is - /// raised when the WebView2 detects a drag started within the WebView2. + /// a deferrable event that is raised when the WebView2 detects a drag started + /// within the WebView2. /// WebView2's default drag behavior is to synchronously call DoDragDrop when /// it detects drag. This event's args expose the data WebView2 uses to call /// DoDragDrop to allow users to implement their own drag logic and override /// WebView2's. + /// Handlers of this event must set the `Handled` event to true in order to + /// override WebView2's default logic. When invoking drag logic asynchronously + /// using a deferral, handlers must take care to follow these steps in order: + /// * Invoke asynchronous drag logic + /// * Set the event args `Handled` property true + /// * Complete the deferral + /// In the asynchronous case, WebView2 decides whether or not to invoke its + /// default drag logic when the deferral completes. So the event args' + /// `Handled` property must be true when the deferral is completed. HRESULT add_DragStarting( [in] ICoreWebView2DragStartingEventHandler* eventHandler, [out] EventRegistrationToken* token); @@ -181,13 +171,13 @@ interface ICoreWebView2CompositionController5 : IUnknown { /// This interface is implemented by the /// Microsoft.Web.WebView2.Core.CoreWebView2CompositionController runtime class. [uuid(7a4daef9-1701-463f-992d-2136460cf76e), object, pointer_default(unique)] -interface ICoreWebView2StagingCompositionControllerInterop : IUnknown { +interface ICoreWebView2CompositionControllerInterop3 : ICoreWebView2CompositionControllerInterop2 { /// Adds an event handler for the `DragStarting` event. `DragStarting` is /// raised when the WebView2 detects a drag started within the WebView2. /// This event can be used to override WebView2's default drag starting /// logic. HRESULT add_DragStarting( - [in] ICoreWebView2StagingDragStartingEventHandler* eventHandler, + [in] ICoreWebView2DragStartingEventHandler* eventHandler, [out] EventRegistrationToken* token); /// Removes an event handler previously added with `add_DragStarting`. From 8a4130ae472dbb49f1ccb19220a46cac436cca2e Mon Sep 17 00:00:00 2001 From: "John An (from Dev Box)" Date: Mon, 11 Nov 2024 21:57:54 -0800 Subject: [PATCH 8/8] Fixing up sample and removing DWORD const decls from API Details --- specs/DragStarting.md | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/specs/DragStarting.md b/specs/DragStarting.md index bed9ea23..997fa192 100644 --- a/specs/DragStarting.md +++ b/specs/DragStarting.md @@ -30,12 +30,10 @@ CHECK_FAILURE(m_compController5->add_DragStarting( [this](ICoreWebView2CompositionController5* sender, ICoreWebView2DragStartingEventArgs* args) { - DWORD allowedEffects = COREWEBVIEW2_DROP_EFFECTS_NONE; - POINT dragPosition = {0, 0}; + DWORD okEffects = COREWEBVIEW2_DROP_EFFECTS_NONE; wil::com_ptr dragData; - CHECK_FAILURE(args->get_AllowedDropEffects(&allowedEffects)); - CHECK_FAILURE(args->get_Position(&dragPosition)); + CHECK_FAILURE(args->get_AllowedDropEffects(&okEffects)); CHECK_FAILURE(args->get_Data(&dragData)); // This member refers to an implementation of IDropSource. It is an @@ -46,9 +44,9 @@ CHECK_FAILURE(m_compController5->add_DragStarting( m_dropSource = Make(); } + DWORD effect = DROPEFFECT_NONE; HRESULT hr = DoDragDrop( - dragData.get(), m_dropSource.get(), allowedEffects, &effect); - + dragData.get(), m_dropSource.get(), okEffects, &effect); args->put_Handled(SUCCEEDED(hr)); return hr; @@ -76,25 +74,16 @@ CHECK_FAILURE(m_compController5->add_DragStarting( # API Details ```C++ -/// DWORD constants that represent the effects that a given WebView2 drag drop -/// operation can have. The values of this enum align with the -/// [OLE DROPEFFECT constant](https://learn.microsoft.com/en-us/windows/win32/com/dropeffect-constants) -/// with the exception of DROPEFFECT_SCROLL which is unused in WebView2 drag -/// drop scenarios. -const DWORD COREWEBVIEW2_DROP_EFFECTS_NONE = 0; -const DWORD COREWEBVIEW2_DROP_EFFECTS_COPY = 1; -const DWORD COREWEBVIEW2_DROP_EFFECTS_MOVE = 2; -const DWORD COREWEBVIEW2_DROP_EFFECTS_LINK = 4; - /// Event args for the `DragStarting` event. [uuid(edb6b243-334f-59d0-b3b3-de87dd401adc), object, pointer_default(unique)] interface ICoreWebView2DragStartingEventArgs : IUnknown { - /// The operations this drag data supports. + /// The [OLE DROPEFFECT](https://learn.microsoft.com/en-us/windows/win32/com/dropeffect-constants) + /// values this drag data supports. [propget] HRESULT AllowedDropEffects( [out, retval] COREWEBVIEW2_DROP_EFFECTS* value); - /// The data being dragged. + /// The data to be dragged. [propget] HRESULT Data([out, retval] IDataObject** value); /// The position at which drag was detected given in WebView2 relative