8

我正在使用 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 似乎不支持这一点,所以我很好奇是否有人有任何替代方法来实现这一点?

4

3 回答 3

11

我知道将代码插入 VBA 项目的唯一方法是Office.Interop.ExcelMicrosoft.Vbe.Interop不确定 ClosedXML 和其他第 3 方......但仍然想分享)一起使用

但是,既然您要寻求替代方案,这就是我的工作方式;

Creating a workbook and inserting a macro to it using C#


您需要允许以编程方式访问Excel 中的 VBA 项目。

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

在此处输入图像描述

在您的 C# 解决方案中,将 COM 引用添加到

  • Microsoft Visual Basic 应用程序扩展性 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")只需调用宏 - 请注意,如果您不希望该框弹出,则可以注释掉此部分。然后最后将工作簿作为启用宏fullPath的工作簿保存到变量中指定的位置。

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

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

于 2014-04-08T12:56:28.057 回答
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”文件夹下,并且工作簿将需要代号 GUID 和别名(默认为“ThisWorkbook”)。所有工作表还需要一个代号(与工作表名称匹配),以便在引用命名工作表时宏中的调用实际工作。

John McNamara 在 Perl 中创建了一个可行的概念验证,值得在这里查看

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

于 2014-04-07T14:30:17.223 回答
1
return File(stream, @"application/vnd.ms-excel.sheet.macroEnabled.12", "MySS.xlsm");

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

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

您是否在 ClosedXml codeplex 项目上看到有关宏支持的这篇文章。

于 2014-04-04T23:45:37.067 回答