VBScript - 如何让程序等到进程完成?

时间:2022-07-31 20:55:58

I have a problem in a VBScript that I am using with a VBA/Excel macro and a HTA. The problem is just the VBScript, I have the other two components, i.e. the VBA macro and HTA front-end working perfectly. But before I explain the problem, I think for you to help me I must help you understand the context of the VBScript.

我在使用VBA / Excel宏和HTA的VBScript中遇到问题。问题只是VBScript,我还有其他两个组件,即VBA宏和HTA前端工作正常。但在我解释这个问题之前,我想你帮助我,我必须帮助你理解VBScript的背景。

So, basically all components (VBScript, VBA macro and HTA) are parts of a tool that I am building to automate some manual chores. It pretty much goes like this:

因此,基本上所有组件(VBScript,VBA宏和HTA)都是我正在构建的工具的一部分,以自动化一些手动琐事。它几乎是这样的:

A - HTA

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

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

  1. User selects some files from the HTA/GUI.
  2. 用户从HTA / GUI中选择一些文件。
  3. 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)
  4. 在HTA的HTML中,“SCRIPT”标签中有一些VBScript,它将用户的4个输入文件作为参数传递给VBScript(由WScript.exe执行 - 为了清楚起见,您可以参考注释#1)
  5. 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)
  6. 该脚本,从现在开始调用myScript.vbs然后处理4个参数,其中3个是特定文件,第4个是包含多个文件的路径/文件夹位置 - (为清晰起见,请参阅注释#2)

B - myScript.vbs

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

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

  1. myScript.vbs opens up the first 3 arguments which are Excel files. One of them is a *.xlsm file that has my VBA macro.
  2. myScript.vbs打开前3个参数,这些参数是Excel文件。其中一个是具有我的VBA宏的* .xlsm文件。
  3. 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.

    myScript.vbs然后使用第4个参数作为包含多个文件的文件夹的PATH,并将其分配给变量,以便在调用GetFolder时传递给FileSystemObject对象,即

    ... '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)
    ...
    
  4. From here I create a loop so that I can sequentially open the files within the folder and then run my macro, i.e.

    从这里我创建一个循环,以便我可以顺序打开文件夹中的文件,然后运行我的宏,即

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

Please note that when the first 3 Excel files have opened (controlled by code prior to the loop, and not shown here as I am having no problem with that part) I must keep them open.

请注意,当前3个Excel文件打开时(由循环前的代码控制,此处未显示,因为我对该部分没有任何问题)我必须保持它们打开。

It is the files in the folder (that was passed as the 4th argument) which must sequentially open and close. But inbetween opening and closing, I require the VBA/macro (wrote in one of the 3 Excel files previously opened) to run each time the loop iterates and opens a new file from the folder (I hope you follow - if not please let me know :) ).

它是文件夹中的文件(作为第4个参数传递),必须按顺序打开和关闭。但是在打开和关闭之间,我需要VBA /宏(在先前打开的3个Excel文件中的一个中写入)在每次循环迭代时运行并从文件夹中打开一个新文件(我希望你关注 - 如果没有请让我知道:))。

The problem I am having is that the files in the folder open and close, open and close, n number of times (n = # of files in folder, naturally) without waiting for the macro to run. This is not what I want. I have tried the WScript.sleep statement with a 10 second delay after the 'x1.Run strMyMacro' statement, but to no avail.

我遇到的问题是文件夹中的文件打开和关闭,打开和关闭n次(n =文件夹中的文件数,当然),而不等待宏运行。这不是我想要的。我在'x1.Run strMyMacro'语句之后尝试了WScript.sleep语句,延迟了10秒,但无济于事。

Any ideas?

有任何想法吗?

Thanks, QF.

谢谢,QF。

NOTES:

笔记:

1 - For simplicity/clarity this is how:

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 The HTA employs a piece of JavaScript that strips the users 4th input file (HTML: INPUT TYPE="file") and passes that to the the VBScript within the HTA. This gets me round the problem of not being able to exclusively select a FOLDER in HTML.

2 HTA使用一段JavaScript来剥离用户的第四个输入文件(HTML:INPUT TYPE =“file”)并将其传递给HTA中的VBScript。这让我解决了无法在HTML中专门选择FOLDER的问题。

4 个解决方案

#1


16  

You need to tell the run to wait until the process is finished. Something like:

您需要告诉运行等待进程完成。就像是:

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

In the script itself, start Excel like so. While debugging start visible:

在脚本本身,像这样启动Excel。调试启动时可见:

File = "c:\test\myfile.xls"
oShell.run """C:\Program Files\Microsoft Office\Office14\EXCEL.EXE"" " & File, 1, true

#2


2  

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."

#3


1  

This may not specifically answer your long 3 part question but this thread is old and I found this while searching today. Here is one shorter way to: "Wait until a process has finished." If you know the name of the process such as "EXCEL.EXE"

这可能没有具体回答你的长篇3部分问题,但这个帖子已经过时了,我今天在搜索时发现了这个问题。这是一个较短的方法:“等到一个过程完成。”如果您知道进程的名称,例如“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

Credit to: http://crimsonshift.com/scripting-check-if-process-or-program-is-running-and-start-it/

感谢:http://crimsonshift.com/scripting-check-if-process-or-program-is-running-and-start-it/

#4


0  

Probably something like this? (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

#1


16  

You need to tell the run to wait until the process is finished. Something like:

您需要告诉运行等待进程完成。就像是:

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

In the script itself, start Excel like so. While debugging start visible:

在脚本本身,像这样启动Excel。调试启动时可见:

File = "c:\test\myfile.xls"
oShell.run """C:\Program Files\Microsoft Office\Office14\EXCEL.EXE"" " & File, 1, true

#2


2  

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."

#3


1  

This may not specifically answer your long 3 part question but this thread is old and I found this while searching today. Here is one shorter way to: "Wait until a process has finished." If you know the name of the process such as "EXCEL.EXE"

这可能没有具体回答你的长篇3部分问题,但这个帖子已经过时了,我今天在搜索时发现了这个问题。这是一个较短的方法:“等到一个过程完成。”如果您知道进程的名称,例如“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

Credit to: http://crimsonshift.com/scripting-check-if-process-or-program-is-running-and-start-it/

感谢:http://crimsonshift.com/scripting-check-if-process-or-program-is-running-and-start-it/

#4


0  

Probably something like this? (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