c# - 处理困惑的界面层次结构 (MSHTML) 的最佳方法是什么?

标签 c# oop com c#-4.0 mshtml

我正在使用 MSHTML API来自 C# 4.0 和运行代码的逻辑不是问题。然而,由于 MSHTML 和/或 COM 接口(interface)的设计方式,编写代码是一件很痛苦的事情。具体来说,应该有接口(interface)层次结构的时候却没有接口(interface)层次结构。例如,IHTMLDocument7不扩展 IHTMLDocument6 ,不扩展 IHTMLDocument5 ,依此类推(尽管 IHTMLDocument2 确实扩展了 IHTMLDocument)。

为了进一步混淆问题,有一个 HTMLDocument扩展接口(interface) DispHTMLDocument (它具有 IHTMLDocument* 接口(interface)的所有方法)和 HTMLDocumentEvents_Event (它提供了一些但不是全部事件)。雪上加霜的是,HTMLDocumentClass是一个实现所有上述接口(interface)的 coclass,然后是一些,例如 IDocumentSelectorHTMLDocumentEvents4_Event .

我真的很想能够使用 HTMLDocumentClass 的 API ,但尝试转换为它给了我:

System.InvalidCastException: Unable to cast COM object of type 'mshtml.HTMLDocumentClass' to class type 'mshtml.HTMLDocumentClass'. Instances of types that represent COM components cannot be cast to different types that represent COM components; however they can be cast to interfaces as long as the underlying COM component supports QueryInterface calls for the IID of the interface.

此外,一些接口(interface)没有关联的组件类;例如,有 IHTMLElement*接口(interface)但没有 HTMLElement接口(interface)也不是 HTMLElementClass类(class)。总的来说,我发现很难针对接口(interface)进行编程。

是否有解决此接口(interface)故障的好方法,或者我应该放弃 IntelliSense 并使用 dynamic到处?我考虑过编写实现所有接口(interface)的包装类,但 MSHTML 接口(interface)太多,每个接口(interface)都有大量成员,因此必须自动化一个实用的解决方案。

最佳答案

IHTMLDocument6 doesn't extend IHTMLDocument5

即使它扩展了 IHTMLDocument5,根据 COM 规则,您仍然应该通过 QueryInterface 获取 IHTMLDocument5,而不是使用继承。我很高兴他们没有让你想知道如何对包装类已经实现的接口(interface)进行 QI 作为继承的副作用。

我建议您在控制对象时不要使用任何包装类并切换到向后兼容的接口(interface)。根据错误消息,为 IE 生成的 COM 包装器 CLR 看起来像是来自不同程序集的 mshtml.HTMLDocumentClass 类。

在 COM 编程中,您会经常看到工厂模式。对于 html 元素对象,工厂方法是 IHTMLDocument2.createElement。如果作者选择使用此模式,通常您无法自行创建对象。

Visual Studio 会自动引用 PIA(如果存在),否则它会使用 tlbexp.exe 生成以“Interop”为前缀的互操作程序集。然而,大多数时候您会在 PIA 中使用少数几个接口(interface),因此您可以编写自己的互操作类型(或从 Google 代码搜索中复制)并使用这个大型程序集。

关于c# - 处理困惑的界面层次结构 (MSHTML) 的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4952154/

相关文章:

c# - 校正扫描图像

c# - 在这种特定情况下,我应该如何建模我的代码以最大限度地重用代码?

c++ - 来自 ExecMethod 的错误 WBEM_E_INVALID_METHOD_PARAMETERS

.net - 用作事件接收器的 CCmdTarget 的正确生命周期管理是什么?

wcf - 在 IIS (7+) 托管的 WCF 服务中使用 STA COM 组件时,如何处理?

c# - 如何检测 .Net 中(路由器/网关的)公共(public) IP 地址的变化?

c# - 为什么有些异步方法需要返回类型为 Task,而有些则不需要

c# - Windows Phone 8.1 MVVM设置 View 的 View 模型

Python:如何使用类来绘制不同的线?

python - 括号对方法和 'Self' 变量的影响