如何在 VBA 中将字符串作为命令运行

问题描述 投票:0回答:4

我下面有这个简单的 VBA 代码,但我不知道为什么不起作用。

Sub Run()
    test = "MsgBox" & """" & "Job Done!" & """"
    Application.Run test     
End Sub

我想做的是将 VBA 命令作为文本放入变量中,然后将其作为命令运行。在这种情况下,我想像

MsgBox "Job Done!"
一样运行并打印:

工作完成!

excel vba variables command eval
4个回答
9
投票

您可能会被添加自己的字符串“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

1
投票

简短的回答是,你不能那样做(你不应该那样做)但是......阅读以下内容以找出原因并找到解决方法!

如您所知,您是在编译器中编写代码。你想要做的是将人类可读的文本行作为命令运行,这是不可能的。当您运行程序时,所有程序都被编译为机器语言。当您将那行文本传递给它时,它无法将其识别为命令,您最终会收到错误消息。你可以做的是向它传递参数:

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 上也有同样的问题,但我找不到。如果找到它,我会把它作为参考。

附言这两个帖子可能有助于找到答案:

Access VBA - 使用字符串参数评估函数

Excel VBA - 如何将字符串作为一行代码运行

另一个解决方案

这个需要信任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

1
投票

如果你需要一个不需要特殊权限的解决方案,并且比硬编码代码更强大,我维护了一个库,

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,但它本身就是一种完全嵌入式的编程语言。有关详细信息,请参阅文档


-2
投票

我遇到了类似的变化:宏名称在“控制规范”工作表中。在功能区 XML 中添加了带有“onAction”参数的自定义功能区。 “标记”名称在功能区回调宏中返回,然后用于查找要根据 XML 标记名称运行的宏名称。到目前为止是有道理的!我已经在现有代码模块 = [m0_RibbonCallBack] 中处理了子程序。在 [m0_RibbonCallBack] 模块中,当我单击带有 tagName=[Reset2CellA2] 的功能区按钮时,我想运行子名称=[mResetToCellA2]。在“控制规范”工作表中,我在标记名=[Reset2CellA2] 上执行了 vLookUp() 并从第 3 列 (onAction) ="mResetToCellA2" 返回了字符串值。现在我需要在 VBA 端运行宏字符串 (macroName) 名称!!! 我最终用这条简单的线解决了这个挑战: 应用程序。运行“m0_RibbonCallBack”。 &宏名称
干杯!

© www.soinside.com 2019 - 2024. All rights reserved.