如何将一些VBA代码嵌入到使用ClosedXML创建的电子表格中?

时间:2014-04-01 13:06:09

标签: c# asp.net-mvc excel openxml closedxml

我使用ClosedXML从C#(asp.net-mvc)生成电子表格,效果很好。我有一个额外的要求,所以我希望得到一些关于如何实现这一目标的反馈。

我想保存为支持宏的工作簿,当我只是给它一个" xlsm"扩展它似乎没有打开(相对于xlsx)。这是我的代码:

public ActionResult ExportExcel()
{
    MemoryStream stream = nModel.GenerateSS();
    return File(stream, @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", "MySS.xlsx");
}

但如果我尝试这样做:

public ActionResult ExportExcel()
{
    MemoryStream stream = nModel.GenerateSS();
    return File(stream, @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", "MySS.xlsm");
}

Excel在尝试打开时抱怨。

然后,假设我可以做#1,我需要能够获取一些VBA(假设只是一个硬编码的函数)并将其插入到模块或工作簿中,所以当有人打开电子表格并单击宏时,他们可以运行宏。从谷歌搜索来看,这似乎并不支持ClosedXML所以我很好奇是否有人有任何其他方法可以实现这一目标?

3 个答案:

答案 0 :(得分:10)

我知道将代码插入VBA项目的唯一方法是使用Office.Interop.ExcelMicrosoft.Vbe.Interop不确定ClosedXML和其他第三方...但仍然,想要份额

但是既然你要求替代方案,那就是我要去做的事情;

<强> Creating a workbook and inserting a macro to it using C#


您需要在Excel中allow programmatic access to VBA Project

  • (Excel)文件 - &gt;选项 - &gt;信托中心 - &gt;信任中心设置 - &gt;宏设置 - &gt;信任对VBA项目对象模型的访问

enter image description here

在C#解决方案中添加COM引用

  • Microsoft Visual Basic for Applications Extensibility 5.3

  • Microsoft Excel 14.0对象库

将using指令添加到文件后面的C#代码

using Microsoft.Office.Interop.Excel;
using System.Reflection;
using Microsoft.Vbe.Interop;
using System.Runtime.InteropServices;

现在按照代码和评论

Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
xlApp.Visible = true;
Workbook wb = xlApp.Workbooks.Add(XlWBATemplate.xlWBATWorksheet);

VBProject vbProj = wb.VBProject; // access to VBAProject
VBComponent vbComp = vbProj.VBComponents.Add(vbext_ComponentType.vbext_ct_StdModule); // adding a standard coding module
vbComp.CodeModule.DeleteLines(1, vbComp.CodeModule.CountOfLines); //emptying it

// this is VBA code to add to the coding module
string code = "Public Sub HelloWorld() \n" +
                "    MsgBox \"hello world!\" \n" +
                "End Sub";

// code should be added to the module now
vbComp.CodeModule.AddFromString(code); 

// location to which you want to save the workbook - desktop in this case
string fullPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\macroWorkbook.xlsm";

// run the macro
xlApp.Run("HelloWorld");

// save as macro enabled workbook
wb.SaveAs(Filename: fullPath, FileFormat: XlFileFormat.xlOpenXMLWorkbookMacroEnabled);
xlApp.Quit();

在上面的代码中;

您创建一个主机Excel应用程序,添加一个工作簿。访问VBA项目对象模块,向VBA项目添加新的标准编码模块,将VBA宏写入该模块。 Application.Run("HelloWorld")只需调用宏 - 请注意,如果您不希望弹出框,则可以注释掉此部分。然后,最后将工作簿保存为 Macro Enabled Workbook fullPath变量中指定的位置。

PS。请注意,我没有添加任何错误处理。

有关C#和VBA的其他提示,请参阅this blog 希望这会有所帮助:)

答案 1 :(得分:3)

ClosedXML目前不支持直接编写VBA。

但是,您可以通过编程方式手动将包含预定义VBA宏/函数的.bin文件添加到现有的.XLSX电子表格中。事先写下所有VBA宏并将文件另存为.XLSM文件。将内容解压缩到一个文件夹,你将拥有一个包含所有代码的vbaProject.bin。要使VBA项目正确加载,workbook.xml需要以下添加:

<Default Extension="bin" ContentType="application/vnd.ms-office.vbaProject"/>
<Override PartName="/xl/workbook.xml" ContentType="application/vnd.ms-excel.sheet.macroEnabled.main+xml"/>

vbaProject.bin需要放在'xl'文件夹下,工作簿需要codeName GUID和别名(默认情况下为'ThisWorkbook')。所有工作表还需要一个codeName(与工作表名称匹配),以便在引用命名工作表时,宏中的调用实际上有效。

John McNamara在Perl中创建了一个值得查看here的工作概念验证。

在IlSpy中扫描程序集时,在ClosedXML中实现这一点应该相当简单,因此如果您在此处取得成功,那么将您的贡献推送到主项目是个好主意。

答案 2 :(得分:1)

return File(stream, @"application/vnd.ms-excel.sheet.macroEnabled.12", "MySS.xlsm");

根据此link,Office Excel 2007启用宏的工作簿(.xlms)的MIME类型为

application/vnd.ms-excel.sheet.macroEnabled.12

您是否在ClosedXml codeplex项目上看到有关支持宏的this帖子。