我正在使用windowsformshost并尝试获取拖动和拖放事件。
我已经在WPF窗口,Windowsformshost和ChromiumWebBrowser上设置了allowdrop。我可以理解,WPF窗口将不会得到事件,因为窗口窗体的空域问题。但是我不明白为什么windowsformshost或者ChromiumWebBrowser没有得到任何事件。它们似乎被CEF/CefSharp吞噬了,并没有被传递出去。如何处理CEF/CefSharp中的事件和/或需要禁用的内容?
当我从纯WPF CefSharp迁移过来的时候,我已经用WPF ChromiumWebBrowser (不使用IDragHandler)实现了一个拖拽,拖移和拖放。
我想要实现的是显示一个不同的拖动效果基于鼠标拖动的地方,其次,我希望能够拦截拖放事件,首先检查文件类型,其中用户拖放在文件上传类型的元素。
从Cefsharp的角度来看,什么是effect of disabling或调用RevokeDragDrop,应该在哪个Hwnd (窗口)上调用?
发布于 2019-02-16 23:33:31
回答我自己的问题:可以恢复已被上游吞噬的拖放事件。
首先,我使用了IOleDropTarget接口,如下所示;
<ComImport, Guid("00000122-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Interface IOleDropTarget
<PreserveSig>
Function OleDragEnter(
<[In], MarshalAs(UnmanagedType.[Interface])> ByVal pDataObj As Object,
<[In], MarshalAs(UnmanagedType.U4)> ByVal grfKeyState As Integer,
<[In], MarshalAs(UnmanagedType.U8)> ByVal pt As Long,
<[In], Out> ByRef pdwEffect As Integer) As Integer
<PreserveSig>
Function OleDragOver(
<[In], MarshalAs(UnmanagedType.U4)> ByVal grfKeyState As Integer,
<[In], MarshalAs(UnmanagedType.U8)> ByVal pt As Long,
<[In], Out> ByRef pdwEffect As Integer) As Integer
<PreserveSig>
Function OleDragLeave() As Integer
<PreserveSig>
Function OleDrop(
<[In], MarshalAs(UnmanagedType.[Interface])> ByVal pDataObj As Object,
<[In], MarshalAs(UnmanagedType.U4)> ByVal grfKeyState As Integer,
<[In], MarshalAs(UnmanagedType.U8)> ByVal pt As Long,
<[In], Out> ByRef pdwEffect As Integer) As Integer
End Interface
接下来,当我们在界面上时,让我们创建当文件被拖动到这个界面时windows资源管理器所显示的漂亮图标。
Imports IDataObject_Com = System.Runtime.InteropServices.ComTypes.IDataObject
Imports System.Windows.Interop
Imports System.Runtime.InteropServices
Namespace Browser
<StructLayout(LayoutKind.Sequential)>
Public Structure Win32Point
Public x As Integer
Public y As Integer
End Structure
<ComImport>
<Guid("4657278A-411B-11d2-839A-00C04FD918D0")>
Public Class DragDropHelper
End Class
<ComVisible(True)>
<ComImport>
<Guid("4657278B-411B-11D2-839A-00C04FD918D0")>
<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Interface IDropTargetHelper
Sub DragEnter(
<[In]> ByVal hwndTarget As IntPtr,
<[In], MarshalAs(UnmanagedType.[Interface])> ByVal dataObject As IDataObject_Com,
<[In]> ByRef pt As Win32Point,
<[In]> ByVal effect As Integer)
Sub DragLeave()
Sub DragOver(
<[In]> ByRef pt As Win32Point,
<[In]> ByVal effect As Integer)
Sub Drop(
<[In], MarshalAs(UnmanagedType.[Interface])> ByVal dataObject As IDataObject_Com,
<[In]> ByRef pt As Win32Point,
<[In]> ByVal effect As Integer)
Sub Show(
<[In]> ByVal show As Boolean)
End Interface
您需要实现IOleDropTaget接口,然后该接口将提供DragEnter、Over、Leave和Drop事件。
要挂接这些事件,您不需要了解关于messageloop或wndproc消息的任何信息,如上所述。你需要知道的是,其中一个类名称为"Chrome_WidgetWin_0“的Chromium窗口是为拖放注册的,在获得事件之前,必须首先撤销这个窗口。
CefSharp示例展示了如何深入到Chromium窗口,但这通常是为了获得另一个窗口类。在本例中,我使用以下代码(注意,我撤销了在回调函数中找到的所有窗口,但似乎只注册了Chrome_WidgetWin_0。
Const Chrome_WidgetWin As String = "Chrome_WidgetWin_0"
Private Function TryFindHandl(ByVal browserHandle As IntPtr, <Out> ByRef chromeWidgetHostHandle As IntPtr) As Boolean
Dim cbXL As New NativeMethodsEx.EnumChildCallback(AddressOf EnumChildProc_Browser)
NativeMethodsEx.EnumChildWindows(browserHandle, cbXL, chromeWidgetHostHandle)
Return chromeWidgetHostHandle <> IntPtr.Zero
End Function
Private Shared Function EnumChildProc_Browser(ByVal hwndChild As Integer, ByRef lParam As Integer) As Boolean
Dim buf As New StringBuilder(128)
NativeMethodsEx.GetClassName(hwndChild, buf, 128)
Dim ret = NativeMethodsEx.RevokeDragDrop(hwndChild)
If ret = NativeMethodsEx.DRAGDROP_E_NOTREGISTERED Then
Debug.Print("")
End If
If buf.ToString = Chrome_WidgetWin Then
lParam = hwndChild
Return False
End If
Return True
End Function
一旦你有了这个句柄,并且你已经撤销了它作为拖放目标,那么你就可以调用RegisterDragDrop,传入句柄和你的IOleDropTarget类。
我的一些WinAPI签名如下所示
Friend Const DRAGDROP_E_NOTREGISTERED = &H80040100
Friend Const DRAGDROP_E_INVALIDHWND = &H80040102
Friend Const DRAGDROP_E_ALREADYREGISTERED = &H80040101
Friend Const E_OUTOFMEMORY = &H8007000E
Friend Const S_OK = 0
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Friend Shared Function GetClassName(ByVal hWnd As System.IntPtr, ByVal lpClassname As System.Text.StringBuilder, ByVal nMaxCount As Integer) As Integer
End Function
Friend Delegate Function EnumChildCallback(ByVal hwnd As Integer, ByRef lParam As Integer) As Boolean
<DllImport("User32.dll")>
Friend Shared Function EnumChildWindows(ByVal hWndParent As Integer, ByVal lpEnumFunc As EnumChildCallback, ByRef lParam As Integer) As Boolean
End Function
<DllImport("ole32.dll")>
Friend Shared Function RegisterDragDrop(ByVal hwnd As IntPtr, DropTarget As Browser.IOleDropTarget) As IntPtr
End Function
<DllImport("ole32.dll")>
Friend Shared Function RevokeDragDrop(ByVal hwnd As IntPtr) As IntPtr
End Function
该事件的示例以及如何使用IDropTargetHelper如下所示
Public Function OleDragEnter(<[In]> <MarshalAs(UnmanagedType.Interface)> pDataObj As Object, <[In]> <MarshalAs(UnmanagedType.U4)> grfKeyState As Integer, <[In]> <MarshalAs(UnmanagedType.U8)> pt As Long, <[In]> <Out> ByRef pdwEffect As Integer) As Integer Implements IOleDropTarget.OleDragEnter
Dim winPT As Win32Point
winPT.x = CInt(pt And &H7FFFFFFF)
winPT.y = CInt((pt >> 32) And &H7FFFFFFF)
Dim eff As DragDropEffects = DragDropEffects.None
'this is my event I am sending back to the browser class to deal with.
RaiseEvent DBDragEnter(eff, New Point(winPT.x, winPT.y))
'you need to pass in the effect
pdwEffect = CInt(eff)
'this is the helper which shows the nice icon you drag around.
ddHelper.DragEnter(targetHwnd, CType(pDataObj, IDataObject_Com), winPT, CInt(eff))
Return NativeMethodsEx.S_OK
End Function
当然,在WinForms的CefSharp中会看到一些很好的东西,特别是当控件目前有一大堆或无用的属性(AllowDrop)和事件(拖放)还没有实现的时候。
https://stackoverflow.com/questions/54711569
复制相似问题