无法挂钩Ole32.dll中定义的DoDragDrop方法

时间:2017-03-19 01:26:16

标签: c# hook outlook-addin unmanaged easyhook

我一直在开发一个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);
}

2 个答案:

答案 0 :(得分:1)

我已经成功地在VSTO Startup方法中使用SetInclusiveACL();代替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...
}

更新#1

如果您需要访问CF_FORMAT,我唯一的成功就是创建一个FORMATETC并将其传递给GetData方法。下面我将其设置为&#39; FileContents&#39;格式

 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);

有关参考,请参阅https://msdn.microsoft.com/en-us/library/windows/desktop/ms678431(v=vs.85).aspx

答案 1 :(得分:-1)

这正是您为当前进程启用挂钩所需要的:

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

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

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