0

我一直在开发一个 Outlook 插件,我想在其中拦截附件的拖放,以便我可以更改 IDataObject 的属性,但不知何故我的回调函数从未执行过。我一直在使用 EasyHook 开放库来实现相同的目标,我已经成功不过,它还连接了一些其他常见的 API,例如 CreateFile 等。

下面是代码快照。

公共部分类 DragDrop {

    private LocalHook DragDropHook;
    Stack<String> Queue = new Stack<string>();

    internal class HookCallbackHelper
    {
        public HookCallbackHelper(bool isUnicode) { IsUnicode = isUnicode; }
        public bool IsUnicode;
    }
    private void DragDrop_Load(object sender, RibbonUIEventArgs e)
    {

    }

    private void btnHook_Click(object sender, RibbonControlEventArgs e)
    {
        try
        {

            DragDropHook = LocalHook.Create(LocalHook.GetProcAddress("Ole32.dll", "DoDragDrop"),
                new DDoDragDrop(DoDragDrop_Hooked),new HookCallbackHelper(true));

            DragDropHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });


        }
        catch (Exception ExtInfo)
        {
            System.Windows.Forms.MessageBox.Show(ExtInfo.Message);
            //Interface.ReportException(ExtInfo);

            return;
        }
    }

    private int DoDragDrop_Hooked(IDataObject pDataObj, IDropSource pDropSource, uint dwOKEffects, uint[] pdwEffect)
    {


        System.Windows.Forms.MessageBox.Show("Hooked");

        try
        {

            HookCallbackHelper hch = HookRuntimeInfo.Callback as HookCallbackHelper;
            lock (Queue)
            {
                Queue.Push("[" + RemoteHooking.GetCurrentProcessId() + ":" +
                    RemoteHooking.GetCurrentThreadId() + "]");
            }
        }
        catch
        {
        }

        // call original API...
        return DoDragDrop(pDataObj, pDropSource, dwOKEffects, pdwEffect);
    }

    [UnmanagedFunctionPointer(CallingConvention.StdCall,
        CharSet = CharSet.Ansi,
        SetLastError = true)]
    public delegate int DDoDragDrop(
        IDataObject pDataObj,
        IDropSource pDropSource,
        UInt32 dwOKEffects,
        UInt32[] pdwEffect
    );

    [DllImport("Ole32.dll",
        CharSet = CharSet.Unicode,
        SetLastError = true,
        CallingConvention = CallingConvention.StdCall)]
    public static extern int DoDragDrop(IDataObject pDataObj, IDropSource pDropSource,
       UInt32 dwOKEffects, UInt32[] pdwEffect);
}

[ComImport, Guid("00000121-0000-0000-C000-000000000046"),
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDropSource
{
    [PreserveSig]
    UInt32 QueryContinueDrag(
    [MarshalAs(UnmanagedType.Bool)] bool fEscapePressed,
    UInt32 grfKeyState);

    [PreserveSig]
    UInt32 GiveFeedback(
    UInt32 dwEffect);
}
4

2 回答 2

1

I've had success hooking the process in the VSTO Startup method and using SetInclusiveACL(); instead of SetExclusiveACL()

[DllImport("Ole32.dll")]
static extern int DoDragDrop(IDataObject pDataObj, IDropSource pDropSource, uint dwOKEffects, uint[] pdwEffect);

[UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)]
[return: MarshalAs(UnmanagedType.I4)]
delegate int DragDropDelegate(IDataObject pDataObj, IDropSource pDropSource, uint dwOKEffects, uint[] pdwEffect);

private LocalHook dragDropHook;

private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
        try
        {

            dragDropHook = EasyHook.LocalHook.Create(EasyHook.LocalHook.GetProcAddress("Ole32.dll", "DoDragDrop"),
                new DragDropDelegate(DoDragDropHook), this);

            // Only hook this thread (threadId == 0 == GetCurrentThreadId)
            dragDropHook.ThreadACL.SetInclusiveACL(new Int32[] {0});
        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show(ex.Message);
        }
}

static int DoDragDropHook(IDataObject pDataObj, IDropSource pDropSource, uint dwOKEffects, uint[] pdwEffect)
{
  //Do something...
}

Update #1

If you need access to the CF_FORMAT the only success I've had is creating a FORMATETC and passing that into the GetData method. Below I'm setting it to the 'FileContents' format

 FORMATETC format = new FORMATETC();
 format.cfFormat = (short)DataFormats.GetFormat("FileContents").Id;
 format.dwAspect = DVASPECT.DVASPECT_CONTENT;
 format.lindex = 0;
 format.ptd = new IntPtr(0);
 format.tymed = TYMED.TYMED_HGLOBAL | TYMED.TYMED_ISTREAM | TYMED.TYMED_ISTORAGE;
 STGMEDIUM medium = new STGMEDIUM();
 pDataObj.GetData(ref format, out medium);

For reference see https://msdn.microsoft.com/en-us/library/windows/desktop/ms678431(v=vs.85).aspx

于 2017-04-12T10:42:49.337 回答
-1

这正是为当前进程启用钩子所需的:

DragDropHook.ThreadACL.SetInclusiveACL(new Int32[] { 0 });

要禁用当前进程的钩子,请调用:

DragDropHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
于 2018-02-19T06:33:44.547 回答