Вопрос

В моей последней среде разработки я мог легко взаимодействовать с 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 с поздней привязкой?

Быстрый поиск переполнения стека для использования IDispatch из C # обнаруживает этот пост сказать, что я хочу, невозможно в .NET.

Так можно ли использовать COM из C # .NET 2.0?

<Ч>

Вопрос в том, что существует принятый шаблон проектирования, который я хочу использовать в C # / .NET. Он включает запуск Internet Explorer вне процесса и предоставление ему содержимого HTML, при этом временные файлы не используются.

Отклоненная идея дизайна - разместить Internet Explorer на WinForm.

Приемлемой альтернативой является запуск зарегистрированного в системе веб-браузера с отображением HTML-кода без использования временного файла.

Камень преткновения продолжает использовать COM-объекты в мире .NET. Конкретная проблема заключается в выполнении вызовов поздней привязки к IDispatch без использования C # 4.0. (т.е. при использовании .NET 2.0)

Это было полезно?

Решение 2

Вызов с поздним связыванием 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);
}

Ссылочный SO-вопрос, в котором изначально было указано "! было изменено, чтобы показать, как это возможно в .NET 2.0.

Поддерживает ли C # .NET позднюю привязку IDispatch?

Другие советы

  

Обновление . На основе обновлений вопросов я удалил части своего ответа, которые больше не относятся к вопросу. Однако, если другие читатели ищут быстрый и грязный способ создания HTML в приложении winforms и не требуют встроенного IE, я оставлю следующее:

Возможный сценарий 1. Конечная цель - просто показать HTML конечному пользователю и использовать Windows Forms

System.Windows.Forms.WebBrowser - кропотливо простая оболочка .NET для интерфейса, который вы пытаетесь реализовать вручную. Чтобы получить его, перетащите экземпляр этого объекта с панели инструментов (указан как & Quot; веб-браузер & Quot; в разделе & Quot; все Windows Forms & Quot; раздел) на вашу форму , Затем на некотором подходящем обработчике событий:

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

В моем тестовом приложении это правильно отображало навязчивое сообщение, которое мы все научились бояться и ненавидеть.

Ответы в сообщении, на которое вы ссылаетесь, на самом деле неверны. Как правило, очень легко иметь дело с объектами на основе IDispatch в .Net. В основном вы проходите три этапа:

Большинство объектов автоматизации (вероятно, более чем на 90%), которые представлены как интерфейсы IDispatch, имеют другие интерфейсы, которые могут использоваться клиентами COM, не относящимися к сценариям (либо интерфейс IDispatch на самом деле является полным интерфейсом COM, полученным из IDispatch, либо объектом поддерживает один или несколько других производных IUnknown интерфейсов). В этом случае вы просто импортируете соответствующее определение интерфейса COM и затем приведете объект к соответствующему интерфейсу. Приведение вызывает QueryInterface под обложками и возвращает упакованную ссылку на нужный интерфейс.

Это техника, которую вы бы использовали в сценарии, который вы представили выше. Объект Document, возвращаемый из объекта автоматизации IE, поддерживает интерфейсы IHTMLDocument, IHTMLDocument2, IHTMLDocument3, IHTMLDocument4 и IHTMLDocument5 (в зависимости от используемой версии IE). Вы должны привести к соответствующему интерфейсу и затем вызвать соответствующий метод. Например:

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

В редком случае, когда объект автоматизации не поддерживает альтернативный интерфейс. Тогда вам следует использовать VB.Net для обертывания этого интерфейса. Если для параметра Option Strict задано значение off (только для класса-оболочки), вы можете использовать встроенную поддержку VB для вызовов с поздним связыванием, чтобы просто вызывать соответствующие методы IDispatch под прикрытием. В редких случаях с необычными типами аргументов вам может понадобиться немного поиграть с вызовом, но, как правило, в VB вы можете просто сделать это! Даже с динамическими добавлениями в C # v4 VB, вероятно, будет значительно лучше поддерживать COM-вызовы с поздней привязкой.

Если по какой-то причине вы не можете использовать VB для переноса интерфейса автоматизации, вы все равно можете делать любые необходимые вызовы из C #, используя отражение. Я не буду вдаваться в подробности, так как этот параметр в принципе никогда не должен использоваться, но вот небольшой небольшой пример с Office автоматизация .

Смотрите эту статью: http://www.codeproject.com/KB/cs/IELateBindingAutowod.aspx

Internet Explorer Поздняя привязка автоматизации По Инцекара

Пример кода автоматизации Internet Explorer с использованием позднего связывания, без зависимости Microsoft.mshtml и shdocvw.

для 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