0

I have been developing a Outlook plugin where I want to intercept the drag drop of attachments so that I can change the property of IDataObject but somehow my callback function is never executed.I have been using EasyHook open library to achieve the same,I have successfully hooked few other common APIs like CreateFile etc though.

Below is code snapshot.

public partial class 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);
}
abhinov
  • 125
  • 1
  • 3
  • 12

2 Answers2

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

MikeS
  • 647
  • 5
  • 18
-1

This is exactcly what do you need to enable the hook for current process:

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

To disable the hook for current process, call:

DragDropHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
uoxon
  • 1
  • 1
  • @Michael, I've hooked DoDragDrop for Outlook. It works great for email/contact/task items. But when dragging calendar item, it crashed, saying the input COMObject doesn't implement IDropSource. Does it work for you? – uoxon Feb 19 '18 at 06:43