2012-04-23 14 views
5

Tengo un problema en un VBScript que estoy usando con una macro de VBA/Excel y una HTA. El problema es solo el VBScript, tengo los otros dos componentes, es decir, la interfaz VBA macro y HTA que funcionan perfectamente. Pero antes de explicar el problema, creo que para ayudarme, debo ayudarlo a comprender el contexto de VBScript.VBScript - ¿Cómo hacer que el programa espere hasta que el proceso haya finalizado?

Por lo tanto, básicamente todos los componentes (VBScript, VBA macro y HTA) son parte de una herramienta que estoy creando para automatizar algunas tareas manuales. Es más o menos así:

A - HTA

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

  1. El usuario selecciona algunos archivos de la HTA/GUI.
  2. Dentro del HTML de la HTA hay algunos VBScript dentro de las etiquetas "SCRIPT" que pasa los 4 archivos de entrada de los usuarios como argumentos a un VBScript (ejecutado por WScript.exe - puede consultar la nota 1 para mayor claridad aquí)
  3. El script, vamos a llamarlo myScript.vbs a partir de ahora maneja los 4 argumentos, 3 de los cuales son archivos específicos y el 4to es una ubicación de ruta/carpeta que tiene múltiples archivos en él - (también vea la nota # 2 para mayor claridad)

B - myscript.vbs

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

  1. myScript.vbs abre los primeros 3 argumentos que son archivos de Excel. Uno de ellos es un archivo * .xlsm que tiene mi macro VBA.
  2. myscript.vbs utiliza entonces el cuarto argumento de que es una ruta a una carpeta que contiene varios archivos y asigna a que una variable para pasar a un objeto FileSystemObject al llamar GetFolder, es decir

    ... '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. Desde aquí puedo crear un bucle para que pueda abrir secuencialmente los archivos dentro de la carpeta y luego ejecutar mi macro, es decir

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

favor n Es decir, cuando los primeros 3 archivos de Excel se hayan abierto (controlados por código antes del ciclo y no se muestren aquí, ya que no tengo problemas con esa parte), debo mantenerlos abiertos.

Son los archivos en la carpeta (que se pasaron como el 4to argumento) que deben abrirse y cerrarse secuencialmente. Pero entre medio de apertura y cierre, requiero la VBA/macro (escrito en uno de los 3 archivos de Excel previamente abiertos) para funcionar cada vez se repite el bucle y se abre un nuevo archivo de la carpeta (espero que siga - si no por favor Házmelo saber :)).

El problema que tengo es que los archivos de la carpeta se abren y cierran, se abren y se cierran, n cantidad de veces (n = n. De archivos en la carpeta, naturalmente) sin esperar que se ejecute la macro. Esto no es lo que quiero. He probado la sentencia WScript.sleep con un retraso de 10 segundos después de la declaración 'x1.Run strMyMacro', pero fue en vano.

¿Alguna idea?

Gracias, QF.

NOTAS:

1 - Para simplificar/claridad esta es la forma:

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 La HTA emplea un fragmento de código JavaScript que elimina el archivo de entrada cuarta usuarios (HTML: input type = archivo " ") y lo pasa al VBScript dentro de la HTA. Esto me hace olvidar el problema de no poder seleccionar exclusivamente una CARPETA en HTML.

+0

¿Es posible añadir el 'x4WB.close' hasta el final de su macro de VBA en lugar de en el VBScript ? –

+0

@oraclecertifiedprofessional: voy a darle un giro junto con las otras referencias más adelante. Gracias. –

Respuesta

15

tiene que decirle a la carrera que esperar hasta que termine el proceso. Algo como:

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 

En el script en sí, inicie Excel como tal. Mientras se depura comenzar visibles:

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

Quizás entendí mal la pregunta, pero File Loop está dentro de vbs y, por lo tanto, el método anterior no se puede utilizar para hacer que el script espere después de 'x4WB.Close' :) Pero, como dije, podría haberlo malinterpretado. –

+0

@peter: Hola Peter, creo que has malentendido. Donde tiene su variable de "comando" y luego la pasa a su objeto WScript, ya lo hice en mi HTA. Mi ** myScript.vbs ** toma el control y dentro de este script estoy haciendo todo el procesamiento de Excel. Aún así, he intentado su idea dentro de ** myScript.vbs ** haciendo: 'Dim WshShell Establecer WshShell = CreateObject (" WScript.Shell ") WshShell.run" C: \ Archivos de programa \ Microsoft Office \ Office14 \ EXCEL.exe "&" "& Fil, 0, true' pero esto devuelve un error de VBScript que indica que el archivo no se puede encontrar ...? –

+0

Además de mi comentario ya que me quedé sin espacio, he probado qué cadena estoy pasando a Excel para probar si es una cadena incorrecta al imprimirla en un MsgBox. Sin embargo, el MsgBox muestra que estoy pasando la cadena del archivo a Excel correctamente. No entiendo qué otra cosa podría ser el problema. –

0

Probablemente algo como esto? (sin probar)

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

Esto puede no responder específicamente a su pregunta larga de 3 partes, pero este hilo es viejo y me encontré con esto mientras busca en la actualidad. Aquí hay una forma más corta de: "Espere hasta que el proceso haya finalizado". Si conoce el nombre del proceso, tales como "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édito a: http://crimsonshift.com/scripting-check-if-process-or-program-is-running-and-start-it/

Cuestiones relacionadas