Office 2011 for Mac 中的 VBA Shell 函数

发布于 2024-11-09 13:14:48 字数 327 浏览 0 评论 0原文

我正在尝试从 Word 2011 for Mac 中的 VBA 宏启动 shell 脚本,该脚本将在终端窗口中运行。我尝试过使用 Shell 函数和 MacScript 函数,但 VBA 解释器似乎在这两种情况下都无法找到脚本。

根据 VBA 参考文档,以下内容应该有效:

 RetVal = Shell("Macintosh HD:Applications:Calculator.app", vbNormalFocus)

这会产生运行时错误 53“找不到文件”。

有什么建议吗?

I am trying to launch a shell script from a VBA macro in Word 2011 for Mac that will run in a Terminal window. I have tried using both the Shell function and the MacScript function, but the VBA interpreter doesn't seem to be able to find the script in either case.

According to the VBA reference documentation, the following should work:

 RetVal = Shell("Macintosh HD:Applications:Calculator.app", vbNormalFocus)

This produces a run-time error 53 'File not found'.

Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

小猫一只 2024-11-16 13:14:48

Mac 上的 Shell() VBA 函数似乎需要完整路径作为 HFS 样式路径(使用冒号而不是斜杠)。它似乎也不像 Windows 上那样接受参数(如果添加任何参数,则会报告“找不到路径”错误)。

还可以使用 MacScript() VBA 函数:MacScript("do shell script ""command""")。这可能是最简单的选择,也是我建议做的。缺点是它有相当大的开销(每次调用 100-200 毫秒)。

另一种替代方法是标准 C 库中的 system() 函数:

Private Declare Function system Lib "libc.dylib" (ByVal command As String) As Long

Sub RunSafari()
    Dim result As Long
    result = system("open -a Safari --args http://www.google.com")
    Debug.Print Str(result)
End Sub

请参阅 http://pubs.opengroup.org/onlinepubs/009604499/functions/system.html 查看文档。

system() 仅返回退出代码。如果您想获取命令的输出,可以使用popen()

Private Declare Function popen Lib "libc.dylib" (ByVal command As String, ByVal mode As String) As Long
Private Declare Function pclose Lib "libc.dylib" (ByVal file As Long) As Long
Private Declare Function fread Lib "libc.dylib" (ByVal outStr As String, ByVal size As Long, ByVal items As Long, ByVal stream As Long) As Long
Private Declare Function feof Lib "libc.dylib" (ByVal file As Long) As Long

Function execShell(command As String, Optional ByRef exitCode As Long) As String
    Dim file As Long
    file = popen(command, "r")

    If file = 0 Then
        Exit Function
    End If

    While feof(file) = 0
        Dim chunk As String
        Dim read As Long
        chunk = Space(50)
        read = fread(chunk, 1, Len(chunk) - 1, file)
        If read > 0 Then
            chunk = Left$(chunk, read)
            execShell = execShell & chunk
        End If
    Wend

    exitCode = pclose(file)
End Function

Sub RunTest()
    Dim result As String
    Dim exitCode As Long
    result = execShell("echo Hello World", exitCode)
    Debug.Print "Result: """ & result & """"
    Debug.Print "Exit Code: " & str(exitCode)
End Sub

请注意,上例中的几个 Long 参数是指针,因此如果发布了 64 位版本的 Mac Word,则必须对其进行更改。

The Shell() VBA function on Mac appears to require the full path as an HFS-style path (with colons instead of slashes). It also doesn't appear to accept arguments as it does on Windows (reporting a 'Path not found' error if any arguments are added).

The MacScript() VBA function can also be used: MacScript("do shell script ""command"""). This is likely to be the simplest option and what I would suggest doing. The downside is that it has quite a lot of overhead (100-200ms per call).

Another alternative is the system() function from the standard C library:

Private Declare Function system Lib "libc.dylib" (ByVal command As String) As Long

Sub RunSafari()
    Dim result As Long
    result = system("open -a Safari --args http://www.google.com")
    Debug.Print Str(result)
End Sub

See http://pubs.opengroup.org/onlinepubs/009604499/functions/system.html for documentation.

system() only returns the exit code. If you want to get the output from the command, you could use popen().

Private Declare Function popen Lib "libc.dylib" (ByVal command As String, ByVal mode As String) As Long
Private Declare Function pclose Lib "libc.dylib" (ByVal file As Long) As Long
Private Declare Function fread Lib "libc.dylib" (ByVal outStr As String, ByVal size As Long, ByVal items As Long, ByVal stream As Long) As Long
Private Declare Function feof Lib "libc.dylib" (ByVal file As Long) As Long

Function execShell(command As String, Optional ByRef exitCode As Long) As String
    Dim file As Long
    file = popen(command, "r")

    If file = 0 Then
        Exit Function
    End If

    While feof(file) = 0
        Dim chunk As String
        Dim read As Long
        chunk = Space(50)
        read = fread(chunk, 1, Len(chunk) - 1, file)
        If read > 0 Then
            chunk = Left$(chunk, read)
            execShell = execShell & chunk
        End If
    Wend

    exitCode = pclose(file)
End Function

Sub RunTest()
    Dim result As String
    Dim exitCode As Long
    result = execShell("echo Hello World", exitCode)
    Debug.Print "Result: """ & result & """"
    Debug.Print "Exit Code: " & str(exitCode)
End Sub

Note that several of the Long arguments in the above example are pointers, so will have to be changed if a 64bit version of Mac Word is ever released.

素衣风尘叹 2024-11-16 13:14:48

希望您现在已经找到答案,但您只需要完整路径:

RetVal = Shell("Macintosh HD:Applications:Calculator.app:" & _
              "Contents:MacOS:Calculator", vbNormalFocus)

另一个示例如下:

RetVal = Shell("Macintosh HD:Users:brownj:Documents:" & _
              "rnaseq:IGV_2.0.14:igv.sh", vbNormalFocus)

Hopefully you've found the answer by now but you just need the full path:

RetVal = Shell("Macintosh HD:Applications:Calculator.app:" & _
              "Contents:MacOS:Calculator", vbNormalFocus)

Another example is something like:

RetVal = Shell("Macintosh HD:Users:brownj:Documents:" & _
              "rnaseq:IGV_2.0.14:igv.sh", vbNormalFocus)
朦胧时间 2024-11-16 13:14:48

另一个问题完全是这样的:由于 AppleScript 环境和用户的 bash 环境之间的差异,权限会导致您的脚本失败。这个问答帮助我解决了这个问题。为了让我的脚本正常工作,我必须解决一些路径和权限问题(不是脚本本身,而是脚本涉及的内容)。

以下是我的建议,希望在您进行故障排除时能够比我在使用 AppleScript 编辑器之前看到的毫无意义的 Excel 错误提供更好的见解:

  1. 使用 AppleScript 编辑器确认该脚本实际上可以作为任何用户以及任何环境变量运行。使用:

    1. 在 Spotlight 中,开始输入“applescript editor”,直到它出现,然后单击它
    2. 创建新的 AppleScript 编辑器文件
    3. 将您的简单脚本输入到新文件中,不使用双引号 - 我的读法是

      执行 shell 脚本“parseCsvAndOpen.sh”
      
    4. 点击脚本的“运行”按钮
    5. 跟踪任何问题,进行更改,然后重复点击“运行”按钮,直到它在 AppleScript 编辑器中执行
      • 好消息是,如果您需要返回 StackOverflow 或 Google 寻求帮助,您的搜索范围会更窄;-)
  2. 现在将您的简单脚本从 AppleScript 编辑器复制到您的 vba 并确认它仍然有效 < /p>

    1. 我可以将双引号加倍,并将其放在 MacScript 代码后面的双引号中:

      MacScript“执行shell脚本”“parseCsvAndOpen.sh”“”
      

      这确实是一个、两个、然后三个双引号字符! (大概是转义双引号)

Another problem presents exactly like this: permissions cause your script to fail due to differences between the AppleScript environment and your user's bash environment. This Q&A helped me figure this out. To get my script to work, I had to resolve some path and permissions issues (not the script itself, but things touched by the script).

Here is my recommendation, which hopefully gives better insight during your troubleshooting than the meaningless Excel errors I was seeing before I used AppleScript Editor:

  1. Use AppleScript Editor to confirm that the script actually works as whatever user and with whatever environment variable happens to be used:

    1. In Spotlight, start typing "applescript editor" until it shows up and then click on it
    2. Create a new AppleScript Editor file
    3. Type your simple script into the new file without doubling the double quotes - mine reads

      do shell script "parseCsvAndOpen.sh"
      
    4. Hit the "Run" button for your script
    5. Track down any issues, make changes, and repeat hitting the "Run" button until you get it to execute from within AppleScript Editor
      • The good news here is that you have a narrower search if you need to go back to StackOverflow or Google for help ;-)
  2. now copy your simple script from AppleScript Editor to your vba and confirm it still works

    1. I was able to just double my double quotes and put it in double quotes after the MacScript code:

      MacScript "do shell script ""parseCsvAndOpen.sh"""
      

      That is indeed one, two, and then three double-quote characters! (presumably escaping the double quotes)

油饼 2024-11-16 13:14:48

对于使用 64 位 Office 的任何人,这里有 Robert 的代码,已更新为与 32 位和 64 位版本兼容。请注意,由于沙箱的更改,声明中必须使用 libc 的完整路径,否则您将在从未有版本的 OSX/Office 上出现错误 53“找不到文件”。

#If Mac Then
  #If VBA7 Then
    ' 64 bit Office:mac
    Private Declare PtrSafe Function popen Lib "/usr/lib/libc.dylib" (ByVal command As String, ByVal mode As String) As LongPtr
    Private Declare PtrSafe Function pclose Lib "/usr/lib/libc.dylib" (ByVal file As LongPtr) As Long
    Private Declare PtrSafe Function fread Lib "/usr/lib/libc.dylib" (ByVal outStr As String, ByVal size As LongPtr, ByVal items As LongPtr, ByVal stream As LongPtr) As Long
    Private Declare PtrSafe Function feof Lib "/usr/lib/libc.dylib" (ByVal file As LongPtr) As LongPtr
    Private file As LongPtr
  #Else
    ' 32 bit Office:mac
    Private Declare Function popen Lib "libc.dylib" (ByVal command As String, ByVal mode As String) As Long
    Private Declare Function pclose Lib "libc.dylib" (ByVal file As Long) As Long
    Private Declare Function fread Lib "libc.dylib" (ByVal outStr As String, ByVal size As Long, ByVal items As Long, ByVal stream As Long) As Long
    Private Declare Function feof Lib "libc.dylib" (ByVal file As Long) As Long
    Private file As Long
  #End If

  Public Function execShell(command As String, Optional ByRef exitCode As Long) As String
    file = popen(command, "r")
    
    If file = 0 Then
      Exit Function
    End If
    
    While feof(file) = 0
      Dim chunk As String
      Dim read As Long
      chunk = SPACE(50)
      read = fread(chunk, 1, Len(chunk) - 1, file)
      If read > 0 Then
        chunk = Left$(chunk, read)
        execShell = execShell & chunk
      End If
    Wend
    
    exitCode = pclose(file) ' 0 = success
  End Function

#End If

For anyone using 64-bit Office here's Robert's code updated to be compatible with both 32 and 64 bit versions. Note that due to a change in sandboxing, the full path to the libc must be used in the declarations otherwise you'll end up with an error 53 "File not found" on never versions of OSX/Office.

#If Mac Then
  #If VBA7 Then
    ' 64 bit Office:mac
    Private Declare PtrSafe Function popen Lib "/usr/lib/libc.dylib" (ByVal command As String, ByVal mode As String) As LongPtr
    Private Declare PtrSafe Function pclose Lib "/usr/lib/libc.dylib" (ByVal file As LongPtr) As Long
    Private Declare PtrSafe Function fread Lib "/usr/lib/libc.dylib" (ByVal outStr As String, ByVal size As LongPtr, ByVal items As LongPtr, ByVal stream As LongPtr) As Long
    Private Declare PtrSafe Function feof Lib "/usr/lib/libc.dylib" (ByVal file As LongPtr) As LongPtr
    Private file As LongPtr
  #Else
    ' 32 bit Office:mac
    Private Declare Function popen Lib "libc.dylib" (ByVal command As String, ByVal mode As String) As Long
    Private Declare Function pclose Lib "libc.dylib" (ByVal file As Long) As Long
    Private Declare Function fread Lib "libc.dylib" (ByVal outStr As String, ByVal size As Long, ByVal items As Long, ByVal stream As Long) As Long
    Private Declare Function feof Lib "libc.dylib" (ByVal file As Long) As Long
    Private file As Long
  #End If

  Public Function execShell(command As String, Optional ByRef exitCode As Long) As String
    file = popen(command, "r")
    
    If file = 0 Then
      Exit Function
    End If
    
    While feof(file) = 0
      Dim chunk As String
      Dim read As Long
      chunk = SPACE(50)
      read = fread(chunk, 1, Len(chunk) - 1, file)
      If read > 0 Then
        chunk = Left$(chunk, read)
        execShell = execShell & chunk
      End If
    Wend
    
    exitCode = pclose(file) ' 0 = success
  End Function

#End If
再浓的妆也掩不了殇 2024-11-16 13:14:48

只是没有足够的点数来发表评论,但感觉这是对罗宾·奈特答案的补充。当然,功劳仍然归于他。
对于 Excel 15.18 (2015),标准 C 库的 system() 函数中使用的 open 调用不需要 --args关键字不再:

Private Declare Function system Lib "libc.dylib" (ByVal command As String) As Long

Sub RunSafari()
    Dim result As Long
    result = system("open -a Safari http://www.google.com")
    Debug.Print Str(result)
End Sub

这很好用。 2011年没有测试过。

Just not enough points to make a comment, but feel this as an addition to Robin Knights answer. Credits of course still to and for him.
For Excel 15.18 (2015) the open call used in the system() function from the standard C library doesn't need the --args keyword anymore:

Private Declare Function system Lib "libc.dylib" (ByVal command As String) As Long

Sub RunSafari()
    Dim result As Long
    result = system("open -a Safari http://www.google.com")
    Debug.Print Str(result)
End Sub

This works fine. Didn't test this under 2011.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文