Domanda

Nel mio ultimo ambiente di sviluppo, sono stato in grado di interagire facilmente con COM, chiamando metodi su oggetti COM. Ecco il codice originale, tradotto in codice stile C # (per mascherare la lingua originale):

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

Ora inizia il noioso, doloroso processo di tentativo di interoperare con COM dal codice gestito.

PInvoke.net contiene già la IWebBrower2 translation , la relazione relavent di che è:

[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; }
}

Ho creato la classe COM:

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

Quindi ora è il momento della mia transazione C # effettiva:

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

I lettori attenti notano che IWebBrowser2.Document è un IDispatch in ritardo. Stiamo utilizzando Visual Studio 2005, con .NET 2.0 sui nostri computer e sui nostri clienti.

Quindi qual è il metodo .NET 2.0 per invocare metodi su un oggetto che, ad un certo livello, supporta solo IDispatch con ritardo di ritardo?

Viene visualizzata una rapida ricerca di Stack Overflow per l'utilizzo di IDispatch da C # questo post dire ciò che voglio non è possibile in .NET.

Quindi è possibile usare COM da C # .NET 2.0?


La domanda è che esiste un modello di progettazione accettato che voglio usare in C # /. NET. Implica l'avvio di Internet Explorer fuori processo e la fornitura di contenuto HTML, senza l'utilizzo di file temporanei.

Un'idea di design rifiutata ospita Internet Explorer su un WinForm.

Un'alternativa accettabile è l'avvio del browser Web registrato di sistema, che consente di visualizzarlo in HTML, senza utilizzare un file temporaneo.

L'ostacolo continua a utilizzare oggetti COM nel mondo .NET. Il problema specifico riguarda l'esecuzione di chiamate in ritardo verso IDispatch senza la necessità di C # 4.0. (ad es. durante l'utilizzo di .NET 2.0)

È stato utile?

Soluzione 2

IDispatch associato in ritardo chiamato è relativamente facile in .NET, anche se pisciante:

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

La domanda SO referenziata che originariamente diceva "non è possibile fino a C # 4.0" è stato modificato per mostrare come è possibile in .NET 2.0.

C # .NET supporta il binding tardivo di IDispatch?

Altri suggerimenti

  

Aggiornamento: in base agli aggiornamenti delle domande, ho rimosso le parti della mia risposta che non sono più pertinenti alla domanda. Tuttavia, nel caso in cui altri lettori stiano cercando un modo rapido e sporco per generare HTML in un'app winforms e non richiedano un IE in-process, lascerò quanto segue:

Possibile scenario 1: l'obiettivo finale è semplicemente mostrare HTML all'utente finale e utilizzare Windows Form

System.Windows.Forms.WebBrowser è il wrapper .NET estremamente semplice per l'interfaccia che si sta tentando di implementare manualmente. Per ottenerlo, trascina e rilascia un'istanza di quell'oggetto dalla tua barra degli strumenti (elencata come "Browser Web" nella sezione "Tutti i moduli di Windows") sul tuo modulo. Quindi, su un gestore di eventi adatto:

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

Nella mia app di test, questo mostrava correttamente il messaggio ossessivo che tutti abbiamo imparato a temere e detestare.

Le risposte nel post a cui ti colleghi sono in realtà errate. In genere è molto semplice gestire oggetti basati su IDispatch in .Net. Fondamentalmente attraversi tre passaggi:

La maggior parte degli oggetti di automazione (probabilmente ben oltre il 90%) esposti come interfacce IDispatch hanno altre interfacce che possono essere utilizzate da client COM di tipo non scripting (l'interfaccia IDispatch è in realtà un'interfaccia COM completa derivata da IDispatch o l'oggetto supporta una o più altre interfacce derivate IUnknown). In questo caso, è sufficiente importare la definizione dell'interfaccia COM appropriata e quindi trasmettere l'oggetto all'interfaccia appropriata. Il cast chiama QueryInterface sotto le copertine e restituisce un riferimento a capo all'interfaccia desiderata.

Questa è la tecnica che useresti nello scenario che hai presentato sopra. L'oggetto Document restituito dall'oggetto di automazione IE supporta le interfacce IHTMLDocument, IHTMLDocument2, IHTMLDocument3, IHTMLDocument4 e IHTMLDocument5 (a seconda della versione di IE in uso). È necessario eseguire il cast all'interfaccia appropriata e quindi chiamare il metodo appropriato. Ad esempio:

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

Nel raro caso in cui l'oggetto di automazione non supporti un'interfaccia alternativa. Quindi dovresti usare VB.Net per avvolgere quell'interfaccia. Con Option Strict impostato su off (solo per la classe wrapper) è possibile utilizzare il supporto integrato di VB per le chiamate associate in ritardo per chiamare semplicemente i metodi IDispatch appropriati sotto le copertine. In rari casi con tipi di argomenti insoliti potresti dover giocherellare un po 'con la chiamata ma, in generale, in VB puoi semplicemente farlo! Anche con le aggiunte dinamiche a C # v4 VB probabilmente avrà ancora un supporto significativamente migliore per le chiamate COM in ritardo.

Se per qualche motivo non è possibile utilizzare VB per avvolgere l'interfaccia di automazione, è comunque possibile effettuare tutte le chiamate necessarie da C # usando la reflection. Non entrerò nei dettagli poiché questa opzione non dovrebbe praticamente mai essere utilizzata, ma ecco un un piccolo esempio che coinvolge Office automazione .

Vedi questo articolo: http://www.codeproject.com/KB/cs/IELateBindingAutowod.aspx

Automazione dell'associazione tardiva di Internet Explorer Di yincekara

Codice di esempio per l'automazione di Internet Explorer che utilizza l'associazione tardiva, senza Microsoft.mshtml e dipendenza shdocvw.

per htmlDoc.write (htmlString); modifica

   [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);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top