28

问题

我的问题是:C# 是否天生支持后期绑定 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。当然,如果真的要使用对象,就得调用有某种调用方式的方法。

我们可以得到各种接口声明,翻译成我们的语言。这种技术很好,因为我们得到

  • 早期绑定
  • 代码洞察力
  • 编译类型语法检查

一些示例代码可能是:

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 脚本设计的,所以可以省略很多参数,即使没有它们就不会出现重载。

注意:不要将我的 Excel 示例与我想使用 IDispatch 的原因混淆。并非每个 COM 对象都是 Excel。某些 COM 对象除了通过 IDispatch 之外没有其他支持。

4

6 回答 6

26

您可以相对地在 C# 中使用后期绑定 IDispatch 绑定。

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

这是使用 Excel 的一些示例。这样你就不需要对微软臃肿的 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 );
于 2009-01-28T20:47:42.240 回答
9

您必须等待 C# 4.0 发布才能获得您正在寻找的后期绑定。每当我需要互操作功能时,我都会切换回 VB.Net 模式,这样我就可以利用 C# 似乎缺乏的 COM 功能。

我使用的简单方法是在 VB.Net 中创建一个执行 IDispatch 工作的类,然后公开我想用作包装器方法的方法,然后我可以从我的 C# 代码中随意调用它们。不是最优雅的解决方案,但在过去的几个月里,它让我摆脱了一两次的困境。

于 2008-12-31T15:43:30.300 回答
5

C# 4 的dynamic关键字支持 IDispatch 和后期绑定。您可以阅读 Sam Ng 的动态系列以获取更多信息

哦,C# 4 目前仅作为 CTP 提供。您必须等待 Visual Studio vNext 或使用测试版(在 Windows Server 2008 Virtual PC 上运行)才能使用它。

于 2008-12-31T15:36:37.257 回答
3

As others have said - using c#4's "dynamic" keyword rocks. Here's a simple example - it so much more succint than using "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"
}
于 2011-11-09T18:33:44.960 回答
2

如果您花时间编写一个包含您想要的对象的方法和属性的接口并添加一些属性(我从内存中编写它,所以细节可能不是),您可能可以在 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 中挖掘什么。

于 2009-10-31T20:31:59.227 回答
1

嘿伙计,我目前有 2 个 codeplex 项目来解决这个问题。

第一个是将 LateBindingApi.Excel http://excel.codeplex.com 映射到众所周知的对象模型的后期绑定调用调用。这是以下项目的测试项目。

the second one is a CodeGenerator http://latebindingapi.codeplex.com the tool creates c# projects from COM Type libraries. the generated projects includes mapper objects with latebind accessing the COM Server. the highlight is the tool converts COM type libs in different versions to one single project(for example excel 9,10,11) and marked all entities with an self defined SupportByLibrary Attribut. i have analyzed all office apps in version 9,10,11,12,14 with this this tool now and generate a c# solution, its available as tested beta with sample code on main page.

于 2011-04-28T12:35:53.840 回答