我下面有这个简单的 VBA 代码,但我不知道为什么不起作用。
Sub Run()
test = "MsgBox" & """" & "Job Done!" & """"
Application.Run test
End Sub
我想做的是将 VBA 命令作为文本放入变量中,然后将其作为命令运行。在这种情况下,我想像
MsgBox "Job Done!"
一样运行并打印:
工作完成!
您可能会被添加自己的字符串“Executer”所诱惑:
Sub StringExecute(s As String)
Dim vbComp As Object
Set vbComp = ThisWorkbook.VBProject.VBComponents.Add(1)
vbComp.CodeModule.AddFromString "Sub foo()" & vbCrLf & s & vbCrLf & "End Sub"
Application.Run vbComp.name & ".foo"
ThisWorkbook.VBProject.VBComponents.Remove vbComp
End Sub
Sub Testing()
StringExecute "MsgBox" & """" & "Job Done!" & """"
End Sub
简短的回答是,你不能那样做(你不应该那样做)但是......阅读以下内容以找出原因并找到解决方法!
如您所知,您是在编译器中编写代码。你想要做的是将人类可读的文本行作为命令运行,这是不可能的。当您运行程序时,所有程序都被编译为机器语言。当您将那行文本传递给它时,它无法将其识别为命令,您最终会收到错误消息。你可以做的是向它传递参数:
Sub Run()
test = "Job Done"
MsgBox(test)
End Sub
您还可以运行一个可执行文件,它可以在
macro
中编写为文本文件,然后在相同的 Sub
中运行(需要处理扩展名)。
如果你不能改变变量(即
test
)那么你需要采取另一种方法来解决它。我会建议提取可以传递给函数的参数并使用它。像下面这样的东西;
Sub Run()
test = "MsgBox" & """" & "Job Done!" & """"
extest = Right(test, Len(test) - 7)
MsgBox (extest)
End Sub
我相信在 SO 上也有同样的问题,但我找不到。如果找到它,我会把它作为参考。
附言这两个帖子可能有助于找到答案:
另一个解决方案
这个需要信任VB工程。引用 ExcelForum 并参考 Programmatic Access To Visual Basic Project Is Not Trusted - Excel
引用:
将启用宏的工作簿放在您可以指定的文件夹中 作为宏观友好。
然后打开工作簿。
Click on the Office Button -> Excel Options ->
Trust Center -> Trust Center Setting -> Trusted Locations.
然后将您的文件夹(您拥有启用 Excel 宏的工作簿的位置)添加为 受信任的位置。
你还需要这样做:
File -> Options -> Trust Center -> Trust Center Setting -> Macro Setting ->
Check the box beside "Trust access to the VBA project object model"
关闭并重新打开您的工作簿。
那些使用你的宏的人应该经过同样的步骤。
取消引用。
然后你可以使用我从 VBA - 在 Excel 中将字符串作为命令执行(未测试)
Sub test()
Set VBComp = ThisWorkbook.VBProject.VBComponents.Add(vbext_ct_StdModule)
VBComp.Name = "NewModule"
Set VBCodeMod = ThisWorkbook.VBProject.VBComponents("NewModule").CodeModule
Dim test As String
test = "MsgBox " & """" & "Job Done!" & """"
With VBCodeMod
LineNum = .CountOfLines + 1
.InsertLines LineNum, _
"Sub MyNewProcedure()" & Chr(13) & test & Chr(13) & "End Sub"
End With
'run the new module
Application.Run "MyNewProcedure"
UserForm1.Show
'Delete the created module
ThisWorkbook.VBProject.VBComponents.Remove VBComp
End Sub
@A.S.H 回答做了最后一个解决方案打算实现的事情。为了完整起见,我将其包含在这里。大家可以参考原答案点个赞
Public Sub StringExecute(s As String)
Dim vbComp As Object
Set vbComp = ThisWorkbook.VBProject.VBComponents.Add(1)
vbComp.CodeModule.AddFromString "Sub foo" & vbCrLf & s & vbCrLf & "End Sub"
Application.Run vbComp.name & ".foo"
ThisWorkbook.VBProject.VBComponents.Remove vbComp
End Sub
Sub Testing()
StringExecute "MsgBox" & """" & "Job Done!" & """"
End Sub
如果你需要一个不需要特殊权限的解决方案,并且比硬编码代码更强大,我维护了一个库,
stdLambda
来自 stdVBA
,用于这种事情:
'Ensure module name is "mainModule"
Public Sub Main()
Call stdLambda.bindGlobal("msgbox", stdCallback.CreateFromModule("mainModule","msgbox"))
x = stdLambda.Create("msgbox(""hello world"")").Run()
End Sub
Public Function msgbox(ByVal sMessage as string) as long
msgbox = VBA.msgbox(sMessage)
End Function
stdLambda
语法类似于 vba,但它本身就是一种完全嵌入式的编程语言。有关详细信息,请参阅文档。
我遇到了类似的变化:宏名称在“控制规范”工作表中。在功能区 XML 中添加了带有“onAction”参数的自定义功能区。 “标记”名称在功能区回调宏中返回,然后用于查找要根据 XML 标记名称运行的宏名称。到目前为止是有道理的!我已经在现有代码模块 = [m0_RibbonCallBack] 中处理了子程序。在 [m0_RibbonCallBack] 模块中,当我单击带有 tagName=[Reset2CellA2] 的功能区按钮时,我想运行子名称=[mResetToCellA2]。在“控制规范”工作表中,我在标记名=[Reset2CellA2] 上执行了 vLookUp() 并从第 3 列 (onAction) ="mResetToCellA2" 返回了字符串值。现在我需要在 VBA 端运行宏字符串 (macroName) 名称!!!
我最终用这条简单的线解决了这个挑战:
应用程序。运行“m0_RibbonCallBack”。 &宏名称
干杯!