【问题标题】:Does C# .NET support IDispatch late binding?C# .NET 是否支持 IDispatch 后期绑定?
【发布时间】:2010-09-29 00:40:20
【问题描述】:

问题

我的问题是: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。当然,如果真的你想使用对象,你就得调用有某种调用方式的方法。

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

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

一些示例代码可能是:

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# late-binding idispatch


【解决方案1】:

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

【讨论】:

  • 嗯...链接到 MSDN 页面的 C# 中的示例已经...?不管怎样,谢谢你的信息。我确信我可以找到这种后期绑定方法的用途。
  • 这会产生一些非常丑陋的代码,但至少它可以工作:)
  • 非常棒!我已经“打破”了我的脑袋,想着解决我的类似问题,但你救了我的命。 :) 真的行! :) 谢谢! :)
  • @IanBoyd Activator.CreateInstance() 方法是创建一个新的 Excel 窗口还是连接到现有的?
【解决方案2】:

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

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

【讨论】:

  • 这是解决这个问题的好方法。我通常在 C# 中使用具有强类型和 COM 接口的适配器项目 - 我发现它更防错。
【解决方案3】:

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

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

【讨论】:

  • 嗯,CTP,但同样的区别。
【解决方案4】:

正如其他人所说 - 使用 c#4 的“动态”关键字 Rocks。这是一个简单的例子——它比使用“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"
}

【讨论】:

  • 我仍然感到难过的是,微软花了十年时间才完成了竞争对手在 1999 年所做的事情。话虽如此:我仍然必须支持 .NET 2.0。
【解决方案5】:

如果您花时间编写接口,您可能会在 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 中挖掘什么。

【讨论】:

  • 你所拥有的是early binding,这与late binding完全相反。
  • 哦,有些 COM 对象只公开两个接口:IUnknownIDispatch
【解决方案6】:

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

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

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

【讨论】:

    猜你喜欢
    • 2010-09-28
    • 2021-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多