2012-04-23 318 views
5

我在使用VBA/Excel宏和HTA的VBScript中遇到问题。问题只是VBScript,我还有其他两个组件,即VBA宏和HTA前端完美运行。但在我解释这个问题之前,我想你会帮助我,我必须帮助你理解VBScript的上下文。因此,基本上所有组件(VBScript,VBA宏和HTA)都是我正在构建的一个工具的一部分,用于自动执行一些手动操作。它几乎是这样的:VBScript - 如何让程序等待进程完成?

A - HTA

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

  1. 用户选择从HTA/GUI的一些文件。
  2. 在HTA的HTML中,在“SCRIPT”标记中有一些VBScript将用户4输入文件作为参数传递给VBScript(由WScript.exe执行 - 为了清晰起见您可以参考注释1)
  3. 这个脚本,现在叫它myScript.vbs然后处理4个参数,其中3个是特定的文件,第4个是其中有多个文件的路径/文件夹位置 - (也见注释2为了清楚起见)

乙 - myScript.vbs

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

  1. myScript.vbs打开前3个参数,它们是Excel文件。其中之一是具有我的VBA宏的* .xlsm文件。
  2. myScript.vbs然后使用第四参数,它是一个PATH到包含多个文件,并指定文件夹到一个变量,以传递给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文件已经打开(在循环之前由代码控制,并且由于我对该部分没有问题而在这里未显示),我必须保持它们打开。

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

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

任何想法?请致电 QF。

NOTES:

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的那条用户第四输入文件(HTML:INPUT TYPE =“文件“)并将其传递给HTA中的VBScript。这让我不能独自选择HTML中的FOLDER。

+0

你能不能添加'x4WB.close'到您的VBA宏的结束,而不是在VBScript中? – 2012-04-23 11:22:35

+0

@oraclecertifiedprofessional:我会在稍后与其他参考文献一起提供。谢谢。 – 2012-04-23 16:40:15

回答

15

你需要告诉运行要等到过程结束。例如:

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 
+0

也许我误解了这个问题,但是文件循环在vbs里面,因此上面的方法不能用于使脚本在'x4WB.Close'之后等待:)但是就像我说的那样,我可能误解了它。 – 2012-04-23 12:23:14

+0

@彼得:嗨,彼得,我想你可能误解了。如果你有你的“命令”变量,然后你把它传递给你的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错误,指出找不到文件...? – 2012-04-23 13:17:53

+0

除了我在空间不足时发表的评论外,我还测试了传递给Excel的字符串,以便通过将其打印到MsgBox中来测试它是否为错误的字符串。但是,MsgBox显示我正确地将该文件的字符串传递给Excel。我不明白还有什么可能是这个问题。 – 2012-04-23 13:26:41

0

可能是这样的? (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 
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

这可能不是具体回答你的长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 

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