Подтвердить что ты не робот

Поддерживает ли С#.NET поддержку позднего связывания IDispatch?


Вопрос

Мой вопрос: Поддерживает ли С# поддержку позднего связывания IDispatch?


Притвориться, что я пытаюсь автоматизировать Office, будучи совместимым с любой версией, установленной клиентом.

В мире .NET, если вы создали с установленным Office 2000, каждый разработчик и каждый клиент, отныне до конца срока, должен иметь Office 2000.

В мире перед .NET мы использовали COM для общения с приложениями Office.

Например:

1) Используйте независимую версию версии ProgID

"Excel.Application"

который разрешает:

clsid = {00024500-0000-0000-C000-000000000046}

а затем используя COM, мы просим, ​​чтобы один из этих классов был создан в объект:

IUnknown unk;
CoCreateInstance(
    clsid, 
    null,
    CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
    IUnknown, 
    out unk);

И теперь мы уходим на гонки - умеем использовать Excel из моего приложения. Конечно, если вы действительно хотите использовать объект, вы должны вызвать способ вызова методов.

Мы могли бы получить различные объявления интерфейса, переведенные на наш язык. Этот метод хорош, потому что мы получаем

  • раннее связывание
  • code-insight
  • проверка синтаксиса типа компиляции

а пример кода может быть:

Application xl = (IExcelApplication)unk;
ExcelWorkbook workbook = xl.Workbooks.Add(template, lcid);
Worksheet worksheet = workbook.ActiveSheet;

Но есть недостатки в использовании интерфейсов: нам нужно получить различные декларации интерфейса, переданные на наш язык. И мы застряли, используя вызовы на основе методов, указав все параметры, например:

ExcelWorkbook workbook = xl.Workbooks.Add(template, lcid);
xl.Worksheets.Add(before, after, count, type, lcid);

Это доказало, что в реальном мире есть такие недостатки, которые мы бы с готовностью отказались:

  • раннее связывание
  • код-прозрение
  • проверка синтаксиса времени компиляции

и вместо этого используйте IDispatch позднюю привязку:

Variant xl = (IDispatch)unk;
Variant newWorksheet = xl.Worksheets.Add();

Поскольку автоматизация Excel была разработана для VB Script, многие параметры могут быть опущены, даже если нет перегрузки без них.

Примечание. Не путайте мой пример Excel по причине того, почему я хочу использовать IDispatch. Не каждый COM-объект является Excel. Некоторые COM-объекты не имеют поддержки, кроме как через IDispatch.

4b9b3361

Ответ 1

Вы можете, relativly, использовать привязку IDispatch с поздним связыванием в С#.

http://support.microsoft.com/kb/302902

Вот пример для использования Excel. Таким образом, вам не нужно добавлять ненужную зависимость от Microsoft bloaty PIA:

//Create XL
Object xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));

//Get the workbooks collection.
//   books = xl.Workbooks;
Object books = xl.GetType().InvokeMember( "Workbooks", 
      BindingFlags.GetProperty, null, xl, null);

//Add a new workbook.
//   book = books.Add();
Objet book = books.GetType().InvokeMember( "Add", 
      BindingFlags.InvokeMethod, null, books, null );

//Get the worksheets collection.
//   sheets = book.Worksheets;
Object sheets = book.GetType().InvokeMember( "Worksheets",
      BindingFlags.GetProperty, null, book, null );

Object[] parameters;

//Get the first worksheet.
//   sheet = sheets.Item[1]
parameters = new Object[1];
parameters[0] = 1;
Object sheet = sheets.GetType().InvokeMember( "Item", 
      BindingFlags.GetProperty, null, sheets, parameters );

//Get a range object that contains cell A1.
//   range = sheet.Range["A1];
parameters = new Object[2];
parameters[0] = "A1";
parameters[1] = Missing.Value;
Object range = sheet.GetType().InvokeMember( "Range",
      BindingFlags.GetProperty, null, sheet, parameters );

//Write "Hello, World!" in cell A1.
//   range.Value = "Hello, World!";
parameters = new Object[1];
parameters[0] = "Hello, World!";
objRange_Late.GetType().InvokeMember( "Value", BindingFlags.SetProperty, 
      null, range, parameters );

//Return control of Excel to the user.
//   xl.Visible = true;
//   xl.UserControl = true;
parameters = new Object[1];
parameters[0] = true;
xl.GetType().InvokeMember( "Visible", BindingFlags.SetProperty,
      null, xl, Parameters );
xl.GetType().InvokeMember( "UserControl", BindingFlags.SetProperty,
      null, xl, Parameters );

Ответ 2

Вы должны ждать появления С# 4.0, чтобы получить последнее связывание, которое вы ищете. Каждый раз, когда мне нужны возможности взаимодействия, я переключаюсь обратно в режим VB.Net, поэтому я могу использовать возможности COM, которые, как представляется, отсутствуют.

Простым методом, который я использую, является создание класса в VB.Net, который выполняет работу IDispatch, а затем раскрывает методы, которые я хочу использовать в качестве методов моего обертки, и затем я могу называть их по своему коду кодом С#. Не самые изящные решения, но за последние несколько месяцев он вывел меня из джема или двух.

Ответ 3

С# 4 dynamic ключевое слово поддерживает IDispatch и позднюю привязку. Вы можете прочитать Sam Ng динамические серии для получения дополнительной информации

О, а С# 4 доступен только как CTP. Вам придется либо ждать Visual Studio vNext, либо использовать бета-версию (которая работает на виртуальном ПК Windows Server 2008), чтобы использовать ее.

Ответ 4

Как говорили другие, используя С# 4 "динамические" ключевые слова. Вот простой пример - это гораздо более сукцинт, чем использование "InvokeMethod"

dynamic xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));
dynamic books = xl.Workbooks;
dynamic book = books.Add();

Console.WriteLine(books.Count);     //Writes 1

foreach (dynamic b in books)        
{
Console.WriteLine(b.Name);      //Writes "Book1"
}

Ответ 5

Вероятно, вы можете уйти с гораздо более приятным кодом в С# 2.0/3.0, если вы потратите время на создание интерфейса содержащий методы и свойства, которые вы хотите от объекта, и добавить некоторые атрибуты (я пишу его из памяти, поэтому детали могут быть неправильными, но я клянусь, что это сработало для меня...)

    using System.Runtime.Interopservices;

    [Guid("00024500-0000-0000-C000-000000000046")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    interface IExcel
    {
      // sample property
      string Name{get;}
      // more properties
    }

    // and somewhere else
    void main()
    {
      Object xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));
      IExcel excel = (IExcel)xl;
      string name = xl.name
    }

Как уже упоминалось, код не будет работать из коробки, это скорее намек на то, что нужно копать в msdn.

Ответ 6

Эй, чувак, В настоящее время у меня есть 2 проекта codeplex для решения этой проблемы.

первый из них - LateBindingApi.Excel http://excel.codeplex.com отображаемый обратный вызов с призывом к хорошо известной объектной модели. это был тестовый проект для следующего проекта.

второй - это CodeGenerator http://latebindingapi.codeplex.com инструмент создает проекты С# из библиотек типа COM. сгенерированные проекты включают объекты сопоставления с latebind, доступ к COM-серверу. основным моментом является то, что инструмент преобразует библиотеки типа COM в разных версиях в один проект (например, excel 9,10,11) и помещает все объекты с самонастраиваемым атрибутом SupportByLibrary Attribut. Я проанализировал все офисные приложения в версии 9,10,11,12,14 с этим инструментом сейчас и создаю решение С#, которое доступно как протестированное бета-тестирование с образцом кода на главной странице.