C# 在C中实现IDocHostUIHandler.FilterDataObject#

C# 在C中实现IDocHostUIHandler.FilterDataObject#,c#,.net,webbrowser-control,com-interop,C#,.net,Webbrowser Control,Com Interop,我正在尝试向WPF应用程序添加一个支持HTML的编辑器。显而易见的选择是使用默认的WebBrowser控件,并将其文档置于“设计模式”。到目前为止,一切顺利 现在,这变得很棘手,因为我需要能够截取从剪贴板粘贴到编辑器中的内容,以确保其格式可用。例如,当粘贴包含图像的Word文档的片段时,图像由浏览器控件不理解的一段Office XML表示,因此在将其插入文档之前,我需要将其替换为一个简单的标记 在意识到在纯WPF级别上无法实现这一点后,我不得不深入到ActiveX组件,WebBrowser控件只

我正在尝试向WPF应用程序添加一个支持HTML的编辑器。显而易见的选择是使用默认的WebBrowser控件,并将其文档置于“设计模式”。到目前为止,一切顺利

现在,这变得很棘手,因为我需要能够截取从剪贴板粘贴到编辑器中的内容,以确保其格式可用。例如,当粘贴包含图像的Word文档的片段时,图像由浏览器控件不理解的一段Office XML表示,因此在将其插入文档之前,我需要将其替换为一个简单的标记

在意识到在纯WPF级别上无法实现这一点后,我不得不深入到ActiveX组件,WebBrowser控件只是它的包装器。似乎我的问题(以及我也面临的一些其他问题,但与此问题无关)可以通过提供
IDocHostUIHandler
接口的自定义实现来解决

此接口包含一个名为
FilterDataObject
的方法,该方法显然会在粘贴操作发生时调用,从而使实现有机会检查并在必要时更改浏览器从剪贴板接收的数据

以下是我对IDocHostUIHandler接口中方法的定义的参考:

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("bd3f23c0-d43e-11cf-893b-00aa00bdce1a")]
public interface IDocHostUIHandler {
    // ...
    [PreserveSig]
    int FilterDataObject(
        [In, MarshalAs(UnmanagedType.Interface)] object pDO,
        [Out, MarshalAs(UnmanagedType.Interface)] out object ppDORet
    );
}
传入的COM对象可以强制转换为
System.Runtime.InteropServices.ComTypes.IDataObject
,并且可以很好地访问剪贴板内容。但是当我实际尝试通过out参数返回替换IDataObject时,我得到了一个访问冲突异常

例如,简单地返回现有类
System.Windows.DataObject
(它还实现了
…ComTypes.IDataObject
,因此我希望CLR能够正确地将其打包)的新实例的天真尝试如下

public class MyDocHostUIHandler : IDocHostUIHandler {
    // ...
    public int FilterDataObject(object pDO, out object ppDORet) {
        ppDORet = new System.Windows.DataObject("Text", "New Clipboard Content!");
        return S_OK; // S_OK means that the data object has been replaced
    }
}
。。。不起作用(只要我尝试将任何内容粘贴到编辑器中,AccessViolationException就会出现)

有人做过这样的事吗?我可能做错了什么?我的ComImport ed界面的定义是否被破坏了(在网络上找到一个真正有效的版本是相当困难的,至少在某些时候是如此)?我试图从托管代码中执行的操作可能吗?

尝试[return:MarshalAs(UnmanagedType.I4)]int-FilterDataObject(System.Runtime.InteropServices.ComTypes.IDataObject pDO,out-System.Runtime.InteropServices.ComTypes.IDataObject-ppDORet);]


如果您在为COM接口生成签名时遇到问题,通常可以

不知道默认封送拆收器在做什么,但您是否尝试通过Marshal.getIUnknownProbject分离COM接口?我怀疑问题在于原始COM接口的方法声明中为out参数定义的双指针:
HRESULT FilterDataObject(IDataObject*pDO,IDataObject**ppDORet);
我不知道如何正确封送。我甚至尝试将
ppDORet
转换为
IntPtr
,然后使用
marshal.WriteIntPtr
marshal.getiunknownobject
的结果写入它,但我仍然得到相同的访问冲突异常。尝试[return:MarshalAs(UnmanagedType.I4)]int FilterDataObject(System.Runtime.InteropServices.ComTypes.IDataObject pDO,out System.Runtime.InteropServices.ComTypes.IDataObject ppDORet);}奇怪的我确信这是我第一次尝试的事情之一(因为这似乎是最明显的),但当时它不起作用。但我刚刚试过,它毕竟是有效的。COM互操作有时真的像黑魔法。。。不管怎样,谢谢你。附言:你可能想把你的评论改写成一个答案,这样我就可以接受并投票,就像它应得的那样:)