首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MSHTML HTMLHeadElementClass COM错误

MSHTML HTMLHeadElementClass COM错误
EN

Stack Overflow用户
提问于 2012-04-17 22:32:02
回答 1查看 4.9K关注 0票数 1

我目前正在使用MS将JavaScript代码插入到网站中。

我引用了Microsoft HTML对象库并键入了这段代码。

代码语言:javascript
复制
IHTMLDocument2 doc = BrowserHost.Document as HTMLDocumentClass;
IHTMLElement head = (IHTMLElement)
      ((IHTMLElementCollection)doc.all.tags("head")).item(null, 0);
IHTMLScriptElement scriptObject = 
      (IHTMLScriptElement)doc.createElement("script");
scriptObject.type = @"text/javascript";
scriptObject.text = TTS.TTSWebFactory.GetJavascript();
((HTMLHeadElementClass)head).appendChild((IHTMLDOMNode)scriptObject);

我在脚本的最后一行得到一个错误,这是消息。

代码语言:javascript
复制
Unable to cast COM object of type 'System._ComObject' to class type 
'mshtml.HTMLHeadElementClass'. COM components that enter the CLR and do not 
support IProvideClassInfo or that do not havae any iterop assembly registered 
will be wrapped in the _ComObject type. Instances of this type cannot be cast 
to any other class; however they can be cast to interfaces as long as the 
underlying COM component supports QueryInterface calls for the IID of the 
interface

我对COM没有太多的经验,把最后一行保留在代码中是很重要的,有人能帮我理解这意味着什么以及我是如何解决它的吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-04-18 01:26:38

从像mshtml.tlb这样的类型库中得到的互操作类有一个非常严重的问题。类型库导入程序从类型库中的coclass定义生成合成.NET类。您可以从它们的类型名称中识别它们,它们以"Class“结尾,并以接口类型的名称开头。它们旨在提供帮助,允许您将COM coclass视为.NET类。

然而,它们导致了一个非常严重的版本控制问题。当我使用oleview.exe在我的机器上查看mshtml.tlb时,我看到了HTMLHeadElement coclass的定义:

代码语言:javascript
复制
[
  uuid(3050F493-98B5-11CF-BB82-00AA00BDCE0B),
  noncreatable
]
coclass HTMLHeadElement {
    [default] dispinterface DispHTMLHeadElement;
    [default, source] dispinterface HTMLElementEvents;
    [source] dispinterface HTMLElementEvents2;
    interface IHTMLElement;
    interface IHTMLElement2;
    interface IHTMLElement3;
    interface IHTMLElement4;
    interface IHTMLUniqueName;
    interface IHTMLDOMNode;
    interface IHTMLDOMNode2;
    interface IHTMLElement5;
    interface IHTMLDOMConstructor;
    interface IHTMLHeadElement;
    interface IHTMLHeadElement2;
};

当我右键单击源代码中的mshtml.HtmlHeadElementClass并选择Go To Definition时,我看到了以下内容:

代码语言:javascript
复制
public class HTMLHeadElementClass : DispHTMLHeadElement, HTMLHeadElement, 
   HTMLElementEvents_Event, IHTMLElement, IHTMLElement2, IHTMLElement3, 
   IHTMLElement4, IHTMLUniqueName, IHTMLDOMNode, IHTMLDOMNode2, 
   IHTMLHeadElement, IHTMLElementEvents2_Event {
   // Lots of members
   //...
}

请注意两者之间的不匹配。我从Oleview得到的那个有额外的接口,IHtmlElement5和IHtmlHeadElement2。原因很容易解释,我的机器上安装了IE9。互操作定义来自mshtml PIA。这是一个旧版本,可能可以追溯到IE7。

可怕的问题是新的IHtmlElement5接口被插入到继承列表中。这是一个非常严重的错误,至少就.NET代码而言是如此。这对纯COM代码来说一点也不重要,它只与接口一起工作,并使用QueryInterface向coclass请求接口指针。然而,对于.NET包装器类来说,它是致命的偏移量(),所有通过IHTMLDOMNode2的方法都有错误的偏移量。因此,如果您调用IHTMLHeadElement.appendChild方法,那么您最终将调用错误的方法。

这是一个无法解决的问题。您可以卸载PIA并生成您自己的interop.mshtml.dll互操作库,它将在您的机器上正常工作。但是它在另一台没有安装IE9的机器上不能正常工作。

不过,有一个很好的变通方法,就是不要使用XxxClass类。仅使用接口类型。它应该类似于这样(在Winforms应用程序中测试):

代码语言:javascript
复制
        var doc = (IHTMLDocument2)webBrowser1.Document.DomDocument;
        var headItems = (IHTMLElementCollection)doc.all.tags("head");
        var scriptObject = (IHTMLScriptElement)doc.createElement("script");
        scriptObject.type = @"text/javascript";
        //scriptObject.text = TTS.TTSWebFactory.GetJavascript();
        var node = (IHTMLDOMNode)headItems.item(null, 0);
        node.appendChild((IHTMLDOMNode)scriptObject);

我有意使用转换为(IHTMLDOMNode)而不是(IHTMLHeadElement),因为这个较小的接口已经足够好,可以访问item元素。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10193253

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档