3

I'm a new VB Script programmer trying to use VB Script to open a pdf file via the default program (Adobe Reader X in this case) and save it as a text file.

The current script I have opens the PDF, waits 1 second, then saves it as text. However, for slower computers, it might take more than 1 second for the PDF to load up. Does anyone know how to do a sleep loop until the file is opened or the status is ready?

Set WshShell = WScript.CreateObject("WScript.Shell") 
WshShell.Run """C:\Temp\Gasprices.pdf"""
Set objShell = CreateObject("WScript.Shell") 
wscript.sleep 1000
objShell.SendKeys "%FAX%S"
Tomalak
  • 332,285
  • 67
  • 532
  • 628
aqpham1
  • 31
  • 1
  • 5

2 Answers2

5

First off, since you are a beginner, always use Option Explicit. Many errors are caused by typos in variable names, you will catch them if you force yourself to declare all variables you use.

Secondly, you don't need to create two WScript.Shell objects, just re-use the existing one.

Thirdly, you need to activate the application you want to send commands to. That's what the Shell object's AppActivate method is for. It returns True or False, indicating whether bringing the application in question to the foreground has worked or not. You could use that in a loop (While Not Shell.AppActivate("Adobe Reader") ...) to wait exactly as long as the application needs.

However, the downside is that you need to know the exact title of the application window (or its process ID) for this to work at all. Application titles might change without warning, so this is kind of shaky. The PID is robust but it is not guessable.

In the end you will need the help of WMI to list all processes, fetch the correct PID and then pass that to AppActivate. The Win32_Process class is made for this.

Dim Shell, WMI, pid
Set Shell = WScript.CreateObject("WScript.Shell") 
Set WMI = GetObject("winmgmts:!\\.\root\cimv2")

Shell.Run "start ""C:\Temp\Gasprices.pdf"""

pid = WaitForProcess("AcroRd32.exe", 5)

If pid > 0 Then
    Shell.AppActivate pid
    Shell.SendKeys "%FAX%S"
Else
    WScript.Echo "Could not talk to PDF reader"
    WScript.Quit 1
End If

Function WaitForProcess(imageName, tries)
    Dim wql, process

    wql = "SELECT ProcessId FROM Win32_Process WHERE Name = '" & imageName & "'"

    WaitForProcess = 0

    While tries > 0 And WaitForProcess = 0
        For Each process In WMI.ExecQuery(wql)
            WaitForProcess = process.ProcessId
        Next
        If WaitForProcess = 0 Then
            WScript.Sleep 1000
            tries = tries - 1
        End If
    Wend    
End Function

Note that assigning to the function name (as in WaitForProcess = 0) sets the return value.


You could optimize this by finding the script's own PID and querying

"SELECT ProcessId FROM Win32_Process WHERE ParentProcessId = '" & scriptPID & "'"

in WaitForProcess().

Community
  • 1
  • 1
Tomalak
  • 332,285
  • 67
  • 532
  • 628
1

Another possible option would be to test for Process CPU Usage...

You would need to test and see if this works in your environment...

Dim oShell, oExec, PID, X, Z
Set oShell = CreateObject("WScript.Shell")
Set oExec = oShell.Exec(Chr(34) & "C:\ADOBE PATH" & Chr(34) & " " & Chr(34) & "C:\YOUR PDF PATH.pdf" & Chr(34))
PID = oExec.ProcessID
WScript.Echo PID
'Prevent an Endless Loop
Z = 600  'about one minute worse case
Do
    WScript.Sleep 100
    X = GetCPUUsage(PID)
    WScript.Echo X
    Z = Z - 1
    If oExec.Status <> 0 Then
        MsgBox "The Process has been Terminated.  Ending Script"
        WScript.Quit
    End If
Loop Until X = 0 Or Z = 0
If Z > 0 Then
    WScript.Echo "Process Is More Or Less Opened"
Else
    WScript.Echo "Process is open...  Maybe?"
End If

Function GetCPUUsage(ProcID)
Dim objWMIService, colItems, objItem
Const wbemFlagReturnImmediately = &h10
Const wbemFlagForwardOnly = &h20
'Just in case
GetCPUUsage = 0
Set objWMIService = GetObject("winmgmts:\\.\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT PercentProcessorTime FROM Win32_PerfFormattedData_PerfProc_Process WHERE IDProcess = '" & ProcID & "'", _
    "WQL", wbemFlagReturnImmediately + wbemFlagForwardOnly)
For Each objItem In colItems
    GetCPUUsage = objItem.PercentProcessorTime
Next
End Function
B Hart
  • 1,108
  • 11
  • 20