VBScript - Как заставить программу ждать завершения процесса?

У меня проблема с VBScript, который я использую с макросом VBA / Excel и HTA. Проблема только в VBScript, у меня есть два других компонента, то есть макрос VBA и интерфейс HTA, которые работают отлично. Но прежде чем я объясню проблему, я думаю, что для того, чтобы вы мне помогли, я должен помочь вам понять контекст VBScript.

Итак, в основном все компоненты (VBScript, VBA macro и HTA) являются частями инструмента, который я создаю для автоматизации некоторых ручных работ. Это примерно так:

A - HTA

~~~~~~~~~~~~

  1. Пользователь выбирает некоторые файлы из HTA / GUI.
  2. В HTML HTA есть некоторый VBScript в тегах «SCRIPT», который передает 4 входных файла пользователей в качестве аргументов VBScript (выполняется WScript.exe - вы можете обратиться к примечанию № 1 для ясности здесь)
  3. Сценарий, позволяющий называть его myScript.vbs с этого момента, обрабатывает 4 аргумента, 3 из которых являются конкретными файлами, а 4-й - это путь / расположение папки, в котором есть несколько файлов - (также см. примечание # 2 для ясности)

B - myScript.vbs

~~~~~~~~~~~~

  1. myScript.vbs открывает первые 3 аргумента, которые являются файлами Excel. Один из них - файл * .xlsm с моим макросом VBA.
  2. myScript.vbs затем использует 4-й аргумент, который представляет собой ПУТЬ к папке, содержащей несколько файлов, и назначает его переменной для передачи объекту FileSystemObject при вызове GetFolder, т.е.

    ... 'Other code here, irrelevant for this post
    Dim FSO, FLD, strFolder
    ... 'Other code here, irrelevant for this post
    arg4 = args.Item(3)
    strFolder = arg4
    Set FSO = CreateObject("Scripting.FileSystemObject"
    'Get a reference to the folder you want to search
    Set FLD = FSO.GetFolder(strFolder)
    ...
    
  3. Отсюда я создаю цикл, чтобы я мог последовательно открывать файлы в папке, а затем запускать свой макрос, т.е.

    ...
    Dim strWB4, strMyMacro
    strMyMacro = "Sheet1.my_macro_name"
    
    'loop through the folder and get the file names
    For Each Fil In FLD.Files
    
        Set x4WB = x1.Workbooks.Open(Fil)
    x4WB.Application.Visible = True
    
    x1.Run strMyMacro
    
    x4WB.close
    Next 
    ...
    

Обратите внимание, что при открытии первых 3 файлов Excel (управляемых кодом до цикла и не показанных здесь, поскольку у меня нет проблем с этой частью), я должен держать их открытыми.

Это файлы в папке (которая была передана как 4-й аргумент), которые должны последовательно открываться и закрываться. Но между открытием и закрытием мне нужно, чтобы макрос VBA / (записанный в одном из трех ранее открытых файлов Excel) запускался каждый раз, цикл повторяется и открывает новый файл из папки (надеюсь, вы следуйте - если нет, дайте мне знать :)).

Проблема, с которой я столкнулся, заключается в том, что файлы в папке открываются и закрываются, открываются и закрываются n количество раз (n = # файлов в папке, естественно), не дожидаясь запуска макроса. Это не то, что я хочу. Я пробовал оператор WScript.sleep с 10-секундной задержкой после оператора x1.Run strMyMacro, но безрезультатно.

Любые идеи?

Спасибо, QF.

ПРИМЕЧАНИЯ:

1 - Для простоты / ясности вот как:

    strCMD = cmd /c C:\windows\system32\wscript.exe myScript.vbs <arg1> <arg2> <arg3> <arg4>
    'FYI - This is run by creating a WShell object, wsObj, and using the .run method, i.e. WShell.run(strCMD)

2 HTA использует фрагмент JavaScript, который удаляет 4-й входной файл пользователя (HTML: INPUT TYPE = "file") и передает его сценарию VBScript в HTA. Это помогает мне решить проблему невозможности исключительного выбора ПАПКИ в HTML.


person qwerty_face    schedule 23.04.2012    source источник
comment
не могли бы вы добавить x4WB.close в конец макроса VBA вместо VBScript?   -  person    schedule 23.04.2012
comment
@oraclecertifiedprofessional: Позже я рассмотрю его вместе с другими ссылками. Спасибо.   -  person qwerty_face    schedule 23.04.2012


Ответы (3)


Вам нужно сказать запуску, чтобы он дождался завершения процесса. Что-то типа:

const DontWaitUntilFinished = false, ShowWindow = 1, DontShowWindow = 0, WaitUntilFinished = true
set oShell = WScript.CreateObject("WScript.Shell")
command = "cmd /c C:\windows\system32\wscript.exe <path>\myScript.vbs " & args
oShell.Run command, DontShowWindow, WaitUntilFinished

В самом скрипте запускаем Excel вот так. При запуске отладки видны:

File = "c:\test\myfile.xls"
oShell.run """C:\Program Files\Microsoft Office\Office14\EXCEL.EXE"" " & File, 1, true
person peter    schedule 23.04.2012
comment
Возможно, я неправильно понял вопрос, но File Loop находится внутри vbs, и, следовательно, вышеупомянутый метод не может использоваться для того, чтобы заставить скрипт ждать после x4WB.Close :) Но тогда, как я уже сказал, я мог неправильно это понять ... - person Siddharth Rout; 23.04.2012
comment
@peter: Привет, Питер, я думаю, ты неправильно понял. Если у вас есть командная переменная, которую вы затем передаете своему объекту WScript, я уже сделал это в моем HTA. Затем мой myScript.vbs вступает во владение, и именно в этом сценарии я выполняю всю обработку Excel. Тем не менее, я попробовал вашу идею в myScript.vbs, выполнив: Dim WshShell Set WshShell = CreateObject("WScript.Shell") WshShell.run "C:\Program Files\Microsoft Office\Office14\EXCEL.exe" & " " & Fil, 0, true, но это возвращает ошибку VBScript о том, что файл не может быть найден ...? - person qwerty_face; 23.04.2012
comment
В дополнение к моему комментарию, когда у меня закончилось место, я проверил, какую строку я передаю в Excel, чтобы проверить, является ли это плохой строкой, распечатав ее в MsgBox. Однако MsgBox показывает, что я правильно передаю строку файла в Excel. Я не понимаю, в чем еще может быть проблема. - person qwerty_face; 23.04.2012
comment
извините за это, но всегда указывайте полный путь в вашей команде, иначе вы не знаете, где скрипт пытается его получить, значит, ваша переменная Fil - это полный путь? Попробуйте полную командную строку в кулаке консоли - person peter; 23.04.2012
comment
@peter: Ага, я сделал это из командной строки, и он отлично открывает файл. Я попробую еще раз ... следите за обновлениями ... - person qwerty_face; 23.04.2012
comment
ха, здесь мы пропустили друг друга, вы можете опубликовать всю строку, которую пытаетесь выполнить, и получить ошибку в скрипте? - person peter; 23.04.2012
comment
@peter: Конечно. Перед оператором WshShell.run "C:\Program Files\Microsoft Office\Office14\EXCEL.exe" & " " & Fil, 0, true я вставил MsgBox(Fil), чтобы отладить, какая строка передается. Он распечатывает D:\I\S\myfile.xls, что правильно. Тем не менее, я получаю сообщение об ошибке. Я поместил это в командную строку, т.е. C:\Program Files\Microsoft Office\Office14\EXCEL.exe D:\I\S\myfile.xls, и все работает нормально ... Есть идеи? - person qwerty_face; 23.04.2012
comment
я постараюсь воспроизвести, держись - person peter; 23.04.2012
comment
думаю, я нашел это, команду в самой консоли также нужно ввести, я адаптирую свой ответ, более понятный - person peter; 23.04.2012
comment
Ага, это работает. Однако осталось одно препятствие. Этот файл открывается объектом WShell, тогда как я открыл три других файла Excel, создав объект Excel.Application и запустив их таким образом. В моем цикле после того, как я открываю 4-й файл (-ы), используя ваше предложение, я не могу запустить макрос, поскольку он не может определить, где находится 4-й файл. Я бы преобразовал остальные 3, чтобы они были открыты таким же образом, но я не знаю, можно ли и как запустить макрос таким образом. Есть идеи по этому поводу? - person qwerty_face; 23.04.2012
comment
не знаю, все ли это правильный подход, должен увидеть весь ваш код, чтобы судить, в любом случае вы можете запустить макрос автоматически следующим образом: [code] Private Sub Auto_Open () MacroName End Sub [/ code] - person peter; 23.04.2012

Возможно, это не конкретно ответ на ваш длинный вопрос из трех частей, но эта ветка устарела, и я нашел ее сегодня во время поиска. Вот один более короткий способ: «Дождаться завершения процесса». Если вы знаете название процесса, например "EXCEL.EXE"

strProcess = "EXCEL.EXE"    
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colProcesses = objWMIService.ExecQuery ("Select * from Win32_Process Where Name = '"& strProcess &"'")
Do While colProcesses.Count > 0
    Set colProcesses = objWMIService.ExecQuery ("Select * from Win32_Process Where Name = '"& strProcess &"'")
    Wscript.Sleep(1000) 'Sleep 1 second
   'msgbox colProcesses.count 'optional to show the loop works
Loop

Кредит: http://crimsonshift.com/scripting-check-if-process-or-program-is-running-and-start-it/

person jelde015    schedule 17.01.2018
comment
Это правда, но полностью упускает из виду вопрос. Вы можете использовать сон в течение 1 секунды, но что, если процесс займет больше 1 секунды? Вы не можете знать, сколько это займет, следовательно, бесполезно ... - person Shai Alon; 10.02.2019
comment
Это не бесполезно. Посмотрите еще раз на код. Спящий режим предназначен только для уменьшения количества запросов, т.е. 1 в секунду, и во избежание цикла занятости. Программа застрянет в цикле до завершения процесса. - person jelde015; 11.02.2019
comment
Хорошо понял. Спасибо :) - person Shai Alon; 12.03.2019

Наверное, как-то так? (НЕ ПРОВЕРЕНО)

Sub Sample()
    Dim strWB4, strMyMacro
    strMyMacro = "Sheet1.my_macro_name"

    '
    '~~> Rest of Code
    '

    'loop through the folder and get the file names
    For Each Fil In FLD.Files
        Set x4WB = x1.Workbooks.Open(Fil)
        x4WB.Application.Visible = True

        x1.Run strMyMacro

        x4WB.Close

        Do Until IsWorkBookOpen(Fil) = False
            DoEvents
        Loop
    Next

    '
    '~~> Rest of Code
    '
End Sub

'~~> Function to check if the file is open
Function IsWorkBookOpen(FileName As String)
    Dim ff As Long, ErrNo As Long

    On Error Resume Next
    ff = FreeFile()
    Open FileName For Input Lock Read As #ff
    Close ff
    ErrNo = Err
    On Error GoTo 0

    Select Case ErrNo
    Case 0:    IsWorkBookOpen = False
    Case 70:   IsWorkBookOpen = True
    Case Else: Error ErrNo
    End Select
End Function
person Siddharth Rout    schedule 23.04.2012