【问题标题】:Can't run macro via interop if it's in a worksheet?如果它在工作表中,则无法通过互操作运行宏?
【发布时间】:2016-02-22 05:58:40
【问题描述】:

我正在使用以下代码通过 C# Excel 互操作运行 VBA 宏:

public void macroTest()
    {
        Excel.Application xlApp = new Excel.Application();
        xlApp.Visible = true;
        string bkPath = @"C:\somePath\someBk.xlsm";
        Excel.Workbook bk = xlApp.Workbooks.Open(bkPath);
        string bkName = bk.Name;
        string macroName = "testThisMacro_m";
        string runString = "'" + bkName + "'!"+macroName;
        xlApp.Run(runString);
        bk.Close(false);
        xlApp.Quit();
    }

testThisMacro_m 在模块testMacro 中,并且运行成功。当我将其替换为:

string macroName = "testThisMacro_s";

如果testThisMacro_s 的代码在Sheet1 中,xlApp.Run() 行会给出以下 COM 异常:

Cannot run the macro ''someBk.xlsm'!testThisMacro_s'. 
The macro may not be available in this workbook or all macros may be disabled.

我检查了宏安全设置,它们确实设置为“通过通知禁用”,但能够从模块而不是工作表运行宏似乎表明这是与应用程序级宏不同的问题安全。

在对工作表中的宏进行互操作调用时,我需要做些什么不同的事情吗?

更新:我能够通过将调用更改为来执行宏:

string macroName = "Sheet1.testThisMacro_s"

但似乎在宏完成之前这个手控制回到了 C#,所以现在我需要弄清楚如何检查宏完成(可能是一个不同的问题)。

【问题讨论】:

  • 是的,您的更新中有不同的问题。将您的发现写为“答案”,标记它以关闭线程,然后写一个新问题。

标签: c# vba excel office-interop


【解决方案1】:

Worksheet 对象是一个对象 - 对象是用类模块 定义的。工作表、工作簿、用户表格;他们都是对象。如果您没有该对象的 instance,则不能只调用该对象的方法。

宏处理标准模块,它们不是对象,不需要实例化。

Application.Run 不能调用 对象 的方法,这就是宏需要在标准模块中的原因。

【讨论】:

  • 我可以通过调用 Sheet1.testThisMacro_s 让它运行,但现在我需要弄清楚如何检测宏何时完成(请参阅我的 OP 更新)。
  • AFAIK,你不能。如果你弄清楚了,我很想知道,我的Rubberduck 项目的单元测试功能绝对可以使用它!有趣的是,你可以给它工作表名称,我认为它可以工作,因为 Sheet1 是工作表的 CodeName,因此指的是实际的对象实例。
  • @Mat'sMug 哦,但似乎可以,但仅适用于文档类型模块!调用 Application.Run "Sheet1.Foo"Application.Run "ThisWorkbook.Foo" 或(在 Word 中)Application.Run "ThisDocument.Foo" 都可以。不幸的是,它不适用于预先声明的类模块,无论该类是否为 PublicNotCreatable。
【解决方案2】:

我能够通过将调用更改为来执行宏:

string macroName = "Sheet1.testThisMacro_s"

【讨论】:

    【解决方案3】:

    一个助手子不会解决你的两个问题吗,回复:Mat's Mug 关于实例化的回复?

    在一些标准模块中:

    Sub testHelperSubToBeCalledFromInterop
        Call Sheet1.testThisMacro_s
    End Sub
    

    编辑:

    【讨论】:

    • 这是针对许多具有相同模板的工作簿运行的,因此它们都需要相应地更新其代码。最好找到只涉及修改 C# 代码的解决方案。
    • Sheet1 像这样使用一个对象实例:工作表和用户窗体是类模块,它们的VB_PredeclaredId 属性设置为True,这使得 VBA 创建一个全局以类型命名的对象实例(如here 所述)。
    • @Mat'sMug:我认为问题仅限于找到入口点。您说Application.Run 不能调用对象的方法,我不反对,但我将其解释为Application.Run 可以 在标准模块中运行方法。因此,如果您有一个带有指向工作表的宏的标准模块......这不能解决问题吗?把截图放在我的帖子里。它似乎在 Excel 中“本地”工作,难道它也可以与互操作一起工作吗?
    • @Vegard 是的。这正是Rubberduck 单元测试的工作原理 =)
    • @Mat'sMug 哦,在那种情况下,我的错。我的印象是你在反驳我的解决方案。很高兴我们同意!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-12
    • 2014-11-03
    • 2012-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多