在Excel中隐藏用户的宏但仍然通过按钮调用?

use*_*245 2 excel vba excel-vba

我有一份电子表格,将分发给同事; 我希望尽可能使用户友好,所以为了运行宏,我有一个简单的按钮,可以自动完成所有内容.但是我不希望他们有权自己运行任何宏.

我已经成功地使用了这个

Option Private Module
Public Sub Run_Batch_Report()
'The actual script that works is here, cutting it to skip to the portion that won't work'
Call Misc_Doc
MsgBox ("Report finished.")
End Sub
Run Code Online (Sandbox Code Playgroud)

Public Sub Misc_Doc()所做的就是从另一个电子表格导入数据并对其进行格式化.

然后让命令按钮通过application.run调用模块

Private Sub CommandButton1_Click()
Application.Run "Batching_Module.Run_Batch_Report"
End Sub
Run Code Online (Sandbox Code Playgroud)

这样做那种工作的; 因为它似乎运行Run_Batch_Report子只是很好,但该子也调用同一模块中的其他子来完成作业.这些子程序将无法运行除非我在开​​发人员选项中解锁VB以进行查看和编辑.是否可以完整地运行子运行(包括在同一模块中调用其他子组件),或者我是否必须重构我的子组件以包含它所调用的所有其他子组件?

对不起,如果我随意措辞 - 我实际上正在开会,并在听老板的同时玩杂耍.

编辑:为了澄清,我已经锁定VB被查看.当我在脚本仍处于锁定状态时运行脚本时,它将不允许子调用该模块的其他部分.输入密码以解锁VB以供查看后,它就能正常工作.

Mat*_*don 6

假设"但我不想让他们有机会获得运行任何自己的宏的"代表"我不想宏在'宏’窗口中列出",你已经有了.

我无法重现你的"宏不会运行,除非项目解锁"问题,无论Application.Run是否涉及,不确定是什么.在任何情况下,您似乎都错误地认为密码保护您的项目会给它带来任何安全性.它没有.

VBA代码不安全.VBA项目密码保护实际上是一个笑话,它只会惹恼开发者(你!)并防止那些不知道如何处理VBE的无能用户,无论如何都要查看他们不理解的源代码 - 以及是否有人想要看到代码,相信我,他们会在几秒钟内完成.

如果有人可以打开主机文档,他们可以访问VBA代码.

用户可以运行宏,也可以不运行宏.如果用户可以单击按钮来调用某些VBA代码,则他们有权从任何地方调用该VBA代码.

将您的"隐藏"宏放在标准模块(.bas)中并Option Private Module指定:

Option Private Module
Option Explicit

Public Sub SomeHiddenMacro()
    MsgBox "Hi"
End Sub
Run Code Online (Sandbox Code Playgroud)

然后你仍然可以通过输入宏的名称(它不会被列出,因为)来将宏分配给某个形状Option Private Module:

Excel的

单击按钮,看到它的工作原理:

消息框出现

形状可以格式化为比任何ActiveX按钮更漂亮:

它不需要比这更复杂.


优雅的解决方案

你是从VBA开始的,所以我认为你还没有玩过类模块.类模块的一个好处是它们的公共成员不能被调用为宏,因为类模块在运行时不存在 - 它们是类型,而不是模块.对于一个类型来表示任何东西,它需要被实例化 - 而宏运行器不会这样做.

所以把"worker"代码放在一个类模块中,比如说BatchReport:

Option Explicit

Public Sub Run()
    'TODO: do your thing
End Sub
Run Code Online (Sandbox Code Playgroud)

现在在附加到按钮(或ActiveX按钮的Click处理程序)的宏中,您所做的就是使用New关键字创建该对象的实例,并调用其Run方法:

Option Private Module
Option Explicit

Public Sub RunBatchReport()
    With New BatchReport
        .Run
    End With
End Sub    
Run Code Online (Sandbox Code Playgroud)

在这里,我有一个With块保持对象引用.或者,您可以声明一个对象变量,并Set引用该类的New实例BatchReport:

Option Private Module
Option Explicit

Public Sub RunBatchReport()
    Dim report As BatchReport
    Set report = New BatchReport
    report.Run
End Sub    
Run Code Online (Sandbox Code Playgroud)