.NET2.0 C # Взаимодействие: Как вызвать код COM из C #? - PullRequest
3 голосов
/ 22 января 2009

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

Ответы [ 4 ]

4 голосов
/ 23 января 2009

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

Возможный сценарий 1: конечная цель - просто отобразить HTML для конечного пользователя и использовать Windows Forms

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

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

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

3 голосов
/ 29 января 2009

Вызов с поздним связыванием 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, в котором изначально говорилось "невозможно до C # 4.0", был изменен, чтобы показать, как это возможно в .NET 2.0.

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

0 голосов
/ 18 июня 2009

Смотрите эту статью: 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);
0 голосов
/ 29 января 2009

Ответы в сообщении, на которое вы ссылаетесь, фактически неверны. Как правило, очень легко иметь дело с объектами на основе 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 .

...