如何将COM返回的对象的接口“替换”为托管代码?

问题描述

我面对some weird performance issues,我怀疑它们可能是由于将dynamic指定为COM接口方法的返回类型而引起的。具体来说,这是IHTMLDOMChildrenCollection接口最终在互操作中的方式:

[DefaultMember("item")]
[Guid("3050F5AB-98B5-11CF-BB82-00AA00BDCE0B")]
[TypeLibType(4160)]
public interface IHTMLDOMChildrenCollection : IEnumerable
{
    [DispId(-4)]
    [TypeLibFunc(65)]
    IEnumerator GetEnumerator();
    [DispId(0)]
    dynamic item(int index); // HERE is the dynamic

    [DispId(1500)]
    int length { get; }
}

我怀疑代码一旦调用item()方法,就会创建一些额外的连线,从而降低其他代码的性能。

代码的组织方式如下:

var document = (IHTMLDocument)documentBrowser.Document;
var selector = (IDocumentSelector)document;
IHTMLDOMChildrenCollection allElements = selector.querySelectorAll("*");
int length = allElements.length;
for (int index = 0; index < length; index++)
{
    var item = allElements.item(index);
}

This answer指出,如果声明了IHTMLDOMChildrenCollection接口,使得item()返回object而不是dynamic,则性能可能会提高。

是否可以声明一个新接口并以某种方式说服CLR给我一个实现该接口的RCW?

我尝试了以下操作:

[DefaultMember("item")]
[Guid("3050F5AB-98B5-11CF-BB82-00AA00BDCE0B")]
[TypeLibType(4160)]
public interface IHTMLDOMChildrenCollectionCopy : IEnumerable
{
    [DispId(-4)]
    [TypeLibFunc(65)]
    IEnumerator GetEnumerator();
    [DispId(0)]
    [return: MarshalAs(UnmanagedType.IDispatch)]
    object item(int index); // HERE it's object,not dynamic

    [DispId(1500)]
    int length { get; }
}

和代码中的

IHTMLDOMChildrenCollection allElementsOriginal = selector.querySelectorAll("*");
var unknown = Marshal.GetIUnknownForObject(allElements);
var newElements = (IHTMLDOMChildrenCollectionCopy)Marshal.GetTypedObjectForIUnknown(
   unknown,typeof(IHTMLDOMChildrenCollectionCopy));
int length = newElements.length; // this fails

,直到执行读.length的行为止。后者失败并

System.AccessViolationException:'试图读取或写入受保护的内存。这通常表明其他内存已损坏。'

这行得通吗?我在做什么错了?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)