Функция оболочки VBA в Office 2011 для Mac

Я пытаюсь запустить скрипт оболочки из макроса VBA в Word 2011 для Mac, который будет работать в окне терминала. Я пытался использовать как функцию Shell, так и MacScript функции, но интерпретатор VBA не может найти сценарий в любом случае.

Согласно справочной документации VBA, должно работать следующее:

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

Это приводит к ошибке времени выполнения 53 "Файл не найден".

Какие-либо предложения?

4 ответа

Shell() Для функции VBA на Mac требуется полный путь в виде пути в стиле HFS (с двоеточиями вместо косых черт). Он также не принимает аргументы, как в Windows (сообщая об ошибке "Путь не найден", если добавлены какие-либо аргументы).

MacScript() Функцию VBA также можно использовать: MacScript("do shell script ""command"""), Это, вероятно, будет самым простым вариантом, и я бы предложил сделать. Недостатком является то, что он имеет много накладных расходов (100-200 мс на звонок).

Другой альтернативой является system() функция из стандартной библиотеки C:

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.

Надеюсь, вы уже нашли ответ, но вам просто нужен полный путь:

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)

Для всех, кто использует 64-битный Office, здесь обновлен код Роберта, чтобы он был совместим как с 32-битной, так и с 64-битной версиями. Обратите внимание, что из-за изменения песочницы в объявлениях должен использоваться полный путь к libc, иначе вы получите ошибку 53 "Файл не найден" ни в каких версиях 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

Другая проблема возникает именно так: разрешения вызывают сбой вашего скрипта из-за различий между средой AppleScript и средой bash вашего пользователя. Это вопросы и ответы помогли мне понять это. Чтобы заставить мой сценарий работать, мне пришлось решить некоторые проблемы с путями и разрешениями (не сам сценарий, а вещи, затронутые сценарием).

Вот моя рекомендация, которая, как мы надеемся, дает лучшее понимание во время устранения неполадок, чем бессмысленные ошибки Excel, которые я видел до того, как использовал AppleScript Editor:

  1. Используйте AppleScript Editor, чтобы убедиться, что скрипт действительно работает как любой пользователь и с любой переменной среды, которая будет использоваться:

    1. В Spotlight начните вводить "редактор appleScript", пока он не появится, а затем нажмите на него.
    2. Создайте новый файл AppleScript Editor
    3. Введите свой простой скрипт в новый файл без двойных кавычек - мой читает

      do shell script "parseCsvAndOpen.sh"
      
    4. Нажмите кнопку "Выполнить" для вашего скрипта
    5. Отслеживайте любые проблемы, вносите изменения и повторяйте нажатие кнопки "Выполнить" до тех пор, пока вы не запустите ее из редактора AppleScript.
      • Хорошей новостью здесь является то, что у вас есть более узкий поиск, если вам нужно вернуться к Stackru или Google за помощью;-)
  2. Теперь скопируйте ваш простой скрипт из AppleScript Editor в вашу VBA и подтвердите, что он все еще работает

    1. Я смог удвоить свои двойные кавычки и поместить их в двойные кавычки после кода MacScript:

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

      Это действительно один, два, а затем три символа двойной кавычки! (предположительно, избегая двойных кавычек)

Просто не хватает очков, чтобы сделать комментарий, но почувствуйте это как дополнение к ответу Робин Найтс. Кредиты конечно еще и для него. В Excel 15.18 (2015) вызов open, используемый в функции system() из стандартной библиотеки C, больше не нуждается в ключевом слове --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.

Другие вопросы по тегам