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

StackOverflow https://stackoverflow.com/questions/403218

  •  03-07-2019
  •  | 
  •  

Вопрос


Вопрос

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


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

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

В мире до .NET мы использовали КОМ для общения с приложениями 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 изнутри моего приложения.Конечно, если Действительно вы хотите использовать объект, вам нужно вызвать какой-то способ вызова методов.

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

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

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

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.

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

Решение

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

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

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

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

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

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

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

С# 4 dynamic Ключевое слово поддерживает IDispatch и позднее связывание.Вы можете прочитать Сэма Нг динамичный сериал Чтобы получить больше информации

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

Вероятно, вы можете сойти с рук с гораздо более приятным кодом в C# 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.

Как уже говорили другие, использование ключевого слова "dynamic" в С#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"
}

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top