动态加载Excel的所有COM类型?

3

我希望能够动态地使用Excel。


我想在我的C#应用程序中使用Excel,而不需要包括dll等文件。我只需先检查所需的Excel版本是否已安装并运行它。

首先,我想获取所有需要的类型,但我无法获得它们:

// works
Type typeExcel = Type.GetTypeFromProgID("Excel.Application");
object excel = Activator.CreateInstance(typeExcel);
object workbooks = typeExcel.InvokeMember("Workbooks", BindingFlags.GetProperty, null, excel, null);

// this doesn't work, returns null
Type typeWorkbooks = Type.GetTypeFromProgID("Excel.Workbooks");

如果我没有正确的类型,我就无法调用成员。那么我做错了什么?我该如何加载我需要的所有类型并确保它们存在?我的当前Excel版本是2003。


造成这种情况的原因:如果我包含在目标系统上未安装的COM库,我的应用程序将无法启动。如果我动态加载它们,我可以检查它们的存在并通知用户缺少的功能。


你到底想要实现什么目标?如果你想依赖于Interop(因此不需要使用DLL,但需要将给定的引用添加到你的项目中,并针对特定的Office版本进行开发),那么你不需要这样做。这里有一个入门指南:http://support.microsoft.com/kb/302084/en-us - varocarbas
请注意,Office 2003相当古老,具有“某些特殊性”。例如,在您想要使用应用程序的计算机上必须安装“可再分发的主要Interop程序集”(http://www.microsoft.com/en-us/download/details.aspx?id=20923)。这也适用于Office 2007(其特定包);但自Office 2010以来不再需要。 - varocarbas
@varocarbas 我稍后会问我的老板是否可以使用Office 2010。但现在我只能使用2003版。 - Bitterblue
好的。这些是“经典”的Interop规则。显然,GSerg提出了一些替代方案(适合您原始代码中编写的内容),我对此并不太确定。 - varocarbas
我已经编辑了你的标题。请查看“问题标题应该包含“标签”吗?”,那里的共识是“不应该包含”。 - John Saunders
通常情况下,您需要添加对给定COM(Excel)对象的引用,该对象是安装在构建应用程序的计算机上的Office版本之一。这使您可以完全访问给定的Interop命名空间(Microsoft.Office.Interop.Excel)。正如所说,此Interop部分也必须安装在目标计算机上(可重新分发至2007版或自动安装在Office以后)。您提出的是跳过所有这些步骤,直接访问给定计算机中的Excel版本。从未尝试过,因此不知道其实际可靠性。 - varocarbas
2个回答

7
使用 dynamic
Type typeExcel = Type.GetTypeFromProgID("Excel.Application");

dynamic excel = Activator.CreateInstance(typeExcel);
excel.Visible = true;

dynamic workbooks = excel.Workbooks;
workbooks.Add();
workbooks.Add();

也可以查看这个答案

@varocarbas dynamicC#特性 - GSerg
感谢您的澄清,非常有教育意义。虽然仍不确定所有这些内容对办公室/互操作性的确切适用性,但无论如何都很有趣。 - varocarbas
你能提供更多的代码来设置实际单元格吗?有一些方法缺失,比如workbook.get_Item(...)sheet.get_Range(...) - Bitterblue
@mini-me 我担心你并没有明白你所请求的是什么:你正在询问aformentioned Interop命名空间包含什么;要访问它,您需要按照我通过评论解释的步骤进行。动态(如上面的链接中完美解释)就像“Object”一样,也就是说,它不知道给定内容(方法、属性等)。除此之外,我从未测试过这种方法,因此我甚至不确定它的实际可靠性和版本兼容性。 - varocarbas
我向GSerg提出了问题。如果你误解了我的意思,我很抱歉。但是我已经修复了它,并且按照GSerg建议的方式成功通过了测试。请看上面我不想在设计时包含库的原因。 - Bitterblue
显示剩余2条评论

2
如果我包含了目标系统未安装的COM库,我的应用程序将无法启动。
你正在寻找的解决方法比问题本身更糟糕。在你尝试使用片段中所述的方式进行Office代码的后期绑定时,并不会有任何美好之处。C# 4.0版本中支持的dynamic关键字确实使语法更加友好。但是,在编写代码时它并不友好,你将无法获得任何智能提示。而且在运行时也并不友好,你在编码时犯的错误将导致异常,并且后期绑定具有相当大的开销。
有一些简单的对策可以确保Interop程序集可用:
- 要求用户安装Office主要Interop程序集(PIA)。 - 实际上只有在你在自己的公共方法中公开Office类型并在另一个程序集中使用它时才需要PIA,这种情况很少发生。在引用节点中选择Microsoft.Office.Interop程序集,并将其复制到本地属性设置为true。重新构建,你将在构建目录中获得这些程序集。将它们与你自己的可执行文件一起复制到客户端机器上。 - VS2010及以上版本具有这个部署细节的黄金解决方案。在引用节点中选择interop程序集,并将Embed Interop Types属性设置为True。interop声明现在将合并到你自己的可执行文件中,你无需再部署interop程序集或PIA了。
由于你接受了VS2010及以上版本提供的dynamic解决方案,因此最后一个对策是你想要的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接