web-dev-qa-db-fra.com

VBScript - Comment faire pour que le programme attende jusqu'à la fin du processus?

J'ai un problème dans un script VBScript que j'utilise avec une macro VBA/Excel et un HTA. Le problème ne concerne que le VBScript. J'ai les deux autres composants, c’est-à-dire que la macro VBA et le HTA Front-end fonctionnent parfaitement. Mais avant d’expliquer le problème, je pense que pour que vous puissiez m'aider, je dois vous aider à comprendre le contexte du VBScript.

En gros, tous les composants (VBScript, macro VBA et HTA) font partie d’un outil que je construis pour automatiser certaines tâches manuelles. C'est à peu près comme ça:

A - HTA

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

  1. L'utilisateur sélectionne certains fichiers dans HTA/GUI.
  2. Dans le code HTML de la HTA, il y a du VBScript dans les balises "SCRIPT" qui transmet aux utilisateurs 4 fichiers d'entrée en tant qu'arguments à un VBScript (exécuté par WScript.exe - vous pouvez vous référer à la note 1 pour plus de clarté).
  3. Le script, appelons-le myScript.vbs à partir de maintenant gère ensuite les 4 arguments, dont 3 sont des fichiers spécifiques et le 4ème est un chemin/dossier qui contient plusieurs fichiers - (voir aussi la note n ° 2 pour plus de clarté)

B - myScript.vbs

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

  1. myScript.vbs ouvre les 3 premiers arguments qui sont des fichiers Excel. L'un d'eux est un fichier * .xlsm contenant ma macro VBA.
  2. myScript.vbs utilise ensuite le 4ème argument, qui est un chemin PATH vers un dossier contenant plusieurs fichiers, et l'affecte à une variable à transmettre à un objet FileSystemObject lors de l'appel de GetFolder, c'est-à-dire.

    ... '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. À partir de là, je crée une boucle pour pouvoir ouvrir séquentiellement les fichiers du dossier .__, puis exécuter ma macro, c.-à-d.

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

Veuillez noter que lorsque les 3 premiers fichiers Excel sont ouverts (contrôlés par le code avant la boucle, et non affichés ici car je n’ai aucun problème avec cette partie), je dois les garder ouverts.

Ce sont les fichiers du dossier (passé en tant que 4ème argument) qui doivent être ouverts et fermés de manière séquentielle. Mais entre l’ouverture et la fermeture, j’ai besoin de la macro/VBA (écrite dans l’un des 3 fichiers Excel précédemment ouverts) à exécuter à chaque fois la boucle itère et ouvre un nouveau fichier à partir du dossier (j'espère que vous suivrez - si pas s'il vous plaît laissez-moi savoir :)).

Le problème que je rencontre est que les fichiers du dossier s’ouvrent et se ferment, s’ouvrent et se ferment, n nombre de fois (n = n ° de fichiers dans le dossier, naturellement) sans attendre que la macro s’exécute. Ce n'est pas ce que je veux. J'ai essayé l'instruction WScript.sleep avec un délai de 10 secondes après l'instruction 'x1.Run strMyMacro', mais en vain.

Des idées?

Merci, QF.

REMARQUES:

1 - Pour plus de simplicité/clarté, voici comment:

    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 Le HTA utilise un morceau de JavaScript qui supprime le 4ème fichier d'entrée de l'utilisateur (HTML: INPUT TYPE = "fichier") et le transmet au VBScript du HTA. Cela m'empêche de ne pas pouvoir sélectionner exclusivement un DOSSIER en HTML.

6
qwerty_face

Vous devez indiquer à la course d'attendre que le processus soit terminé. Quelque chose comme:

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

Dans le script lui-même, démarrez Excel comme suit. Pendant que le débogage commence visible:

File = "c:\test\myfile.xls"
oShell.run """C:\Program Files\Microsoft Office\Office14\Excel.EXE"" " & File, 1, true
16
peter
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."
2
Krzysztof Gapski

Cela ne répond peut-être pas spécifiquement à votre longue question en 3 parties mais ce fil est ancien et je l’ai trouvé en cherchant aujourd’hui. Voici un moyen plus court de: "Attendre la fin d'un processus." Si vous connaissez le nom du processus tel que "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

Crédit à: http://crimsonshift.com/scripting-check-if-process-or-program-is-running-and-start-it/

0
jelde015

Probablement quelque chose comme ça? (NON TEST&EACUTE;)

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
0
Siddharth Rout