.net文件用mshtml写

时间:2011-03-02 16:00:13

标签: c# .net document mshtml

我使用mshtml进行html解析。 (版本7.0.3300.0,C:\ Program Files \ Microsoft.NET \ Primary Interop Assemblies \ Microsoft.mshtml.dll)。

HTMLDocumentClass有一个write方法,所以我使用它,但它引发了ComException ErrorCode:-2147352571和消息:类型不匹配。它是什么原因?如果不使用HTMLDocumentClass的write方法,为什么要定义?

    HTMLDocumentClass getHTMLDocument(string html)
    {
        HTMLDocumentClass doc = new HTMLDocumentClass();

        doc.write(new object[] { html }); // raises exception
        doc.close();

        return doc;
    }

    HTMLDocumentClass getHTMLDocument2(string html)
    {
        HTMLDocumentClass doc = new HTMLDocumentClass();
        IHTMLDocument2 doc2 = (IHTMLDocument2)doc;
        doc2.write(new object[] { html });
        doc2.close();

        return doc;
    }

1 个答案:

答案 0 :(得分:11)

好的,我找到了。这是一种有趣的失败模式。我在机器上安装的所有Microsoft.mshtml PIA都已过时。其中不少于4个,所有版本为7.0.3300.0,运行时目标为1.0.3705(相当陈旧)。

由类型库导入器生成的fooClass互操作类是原因。它是一个合成类,它存在使事件更容易处理,它们在COM中完成得非常不同。该类是所有接口的所有组合方法的扁平化版本。 HTMLDocument coclass的当前SDK版本声明如下(来自mshmtl.idl):

[
    uuid(25336920-03F9-11cf-8FD0-00AA00686F13)
]
coclass HTMLDocument
{
    [default]           dispinterface DispHTMLDocument;
    [source, default]   dispinterface HTMLDocumentEvents;
    [source]            dispinterface HTMLDocumentEvents2;
    [source]            dispinterface HTMLDocumentEvents3;
                        interface IHTMLDocument2;
                        interface IHTMLDocument3;
                        interface IHTMLDocument4;
                        interface IHTMLDocument5;
                        interface IHTMLDocument6;
                        interface IHTMLDOMNode;
                        interface IHTMLDOMNode2;
                        interface IDocumentSelector;
                        interface IHTMLDOMConstructor;
};

如果在互操作库上使用对象浏览器,您将看到HTMLDocumentClass 缺少 IHTMLDocument6,IDocumentSelector和IHTMLDOMConstructor的接口方法。您正在使用的write()方法是通过这些接口。

这意味着如果您使用HTMLDocumentClass.write(),则会调用错误的方法。引发异常是因为调用的方法对参数不满意。当然不是。

这当然是一种令人讨厌的失败模式。这是因为微软打破了一个非常困难的COM要求,更改COM接口或coclass需要一个不同的 guid。上述声明中的[uuid]属性。然而,这也使得新版本的Internet Explorer与使用它的旧代码完全不兼容。摇滚和一个艰难的地方,向后兼容性在微软是非常神圣的。在常规COM客户端中,coclass中的接口实现顺序通常不是问题。除了在.NET中,它打破了tlbimp生成的合成XxxClass类型的布局。

我从未见过实际需要合成类的情况,也从未使用过它。您始终可以通过在C#中转换来获取正确的接口指针,该C#调用QueryInterface()并始终返回正确的指针,而不管版本如何。您的替代方案是正确的解决方法。