c# - 如何将 COM 返回的对象的接口“替换”为托管代码?
问题描述
我遇到了一些奇怪的性能问题,我怀疑它们可能是由于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 接口被声明为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: '试图读取或写入受保护的内存。这通常表明其他内存已损坏。
这应该工作吗?我究竟做错了什么?
解决方案
是的,这应该有效。缺少的部分是界面没有装饰[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
}
推荐阅读
- c# - 在两个 C# 进程之间交换消息
- javascript - 更正 javascript 以与 html a href 对齐
- c - 将符号名称输入 C
- java - Java - 计数指定对象的计数器数组
- python - 无法在 virtualenv 中运行特定的 django 项目
- python - Flask 应用程序在 docker 上运行,但不在主机上运行
- html - REACT spa 应用程序 - 为 SEO 提供单独和不同的预渲染静态 html,优点和缺点
- java - 使用java流将标题和行的csv文件转换为hashmap数组
- bash - 如何在 unix 中为给定的字符串创建 kmer 模式?
- c# - 应用程序挂起:解释 WinDbg 命令的输出