C# “我怎么能?”;替换“;从COM返回到托管代码的对象的接口?

C# “我怎么能?”;替换“;从COM返回到托管代码的对象的接口?,c#,.net,com,rcw,C#,.net,Com,Rcw,我面临并怀疑它们可能是由于将dynamic指定为COM接口方法的返回类型而产生的。具体来说,这就是IHTMLDOMChildrenCollection接口在互操作中的结束方式: [DefaultMember("item")] [Guid("3050F5AB-98B5-11CF-BB82-00AA00BDCE0B")] [TypeLibType(4160)] public interface IHTMLDOMChildrenCollection : IEnu

我面临并怀疑它们可能是由于将
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);
}
在守则中:

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:'尝试读取或写入受保护的内存。这通常表示其他内存已损坏。”


这样行吗?我做错了什么?

是的,这应该行得通。缺少的部分是界面没有用
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]

这是完整的声明:

[DefaultMember("item")]
[Guid("3050F5AB-98B5-11CF-BB82-00AA00BDCE0B")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[TypeLibType(4160)]
public interface IHTMLDOMChildrenCollectionCopy : IEnumerable
{
   // same members as in the question
}

dynamic
肯定会影响性能,因为它会在C#端创建大量包装。请尝试以下操作:
[PreserveSig]int-Item(int-index[marshallas(UnmanagedType.IDispatch)]out-object-ppItem
[PreserveSig]
由于某些原因不起作用。然而,我确实“替换”了接口——它必须用
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
声明。我认为接口已经完全生成(TypeLibType、TypeLibFunc、DefautlMember很少使用),所以我没有仔细查看它的定义。它应该是InterfaceIsividual,而不是纯分派,否则您将再次遇到性能问题(.NET将始终使用Invoke,而不是直接调用方法)。[PreserveSig]应该可以工作。使用InterfaceSidual会导致AccessViolationException,因为它没有属性。在这种情况下,.NET会直接调用这些方法(这是perf所需的),因此这意味着定义不正确。实际上,接口二进制布局是先
get_length
,然后
get_newEnum
item
,如下所示:
[DefaultMember("item")]
[Guid("3050F5AB-98B5-11CF-BB82-00AA00BDCE0B")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[TypeLibType(4160)]
public interface IHTMLDOMChildrenCollectionCopy : IEnumerable
{
   // same members as in the question
}