.net文件用mshtml写

loc*_*ope 4 .net c# document mshtml

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

HTMLDocumentClass有一个write方法,所以我使用它,但它引发了与ErrorCode的ComException:-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;
    }
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 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;
};
Run Code Online (Sandbox Code Playgroud)

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

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

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

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