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