문제

마지막 개발 환경에서 COM과 쉽게 상호 작용하여 COM 객체에서 메소드를 호출 할 수있었습니다. 다음은 C# 스타일 코드로 번역 된 원본 코드입니다 (원래 언어를 마스킹하기 위해).

public static void SpawnIEWithSource(String szSourceHTML)
{
    OleVariant ie; //IWebBrowser2
    OleVariant ie = new InternetExplorer();
    ie.Navigate2("about:blank");

    OleVariant webDocument = ie.Document;
    webDocument.Write(szSourceHTML);
    webDocument.close;

    ie.Visible = True;
}

이제 관리 된 코드에서 COM과 인터 로프하려는 지루하고 고통스럽고 과정을 시작합니다.

pinvoke.net은 이미 포함되어 있습니다 iWebBrower2 번역,이 릴라 벤트는 다음과 같습니다.

[ComImport, 
   DefaultMember("Name"), 
   Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"), 
   InterfaceType(ComInterfaceType.InterfaceIsIDispatch), 
   SuppressUnmanagedCodeSecurity]
public interface IWebBrowser2
{
    [DispId(500)]
    void Navigate2([In] ref object URL, [In] ref object Flags, [In] ref object TargetFrameName, [In] ref object PostData, [In] ref object Headers);

    object Document { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xcb)] get; }
}

COM 클래스를 만들었습니다.

[ComImport]
[Guid("0002DF01-0000-0000-C000-000000000046")]
public class InternetExplorer
{
}

이제 실제 C# 거래를위한 시간입니다.

public static void SpawnIEWithSource(String szHtml)
{
    PInvoke.ShellDocView.IWebBrowser2 ie;
    ie = (PInvoke.ShellDocView.IWebBrowser2)new PInvoke.ShellDocView.InternetExplorer();

    //Navigate to about:blank to initialize the browser
    object o = System.Reflection.Missing.Value;
    String url = @"about:blank";
    ie.Navigate2(ref url, ref o, ref o, ref o, ref o);

    //stuff contents into the document
    object webDocument = ie.Document;
    //webDocument.Write(szHtml);
    //webDocument.Close();

    ie.Visible = true;
}

신중한 독자는 iwebbrowser2.document가 늦게 바운드 Idispatch라는 것을 알 수 있습니다. 우리는 Visual Studio 2005를 사용하고 있으며, 고객의 기계 및 기계에 .NET 2.0을 사용하고 있습니다.

그렇다면 .NET 2.0 메소드는 어떤 수준에서도 후기 바운드 IDISPATCH 만 지원하는 객체에서 메소드를 호출하는 방법은 무엇입니까?

C#에서 idispatch를 사용하기위한 스택 오버 플로우를 빠르게 검색하면 이 게시물 .NET에서 내가 원하는 것을 말하는 것은 불가능합니다.

그렇다면 c# .net 2.0에서 com을 사용할 수 있습니까?


문제는 C#/. Net에서 사용하려는 허용 된 설계 패턴이 있다는 것입니다. 임시 파일을 사용하지 않고 인터넷 익스플로러를 시작하고 HTML 컨텐츠를 제공하는 것이 포함됩니다.

거부 된 디자인 아이디어는 WinForm에서 Internet Explorer를 주최합니다.

허용 가능한 대안은 시스템 등록 웹 브라우저를 시작하여 임시 파일을 사용하지 않고 HTML을 표시 할 수 있습니다.

걸림돌은 .NET 세계에서 COM 객체를 계속 사용하고 있습니다. 구체적인 문제는 C# 4.0을 필요로하지 않고 IDISPATCH에 대한 늦은 바인딩 호출을 수행하는 것입니다. (즉, .NET 2.0을 사용하는 동안)

도움이 되었습니까?

해결책 2

PISS-POOR이지만 .NET에서는 늦은 바운드 IdisPatch가 쉽게 .NET에서 쉽습니다.

public static void SpawnIEWithSource(String szHtml)
{
    // Get the class type and instantiate Internet Explorer.
    Type ieType = Type.GetTypeFromProgID("InternetExplorer.Application");
    object ie = Activator.CreateInstance(ieType);

    //Navigate to the blank page in order to make sure the Document exists
    //ie.Navigate2("about:blank");
    Object[] parameters = new Object[1];
    parameters[0] = @"about:blank";
    ie.GetType().InvokeMember("Navigate2", BindingFlags.InvokeMethod | BindingFlags.IgnoreCase, null, ie, parameters);

    //Get the Document object now that it exists
    //Object document = ie.Document;
    object document = ie.GetType().InvokeMember("Document", BindingFlags.GetProperty | BindingFlags.IgnoreCase, null, ie, null);

    //document.Write(szSourceHTML);
    parameters = new Object[1];
    parameters[0] = szHtml;
    document.GetType().InvokeMember("Write", BindingFlags.InvokeMethod | BindingFlags.IgnoreCase, null, document, parameters);

    //document.Close()
    document.GetType().InvokeMember("Close", BindingFlags.InvokeMethod | BindingFlags.IgnoreCase, null, document, null);

    //ie.Visible = true;
    parameters = new Object[1];
    parameters[0] = true;
    ie.GetType().InvokeMember("Visible", BindingFlags.SetProperty | BindingFlags.IgnoreCase, null, ie, parameters);
}

원래 "C# 4.0까지 불가능한"이라는 언급 된 질문은 .NET 2.0에서 가능한 방법을 보여주기 위해 수정되었습니다.

C# .NET은 IdisPatch 후기 바인딩을 지원합니까?

다른 팁

업데이트: 질문 업데이트를 바탕으로 더 이상 질문과 관련이없는 답변 부분을 제거했습니다. 그러나 다른 독자들이 WinForms 앱에서 HTML을 생성하는 빠르고 더러운 방법을 찾고있는 경우, 즉 프로세스 IE가 필요하지 않으면 다음을 남겨 드리겠습니다.

가능한 시나리오 1 : 궁극적 인 목표는 단순히 최종 사용자에게 HTML을 표시하고 Windows 양식을 사용하는 것입니다.

System.Windows.Forms.WebBrowser 수동으로 구현하려는 인터페이스의 힘든 .NET 래퍼입니다. 이를 얻으려면 툴바에서 해당 객체의 인스턴스를 드래그 앤 드롭 ( "모든 Windows Forms"섹션 아래에있는 "웹 브라우저"로 표시)를 양식으로 끌어 올리십시오. 그런 다음 적절한 이벤트 핸들러에서 :

webBrowser1.Navigate("about:blank");
webBrowser1.Document.Write("<html><body>Hello World</body></html>");

테스트 앱에서 이것은 우리 모두가 두려움과 혐오법을 배운 잊혀지지 않는 메시지를 올바르게 표시했습니다.

링크 된 게시물의 답변은 실제로 잘못되었습니다. .NET의 IdisPatch 기반 객체를 처리하는 것은 일반적으로 매우 쉽습니다. 기본적으로 세 단계를 거칩니다.

Idispatch 인터페이스로 노출되는 대부분의 자동화 객체 (아마도 90%이상)는 비 스크립팅 유형 COM 클라이언트에서 사용할 수있는 다른 인터페이스가 있습니다 (IDISPatch 인터페이스는 실제로 IDISPATCH에서 파생 된 전체 COM 인터페이스 또는 개체가 하나 또는 하나 또는 객체 지원입니다. 더 많은 다른 iunknown 파생 인터페이스). 이 경우 적절한 COM 인터페이스 정의를 단순히 가져온 다음 객체를 적절한 인터페이스에 캐스트합니다. 캐스트는 표지 아래에서 QueryInterface를 호출하고 원하는 인터페이스에 대한 랩핑 참조를 반환합니다.

이것은 위에서 제시 한 시나리오에서 사용할 기술입니다. IE Automation 객체에서 반환 된 문서 개체는 ihtmldocument, ihtmldocument2, ihtmldocument3, ihtmldocument4 및 ihtmldocument5 인터페이스를 지원합니다 (사용중인 IE 버전에 따라 다름). 적절한 인터페이스로 캐스트 한 다음 적절한 방법을 호출해야합니다. 예를 들어:

IHTMLDocument2 htmlDoc = (IHTMLDocument2)webDocument;
htmlDoc.Write(htmlString);
htmlDoc.Close();

자동화 객체가 대체 인터페이스를 지원하지 않는 드문 경우. 그런 다음 vb.net을 사용하여 해당 인터페이스를 랩핑해야합니다. 옵션 strict set to Off (래퍼 클래스에만 해당)를 사용하면 늦은 바운드 호출을 위해 VB의 내장 지원을 사용하여 표지 아래에 적절한 idispatch 메소드를 호출 할 수 있습니다. 비정상적인 인수 유형이있는 드문 경우에는 전화로 약간의 바이올린이 필요할 수 있지만 일반적으로 VB에서는 그냥 할 수 있습니다! C# V4 VB에 동적 추가가 있더라도 여전히 후기 COM 호출에 대한 더 나은 지원이있을 것입니다.

어떤 이유로 든 VB를 사용하여 자동화 인터페이스를 랩핑 할 수없는 경우 반사를 사용하여 C#에서 필요한 호출을 할 수 있습니다. 이 옵션은 기본적으로 사용되지 않아야하지만 여기에 사무실 자동화와 관련된 작은 예.

이 기사를 참조하십시오 :http://www.codeproject.com/kb/cs/ielatebindingautowod.aspx

Yincekara의 인터넷 익스플로러 늦은 바인딩 자동화

Microsoft.MSHTML 및 SHDOCVW 종속성없이 늦은 바인딩을 사용한 Internet Explorer Automation 샘플 코드.

htmldoc.write (htmlstring); 수정하다

   [Guid("332C4425-26CB-11D0-B483-00C04FD90119")]
    [ComImport]
    [TypeLibType((short)4160)]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
    internal interface IHTMLDocument2
    {
        [DispId(1054)]
        void write([MarshalAs(UnmanagedType.BStr)] string psArray);
        //void write([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] object[] psarray);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top