C#.NET是否支持IDispatch后期绑定?

时间:2008-12-31 15:33:17

标签: c# late-binding idispatch


问题

我的问题是: 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。当然,如果确实你想要使用该对象,你必须调用一些方法来调用方法。

我们可以获取各种接口声明,并将其翻译成我们的语言。这项技术很好,因为我们得到了

  • 早期绑定
  • 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。除了通过IDispatch之外,某些COM对象没有其他支持。

6 个答案:

答案 0 :(得分:25)

相反,您可以在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 );

答案 1 :(得分:9)

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

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

答案 2 :(得分:5)

C#4的dynamic关键字支持IDispatch和后期绑定。你可以阅读Sam Ng的dynamic series了解更多信息

哦,C#4今天只作为CTP提供。您必须等待Visual Studio vNext或使用beta(在Windows Server 2008 Virtual PC上运行)才能使用它。

答案 3 :(得分: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中挖掘的内容。

答案 4 :(得分:2)

正如其他人所说 - 使用c#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 :(得分:1)

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

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

第二个是CodeGenerator http://latebindingapi.codeplex.com 该工具从COM Type库创建c#项目。 生成的项目包括具有后端访问COM服务器的映射器对象。 重点是该工具将不同版本的COM类型库转换为单个项目(例如excel 9,10,11),并使用自定义的SupportByLibrary Attribut标记所有实体。我已经使用此工具分析了版本9,10,11,12,14中的所有办公应用程序并生成了一个c#解决方案,它在主页上带有示例代码的测试版。

相关问题