钩住olesetclipboard的问题

时间:2016-02-29 16:25:43

标签: winapi visual-c++ vsto hook office-interop

目标:

在另一个进程内运行时(...在Office应用程序中说一个插件,如Word),拦截对OleSetClipboard/OleGetClipboard的调用并代理iDataObject接口用我们控制的应用程序替换应用程序最初设置/获取的对象,根据需要将调用传递给原始对象。

基本上,我想控制对给定应用程序的剪贴板的访问。

进度:

我已成功连接OleSet/GetClipboard函数(以及其他函数)并可以用我的"代理"替换对象。对象。我的代理对象使用IDataObjectSystem.Runtime.InteropServices.ComTypes.IDataObject)的.Net定义。

请注意,在这种情况下,我使用C#,但在c++重新实现时发生了类似的细分。

问题:

惊喜......很惊讶,当我代理OleSetClipboard函数时,应用程序并不能完全正常运行。当我只挂钩OleGetClipboard函数端时,它就可以了。

我可以看到我的代理对象在getter和setter方面相互调用。细分似乎是当olegetclipboard端的代理对象需要通过getdata调用时,olesetclipboard side代理将在尝试在setter端代理的原始对象上执行getdata时抛出异常。

Sudo示例:

请注意,此示例并非特定于此格式。大多数/所有非文本格式都以这种方式失败。

我看到set side从它从Word原始OleSetClipboard调用代理的对象上调用GetData:

  

代理对象(OLESETCLIPBOARD):GetData调用15

结构似乎是正确的:

FORMATETC Structure Info: cfFormat (15) dwAspect (DVASPECT_CONTENT) lindex (-1) ptd (0) tymed (TYMED_HGLOBAL)

但我得到一个例外:

  

System.Runtime.InteropServices.COMException:GetData:消息:无效   FORMATETC结构(HRESULT的异常:0x80040064   (DV_E_FORMATETC))

可能有什么问题?我没考虑过什么?其他想法?

谢谢!

更新

用于代理的示例类...

 public enum DataObjectSource { OLESETCLIPBOARD = 0, OLEGETCLIPBOARD = 1};  

 public class DataObjectProxy System.Runtime.InteropServices.ComTypes.IDataObject
 {
    private System.Runtime.InteropServices.ComTypes.IDataObject OriginalClipboardObject;
    private DataObjectSource eSource;

    public DataObjectProxy(object OriginalObjectToWrap, DataObjectSource eType)
    {
        this.OriginalClipboardObject = (System.Runtime.InteropServices.ComTypes.IDataObject)OriginalObjectToWrap;
        this.eSource = eType;
    }

    #region Utility Methods

    public string GetSingleLineLoggableOutput(FORMATETC FormatToPrint)
    {
        return $"FORMATETC Structure Info: cfFormat ({(ushort)FormatToPrint.cfFormat} - {GetClipboardFormatName((uint)FormatToPrint.cfFormat)}) dwAspect ({FormatToPrint.dwAspect}) lindex ({FormatToPrint.lindex}) ptd ({FormatToPrint.ptd}) tymed ({FormatToPrint.tymed})";
    }

    private String GetClipboardFormatName(uint ClipboardFormat)
    {
        StringBuilder sb = new StringBuilder(1000);
        GetClipboardFormatName(ClipboardFormat, sb, sb.Capacity);
        return sb.ToString();
    }


    #endregion Utility Methods

    #region pInvokes

    [DllImport("user32.dll")]
    static extern int GetClipboardFormatName(uint format, [Out] StringBuilder lpszFormatName, int cchMaxCount);

    #endregion pInvokes


    #region System.Runtime.InteropServices.ComTypes.IDataObject Interface Implemenation

    public int DAdvise(ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection)
    {
        HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): DAdvise Called");
        return OriginalClipboardObject.DAdvise(ref pFormatetc, advf, adviseSink, out connection);
    }

    public void DUnadvise(int connection)
    {
        HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): DUnadvise Called");
        OriginalClipboardObject.DUnadvise(connection);
    }

    public int EnumDAdvise(out IEnumSTATDATA enumAdvise)
    {
        HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): EnumDAdvise Called");
        return OriginalClipboardObject.EnumDAdvise(out enumAdvise);
    }

    public IEnumFORMATETC EnumFormatEtc(DATADIR direction)
    {
        HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): EnumFormatEtc Called");
        return OriginalClipboardObject.EnumFormatEtc(direction);
    }

    public int GetCanonicalFormatEtc(ref FORMATETC formatIn, out FORMATETC formatOut)
    {
        HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): GetCanonicalFormatEtc Called");
        return OriginalClipboardObject.GetCanonicalFormatEtc(ref formatIn, out formatOut);
    }

    public void GetData(ref FORMATETC format, out STGMEDIUM medium)
    {
        try
        {
            HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): GetData Called for {(ushort)format.cfFormat}");
            HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, GetSingleLineLoggableOutput(format));
            STGMEDIUM medTemp;
            FORMATETC formatTemp = format;
            OriginalClipboardObject.GetData(ref formatTemp, out medTemp);
            medium = medTemp;
        }
        catch(Exception getException)
        {
            HookLogger.LogException(HookLogger.HOOK_CHANNEL, "GetData", getException);
            throw;
        }
    }


    public void GetDataHere(ref FORMATETC format, ref STGMEDIUM medium)
    {
        HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): GetDataHere Called");
        OriginalClipboardObject.GetDataHere(ref format, ref medium);
    }

    public int QueryGetData(ref FORMATETC format)
    {
        HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): QueryGetData Called");
        return OriginalClipboardObject.QueryGetData(ref format);
    }

    public void SetData(ref FORMATETC formatIn, ref STGMEDIUM medium, bool release)
    {
        HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): SetData Called");
        OriginalClipboardObject.SetData(ref formatIn, ref medium, release);
    }

    #endregion System.Runtime.InteropServices.ComTypes.IDataObject Interface Implemenation

}

0 个答案:

没有答案