【问题标题】:How to get CustomDocumentProperties using Excel Interop?如何使用 Excel 互操作获取 CustomDocumentProperties?
【发布时间】:2015-03-11 08:29:10
【问题描述】:

以下代码用于获取 Excel 工作簿的自定义文档属性。

var xlApp = Globals.ThisAddIn.Application; // This works in VSTO Excel Add-in
var xlApp = new global::Microsoft.Office.Interop.Excel.Application(); // This doesn't work anywhere
xlApp.Visible = true;
global::Microsoft.Office.Interop.Excel.Workbook workbook = xlApp.Workbooks.Open(file, false, true, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, false, Type.Missing, Type.Missing);

global::Microsoft.Office.Core.DocumentProperties properties = workbook.CustomDocumentProperties; // Exception occurs here
global::Microsoft.Office.Core.DocumentProperty property = properties["propertyname"];

前 2 行是对 Excel Application 的引用。一种是从 VSTO 插件内部获取引用,另一种是常规的new Application()

使用 VSTO 内部的 Application 时,代码运行良好,没有任何问题。但是当使用new Application() 时,workbook.CustomDocumentProperties 行会抛出InvalidCastException

无法将“System.__ComObject”类型的 COM 对象转换为接口 键入“Microsoft.Office.Core.DocumentProperties”。此操作失败 因为接口的 COM 组件上的 QueryInterface 调用 IID 为“{2DF8D04D-5BFA-101B-BDE5-00AA0044DE52}”失败,原因是 以下错误:不支持此类接口(来自 HRESULT 的异常: 0x80004002 (E_NOINTERFACE))。

我试图让它在没有 VSTO 的 C# winforms 项目上工作。很多示例和教程使用new Application() 进行Excel 互操作,但我注意到Microsoft.Office.Interop.Excel.Application 是一个接口,所以在接口上使用new 对我来说其实很奇怪。如何创建可以获取CustomDocumentProperties 的适当应用程序?

我正在使用的参考程序集:

  • Microsoft.Office.Interop.Excel v2.0.50727 版本 14.0.0.0
  • Microsoft.CSharp v4.0.30319 版本 4.0.0.0

【问题讨论】:

    标签: c# excel interop vsto


    【解决方案1】:

    我注意到 Microsoft.Office.Interop.Excel.Application 是一个接口,所以在接口上使用 new 对我来说其实很奇怪。

    这确实很奇怪,但这是设计使然。 Excel.Application 接口装饰有CoClass 属性,告诉实际类在“实例化”接口时实例化。更多相关信息here

    但是当使用new Application() 时,workbook.CustomDocumentProperties 行会抛出InvalidCastException

    确实又奇怪了。我自己在使用文档属性时遇到了一些问题。似乎返回的实际类与规范不同,所以我转而使用dynamic 以防止类型转换问题。

    所以不要这样:

    Microsoft.Office.Core.DocumentProperties properties = workbook.CustomDocumentProperties;
    

    用途:

    dynamic properties = workbook.CustomDocumentProperties;
    

    【讨论】:

    • DocumentPropertiesDocumentProperty 都更改为动态确实有效!但不确定依赖dynamic 是否是一个好习惯?有没有办法确保代码正在处理的类型正确,以防止进一步可能出现的运行时问题?
    • 据我所知没有。实际上,出于这个确切原因,很多互操作类都使用dynamic
    【解决方案2】:

    如何创建一个可以获取 CustomDocumentProperties 的适当应用程序?

    如果您开发插件,则无需创建新的 Excel 应用程序实例。您应该使用 VSTO 运行时提供的 Application 属性:

    var xlApp = Globals.ThisAddIn.Application; // This works in VSTO Excel Add-in
    

    但是,如果您开发了一个自动化 Excel 的独立应用程序,在这种情况下,您需要使用 new 运算符创建一个新的应用程序实例:

    var xlApp = new global::Microsoft.Office.Interop.Excel.Application(); 
    

    按照How To Use Automation to Get and to Set Office Document Properties with Visual C# .NET 文章的建议,使用后期绑定技术 (Type.InvokeMember) 获取或设置文档属性。

    【讨论】:

      【解决方案3】:

      我也遇到了同样的问题。今天已经解决了。有一种不同的方法可以得出结果。问题及其答案在

      How can I read excel custom document property using c# excel interop

      这是我的实现。

      public string CheckDocProp(string propName, object props)
              {
                  Excel.Workbook workBk = Globals.ThisAddIn.Application.ActiveWorkbook;
      
                  object customProperties = workBk.CustomDocumentProperties;
                  Type docPropsType = customProperties.GetType();
                  object nrProps;
                  object itemProp = null;
                  object oPropName;
                  object oPropVal = null;
      
                  nrProps = docPropsType.InvokeMember("Count",
                      BindingFlags.GetProperty | BindingFlags.Default,
                      null, props, new object[] { });
                  int iProps = (int)nrProps;
      
                  for (int counter = 1; counter <= ((int)nrProps); counter++)
                  {
                      itemProp = docPropsType.InvokeMember("Item",
                          BindingFlags.GetProperty | BindingFlags.Default,
                          null, props, new object[] { counter });
      
                      oPropName = docPropsType.InvokeMember("Name",
                          BindingFlags.GetProperty | BindingFlags.Default,
                          null, itemProp, new object[] { });
      
                      if (propName == oPropName.ToString())
                      {
                          oPropVal = docPropsType.InvokeMember("Value",
                              BindingFlags.GetProperty | BindingFlags.Default,
                              null, itemProp, new object[] { });
                          return oPropVal.ToString();
                          break;
                      }
                      else
                      {
                          return "Not Found.";
                      }
                  }
                  return "Not Found.";
              }
      

      用法:

      object docProps = wb.CustomDocumentProperties;
                  string prop1 = ExistsDocProp("<CustomProperty>", docProps);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-27
        • 1970-01-01
        • 2010-10-25
        • 1970-01-01
        • 2015-08-29
        • 1970-01-01
        • 1970-01-01
        • 2010-10-25
        相关资源
        最近更新 更多