2012-04-17 7 views
1

현재 웹 사이트에 JavaScript 코드를 삽입하기 위해 MS HTML을 사용하고 있습니다.MSHTML HTMLHeadElementClass COM 오류

Microsoft HTML Object Library에 대한 참조를 만들고이 코드를 입력합니다.

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); 

스크립트 맨 마지막 줄에 오류가 발생했습니다. 이것은 메시지입니다.

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과 많은 경험이 없어 그가 코드를 마지막 라인 INT를 유지하는 것이 중요하다, 어느 날이게 무슨 뜻인지 이해하고 어떻게 그것을 해결할 수 있습니까?

답변

6

mshtml.tlb와 같은 형식 라이브러리에서 얻을 수있는 interop 클래스에는 매우 심각한 문제가 있습니다. 형식 라이브러리 임포터는 형식 라이브러리의 coclass 정의에서 synthetic .NET 클래스를 생성합니다. 유형 이름에서 인식 할 수 있으며, "클래스"로 끝나고 인터페이스 유형의 이름으로 시작합니다. 그것들은 COM 클래스가 .NET 클래스 인 것처럼 COM coclass를 처리 할 수 ​​있도록 도와줍니다.

그러나 이는 매우 심각한 버전 문제를 유발합니다. 나는 소스 코드에 mshtml.HtmlHeadElementClass을 마우스 오른쪽 버튼으로 클릭하고 선택하면

[ 
    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.tlb에보고 oleview.exe을 사용하는 경우 다음 나는 HTMLHeadElement의 coclass에 대한이 정의를 참조 나는 이것을 본다 :

public class HTMLHeadElementClass : DispHTMLHeadElement, HTMLHeadElement, 
    HTMLElementEvents_Event, IHTMLElement, IHTMLElement2, IHTMLElement3, 
    IHTMLElement4, IHTMLUniqueName, IHTMLDOMNode, IHTMLDOMNode2, 
    IHTMLHeadElement, IHTMLElementEvents2_Event { 
    // Lots of members 
    //... 
} 

둘 사이의 불일치에 유의한다. Oleview에서받은 것은 여분의 인터페이스, IHtmlElement5 및 IHtmlHeadElement2입니다. 그 이유는 설명하기 쉽습니다, 나는 내 컴퓨터에 IE9를 설치했습니다. interop 정의는 mshtml PIA에서 가져온 것입니다. 어느 오래된 버전, 아마 IE7 데이트.

새로운 IHtmlElement5 인터페이스가 을 상속 목록에 삽입하여을 삽입했습니다. 이것은 적어도 심각한 오류였습니다. 적어도 .NET 코드가 간다. 순수한 COM 코드는 전혀 중요하지 않습니다.이 인터페이스는 QueryInterface를 사용하여 인터페이스 포인터를 찾아서 코 클라스에 요청합니다. 그러나 은 .NET 래퍼 클래스에 치명적인입니다. IHTMLDOMNode2를 통과 한 모든 메서드에는 잘못된 오프셋이 있습니다. 그래서 IHTMLHeadElement.appendChild 메서드를 호출하면 메서드로 잘못 호출하게됩니다.

이것은 해결할 수없는 문제입니다. PIA를 제거하고 자신의 interop.mshtml.dll interop 라이브러리를 생성 할 수 있습니다.이 라이브러리는 컴퓨터에서 올바르게 작동합니다. 그러나 IE9가 설치되지 않은 다른 컴퓨터에서는 제대로 작동하지 않습니다.

사용할 수있는 좋은 해결 방법이 있지만 은 XxxClass 클래스을 사용하지 마십시오. 인터페이스 유형 만 사용하십시오. 어느 (윈폼 응용 프로그램에서 테스트)이 유사한다고 : 그 작은 인터페이스는 항목 요소에 액세스 할 수 이미 충분히 좋은했기 때문에 내가 의도적으로 대신 (IHTMLHeadElement)의 (IHTMLDOMNode)에 캐스트를 사용

 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); 

.