Question

Dans mon dernier environnement de développement, je pouvais facilement interagir avec COM en appelant des méthodes sur des objets COM. Voici le code original, traduit en code de style C # (pour masquer la langue d'origine):

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

Commence maintenant le processus fastidieux et pénible d’essai d’interopérabilité avec COM à partir de code géré.

PInvoke.net contient déjà la traduction de IWebBrower2 , la por qui est:

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

J'ai créé la classe COM:

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

Le moment est donc venu pour ma transaction C # actuelle:

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

Les lecteurs attentifs remarquent que IWebBrowser2.Document est un IDispatch à liaison tardive. Nous utilisons Visual Studio 2005, avec .NET 2.0 sur nos machines et celles de nos clients.

Alors, quelle est la méthode .NET 2.0 pour invoquer des méthodes sur un objet qui, à un certain niveau, ne prend en charge que IDispatch lié tardivement?

Une recherche rapide dans Stack Overflow pour l'utilisation d'IDispatch à partir de C # révèle ce message. Dire ce que je veux n'est pas possible dans .NET.

Est-il possible d'utiliser COM à partir de C # .NET 2.0?

La question est qu’il existe un modèle de conception accepté que je souhaite utiliser en C # / .NET. Cela implique de lancer Internet Explorer hors processus et de lui donner du contenu HTML sans utiliser de fichiers temporaires.

Une idée de conception rejetée consiste à héberger Internet Explorer sur un formulaire WinForm.

Une alternative acceptable est de lancer le navigateur Web enregistré par le système, en lui donnant le code HTML à afficher, sans utiliser de fichier temporaire.

La pierre d'achoppement continue à utiliser des objets COM dans le monde .NET. Le problème spécifique implique d'effectuer des appels tardifs à IDispatch sans avoir besoin de C # 4.0. (c'est-à-dire en utilisant .NET 2.0)

Était-ce utile?

La solution 2

IDispatch lié tardivement appelé est relativement facile dans .NET, bien que pauvre en pisse:

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 question SO référencée qui disait à l'origine "impossible avant C # 4.0". a été modifié pour montrer comment cela est possible dans .NET 2.0.

C # .NET prend-il en charge la liaison tardive IDispatch?

Autres conseils

  

Mise à jour : après la mise à jour des questions, j'ai supprimé les parties de ma réponse qui ne sont plus pertinentes pour la question. Toutefois, si d’autres lecteurs recherchent un moyen rapide et imprudent de générer du HTML dans une application winforms et ne nécessitent pas d’IE en cours de traitement, je vous laisse:

Scénario 1 possible: l'objectif ultime est simplement d'afficher du code HTML à votre utilisateur final et d'utiliser Windows Forms

System.Windows.Forms.WebBrowser est l'encapsuleur .NET extrêmement simple à utiliser pour l'interface que vous essayez d'implémenter manuellement. Pour l'obtenir, faites glisser une occurrence de cet objet depuis votre barre d'outils (répertoriée en tant que "Navigateur Web" dans la section "Tous les formulaires Windows") sur votre formulaire. Ensuite, sur un gestionnaire d’événement approprié:

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

Sur mon application de test, ceci affichait correctement le message obsédant que nous avons tous appris à craindre et à haïr.

Les réponses dans le message auquel vous créez un lien sont en réalité incorrectes. Il est généralement très facile de traiter des objets basés sur IDispatch dans .Net. En gros, vous passez par trois étapes:

La plupart des objets d'automatisation (probablement bien supérieurs à 90%) exposés en tant qu'interfaces IDispatch ont d'autres interfaces qui peuvent être utilisées par les clients COM de type sans script (l'interface IDispatch est en fait une interface COM complète dérivée d'IDispatch ou l'objet prend en charge une ou plusieurs autres interfaces dérivées IUnknown). Dans ce cas, il vous suffira d'importer la définition d'interface COM appropriée, puis de convertir l'objet en interface appropriée. La distribution appelle QueryInterface sous les couvertures et renvoie une référence encapsulée à l'interface souhaitée.

C’est la technique que vous utiliseriez dans le scénario que vous avez présenté ci-dessus. L'objet Document renvoyé par l'objet d'automatisation IE prend en charge les interfaces IHTMLDocument, IHTMLDocument2, IHTMLDocument3, IHTMLDocument4 et IHTMLDocument5 (selon la version d'IE utilisée). Vous devez transtyper vers l'interface appropriée, puis appeler la méthode appropriée. Par exemple:

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

Dans les rares cas où l'objet d'automatisation ne prend pas en charge une autre interface. Ensuite, vous devriez utiliser VB.Net pour envelopper cette interface. Lorsque Option Strict est défini sur off (pour la classe d'encapsuleur uniquement), vous pouvez utiliser la prise en charge intégrée de VB pour les appels à liaison tardive pour simplement appeler les méthodes IDispatch appropriées sous les couvertures. Dans de rares cas avec des types d'argument inhabituels, vous devrez peut-être jouer un peu avec l'appel, mais en général, en VB, vous pouvez simplement le faire! Même avec les ajouts dynamiques à C # v4, VB aura probablement encore un support nettement meilleur pour les appels COM à liaison tardive.

Si pour une raison quelconque vous ne pouvez pas utiliser VB pour envelopper l'interface d'automatisation, vous pouvez toujours passer les appels nécessaires à partir de C # en utilisant la réflexion. Je n’entrerai pas dans les détails car cette option ne devrait en principe jamais être utilisée, mais voici un petit exemple impliquant Office automatisation .

Voir cet article: http://www.codeproject.com/KB/cs/IELateBindingAutowod.aspx

Automatisation de la liaison tardive dans Internet Explorer Par yincekara

Exemple de code d'automatisation Internet Explorer utilisant une liaison tardive, sans dépendance Microsoft.mshtml et shdocvw.

pour htmlDoc.write (htmlString); modifier

   [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);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top