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

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

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

A - HTA

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

User selects some files from the HTA/GUI. Within the HTML of the HTA there is some VBScript within the "SCRIPT" tags which passes the users 4 input files as arguments to a VBScript (executed by WScript.exe - you may refer to note #1 for clarity here) The script, lets call it myScript.vbs from now on then handles the 4 arguments, 3 of which are specific files and the 4th is a path/folder location that has multiple files in it - (also see note #2 for clarity) B - myScript.vbs

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

myScript.vbs opens up the first 3 arguments which are Excel files. One of them is a *.xlsm file that has my VBA macro.

myScript.vbs then uses the 4th argument which is a PATH to a folder that contains multiple files and assigns that to a variable for passing to a FileSystemObject object when calling GetFolder, i.e.

<code>... '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)
...
</code>

From here I create a loop so that I can sequentially open the files within the folder and then run my macro, i.e.

<code>...
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 
...
</code>

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

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

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

Есть идеи?

Спасибо, QF.

ЗАМЕТКИ:

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

<code>    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)
</code>

2 В HTA используется фрагмент JavaScript, который отбирает у пользователя четвертый входной файл (HTML: INPUT TYPE = & quot; file & quot;) и передает его в VBScript внутри HTA. Это позволяет мне решить проблему невозможности выбора FOLDER исключительно в HTML.

 user6982023 апр. 2012 г., 13:22
не могли бы вы добавитьx4WB.close до конца вашего макроса VBA, а не в VBScript?
 qwerty_face23 апр. 2012 г., 18:40
@oraclecertificprofessional: я приведу его вместе с другими ссылками позже. Благодарю.

Ответы на вопрос(4)

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
objWMIService.Create "notepad.exe", null, null, intProcessID
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colMonitoredProcesses = objWMIService.ExecNotificationQuery _
    ("Select * From __InstanceDeletionEvent Within 1 Where TargetInstance ISA 'Win32_Process'")
Do Until i = 1
    Set objLatestProcess = colMonitoredProcesses.NextEvent
    If objLatestProcess.TargetInstance.ProcessID = intProcessID Then
        i = 1
    End If
Loop
Wscript.Echo "Notepad has been terminated."
Решение Вопроса

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
 23 апр. 2012 г., 14:23
Возможно, я неправильно понял вопрос, но File Loop находится внутри vbs, и, следовательно, вышеописанный метод не может быть использован для того, чтобы заставить скрипт ждать послеx4WB.Close :) Но тогда, как я уже сказал, я мог бы неправильно это понять ...
 23 апр. 2012 г., 15:28
извините за это, но всегда указывайте полный путь в вашей команде, в противном случае вы не знаете, где скрипт пытается его получить, поэтому ваша переменная Fil является полным путем? Попробуйте полную командную строку в консольном кулаке
 qwerty_face23 апр. 2012 г., 15:26
В дополнение к моему комментарию, когда мне не хватило места, я проверил, какую строку я передаю в Excel, чтобы проверить, является ли она плохой строкой, напечатав ее в MsgBox. Тем не менее, MsgBox показывает, что я передаю строку файла в Excel правильно. Я не понимаю, в чем еще может быть проблема.
 qwerty_face23 апр. 2012 г., 15:17
@peter: Привет, Питер, я думаю, ты, возможно, неправильно понял. Где у вас есть ваша & quot; команда & quot; переменная, и затем вы передаете это в свой объект 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 о том, что файл не может быть найден ...?
 qwerty_face23 апр. 2012 г., 15:29
@peter: Да, я сделал это из командной строки cmd, и он прекрасно открывает файл. Я попробую еще раз ... следите за обновлениями ...

UNTESTED)

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

но эта ветка устарела, и я нашел это во время поиска сегодня. Вот один короткий способ: & quot;Wait until a process has finished. & Quot; Если вам известно имя процесса, например & quot; EXCEL.EXE & quot;

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 'opt,ional to show the loop works
Loop

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

 12 мар. 2019 г., 15:17
Хорошо понял. Спасибо :)
 09 февр. 2019 г., 22:31
Это правда, но полностью пропускает вопрос. Вы можете использовать сон в течение 1 секунды, но что делать, если процесс занимает более 1 секунды? Вы не можете знать, сколько это займет, следовательно, это бесполезно ...
 11 февр. 2019 г., 16:40
Это не бесполезно. Посмотрите еще раз на код. Спящий режим просто для того, чтобы уменьшить количество запросов, т.е. 1 в секунду, и избежать «занятого цикла». Программа будет зависать в цикле, пока процесс не будет завершен.

Ваш ответ на вопрос