Как получать события перетаскивания и перетаскивания, используя Winf формы CefSharp - PullRequest
0 голосов
/ 15 февраля 2019

Я использую windowsformshost и пытаюсь получить события перетаскивания и удаления.

Я установил allowdrop в окне WPF, Windowsformshost и ChromiumWebBrowser.Я могу понять, что окно WPF не получит событие из-за проблем воздушного пространства windowsformshost.Но я не понимаю, почему windowsformshost или ChromiumWebBrowser не получают никаких событий.Похоже, что они проглочены и не переданы CEF / CefSharp.Как я могу обработать события и / или что мне нужно отключить в CEF / CefSharp?

Поскольку я перехожу из чистого WPF CefSharp, я реализовал dragenter, dragmove и dragdrop с WPF ChromiumWebBrowser (не используяthe IDragHandler).

Чего я хотел бы добиться, так это показать другой эффект перетаскивания в зависимости от того, куда перетаскивается мышь, и, во-вторых, я хотел бы иметь возможность перехватить событие перетаскивания, чтобы сначала проверить тип файла, гдепользователь перетаскивает элемент типа загрузки файла.

Каков эффект отключения или вызова RevokeDragDrop и какой Hwnd (окно) должен вызываться с точки зрения Cefsharp?

1 Ответ

0 голосов
/ 16 февраля 2019

Отвечая на мой собственный вопрос: можно восстановить события перетаскивания, которые были проглочены вверх по течению.

Сначала я использовал интерфейс 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 Explorer отображает при перетаскивании файла с этим интерфейсом.

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, как было указано выше.Что вам нужно знать, так это то, что одно из окон Chromium с именем класса "Chrome_WidgetWin_0" зарегистрировано для перетаскивания, и его необходимо сначала отозвать, прежде чем вы сможете получить события.

Примеры 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

Конечно, что-то, что было бы неплохо увидеть в CefSharp для WinForms, особенно потому, что элемент управления имеет целую кучу или бесполезные свойства (AllowDrop) и события (Drag and Drop) намомент, который не реализован.

...