运行 另一个工作簿上的 Excel 宏

Running an Excel macro on a different workbook

我正在尝试 运行 一个工作簿中的 VBA 宏到另一个工作簿。
我正在使用 Microsoft.Office.Interop.Excel(或等效)对象(如果您想使用它,请添加对 Microsoft Excel 12.0 对象库的引用 (COM))来编辑和使用来自 Excel 的文档C# 可执行文件。

例如,文档一中有一些数据。文档二包含用于格式化文档一的宏。文件一每天都是新的,所以我不能把宏放在那里。我正在尝试 运行 使用 Excel.Application.Run().

文档一上文档二的宏

我使用的示例宏很简单(存储在 Microsoft Excel 对象中:ThisWorkbook):

Sub Test()
  Sheets("Sheet1").Select
  Range("A1").Value = 32
End Sub

我需要这个 运行 在不同的工作簿上。我可以 运行 使用以下代码在同一个工作簿上:

Application xlApp = new Application(); //Excel app
Workbook xlWbk = null;
try
{
  xlWbk = xlApp.Workbooks.Open(DocumentTwoLocation);
  xlApp.Run("'" + DocumentTwoLocation + "'!" + MacroName); //MacroName example: ThisWorkbook.Test
}
finally
{
  if (xlWbk != null)
    try
    {
      xlWbk.Close(true); //Saves changes
    }
    catch
    {
      xlWbk.Close(false);
    }
  xlApp.Quit();
}

当我将 xlApp.Workbooks.Open 中的 DocumentTwoLocation 更改为 DocumentOneLocation 时,宏不会 运行。抛出 COMException (HRESULT: 0x800A03EC),这是 NameNotFound(仅在使用 xlApp.Run() 时抛出)。文件地址是正确的。即使我像这样预先打开两个文档:

Application xlApp = new Application(); //Excel app
Workbook xlWbk = null;
Workbook xlMacroBook = null;
try
{
  xlWbk = xlApp.Workbooks.Open(DocumentOneLocation);
  xlMacroBook = xlApp.Workbooks.Open(DocumentTwoLocation);
  xlApp.Run("'" + DocumentTwoLocation + "'!" + MacroName); //MacroName example: ThisWorkbook.Test
}
finally
{
  if (xlWbk != null)
    try
    {
      xlWbk.Close(true); //Saves changes
    }
    catch
    {
      xlWbk.Close(false);
    }
  if (xlMacroBook != null)
    xlMacroBook.Close(false) //Don't save changes
  xlApp.Quit();
}

错误仍然发生(相同的 0x800A03EC 异常)。

MSDN 几乎没有关于我遗漏了什么或我应该如何处理这个问题的文档 (https://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.applicationclass.run.aspx)

这里有人问过类似的问题: Error when calling Excel macro from C# 我已尽我所能来匹配他们所写的内容(包括添加 ReleaseComObject,然后设置为 null)但无济于事。

我已经解决了这个问题。

出现此问题的原因是试图 运行 在另一个文档上设置 "xlsm" 格式宏。 运行 另一个工作簿上的宏仅适用于 Microsoft Office Excel 二进制工作表(xlsb 格式)。如果您遇到同样的问题 - 使用 xlsb 来保存宏,而不是 xlsm。

感兴趣的小伙伴,最终代码如下:

/// <summary>
/// Run a macro from an xlsb file on another excel file
/// </summary>
/// <param name="ExcelFile">The excel file to run the macro on</param>
/// <param name="MacroFileLocation">The xlsb file the macro is saved in</m>
/// <param name="Macro">The macro name to run (e.g. Module1.Example)</param>
static void Test(string ExcelFile, string MacroFileLocation, string Macro)
{
    Application xlApp = new Application(); //Excel app
    Workbook xlWbk = null;
    try
    {
        xlWbk = xlApp.Workbooks.Open(ExcelFile);

        string MacroCommand = "'" + MacroFileLocation + "'!" + Macro;
        xlApp.Run(MacroCommand);
    }
    finally
    {
        //Clean up
        if (xlWbk != null)
            try
            {
                xlWbk.Close(true);
            }
            catch
            {
                //Couldn't save - consider alerting user
                xlWbk.Close(false);
            }
        xlApp.Quit();

        System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWbk);
        System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);

        xlWbk = null;
        xlApp = null;
    }
}