使用Microsoft Word插件/ VSTO拦截拖放事件

时间:2015-10-30 19:18:30

标签: c# .net ms-word drag-and-drop vsto

问题:我正在编写Word 2013加载项/插件/ VSTO,需要拦截来自/到我的插件所在的Word实例的拖放事件运行。

解决方案:我正在尝试将RegisterDragDrop functionIDropTarget的实现一起用于传递到寄存器功能。不幸的是,我的IDropTarget实现中的所有事件都没有触发。我猜我错过了一些东西,或者甚至连插件都没有。

问题:

  1. 如果可以,我将传递给RegisterDragDrop方法的句柄是什么?它是插件的句柄吗? MS-Word实例本身的句柄?
  2. 如果无法做到这一点,那么使用Windows Procedures(挂钩Windows调用)是否是一个潜在的解决方案?
  3. 这是我的代码:

    NativeMethods.cs:

    // See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms678405(v=vs.85).aspx
    [DllImport("ole32.dll")]
    public static extern int RegisterDragDrop(IntPtr hwnd, IDropTarget pDropTarget);
    

    ThisAddIn.cs:

    private void ThisAddIn_Startup(object sender, EventArgs e)
    {
        int temp = 0;
        Process[] pWords = Process.GetProcessesByName("WINWORD");
        foreach (Process process in pWords)
        {
            temp = process.Id;
        }
    
        NativeMethods.RegisterDragDrop(Process.GetProcessById(temp).Handle, new MyDropTarget())
    }
    

    MyDropTarget.cs:

    public class MyDropTarget : IDropTarget
    {
        public void OnDragDrop(DragEventArgs e)
        {
            throw new NotImplementedException();
        }
    
        public void OnDragEnter(DragEventArgs e)
        {
            throw new NotImplementedException();
        }
    
        public void OnDragLeave(EventArgs e)
        {
            throw new NotImplementedException();
        }
    
        public void OnDragOver(DragEventArgs e)
        {
            throw new NotImplementedException();
        }
    }
    

2 个答案:

答案 0 :(得分:1)

可以使用RegisterDragDrop函数,但在此之前,你需要调用RevokeDragDrop,你可以得到这样的句柄:

  [DllImport("User32.dll", EntryPoint = "FindWindow")]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
 private  static IntPtr GetCurrentWindowHandle()
    {
        IntPtr windowHandle = IntPtr.Zero;

        windowHandle = FindWindow("OpusApp", null);

        windowHandle = FindWindowEx(windowHandle, IntPtr.Zero, "_WwF", null);
        windowHandle = FindWindowEx(windowHandle, IntPtr.Zero, "_WwB", null);
        windowHandle = FindWindowEx(windowHandle, IntPtr.Zero, "_WwG", null);

        return windowHandle;
    }

这是我的代码:

   [ComImport, Guid("00000122-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleDropTarget
{
    [PreserveSig]
    int OleDragEnter([In, MarshalAs(UnmanagedType.Interface)] object pDataObj, [In, MarshalAs(UnmanagedType.U4)] int grfKeyState, [In, MarshalAs(UnmanagedType.U8)] long pt, [In, Out] ref int pdwEffect);
    [PreserveSig]
    int OleDragOver([In, MarshalAs(UnmanagedType.U4)] int grfKeyState, [In, MarshalAs(UnmanagedType.U8)] long pt, [In, Out] ref int pdwEffect);
    [PreserveSig]
    int OleDragLeave();
    [PreserveSig]
    int OleDrop([In, MarshalAs(UnmanagedType.Interface)] object pDataObj, [In, MarshalAs(UnmanagedType.U4)] int grfKeyState, [In, MarshalAs(UnmanagedType.U8)] long pt, [In, Out] ref int pdwEffect);
}

internal class MyDropTarget : IOleDropTarget
{
    [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    public static extern int RegisterDragDrop(IntPtr hwnd, IOleDropTarget target);

    [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    public static extern int RevokeDragDrop(IntPtr hwnd);
    public int OleDragEnter(object pDataObj, int grfKeyState, long pt, ref int pdwEffect)
    {
        throw new NotImplementedException();
    }

    public int OleDragOver(int grfKeyState, long pt, ref int pdwEffect)
    {
        throw new NotImplementedException();
    }

    public int OleDragLeave()
    {
        throw new NotImplementedException();
    }

    public int OleDrop(object pDataObj, int grfKeyState, long pt, ref int pdwEffect)
    {
        throw new NotImplementedException();
    }
}

像这样使用它:

  var hwnd = GetCurrentWindowHandle();
            MyDropTarget.RevokeDragDrop(hwnd);
            var rtn = MyDropTarget.RegisterDragDrop(hwnd, new MyDropTarget());

答案 1 :(得分:0)

您是否检查了RegisterDragDrop调用的返回值?您可能会重新获得DRAGDROP_E_ALREADYREGISTERED,除非您传入的窗口句柄无效,在这种情况下您将获得DRAGDROP_E_INVALIDHWND。不确定你获取窗户的方式是正确的。

Word应该已经将其窗口注册为放置目标,因此您可能需要在注册自己的窗口句柄之前调用RevokeDragDrop。但是,如果您想检查drop上的IDataObject并且只处理某些事情并让Word处理其他内容,这会让您遇到麻烦。 (在这种情况下,你需要做更多的工作)