How to create options dialog with VbScript? - vbscript

I have a third party application that invokes a vsbscript file for certain operations. I would like to put up a user prompt with a choice of options, either a drop down list or checkbox or some such. However, all I can find is the input box option.
I don't think HTAs are an option in my case (unless there is a way to call them from a .vbs file?)
My other thought was some sort of ActiveX control, but I can't locate a built-in one that would be available by default on WindowsXP/Vista.
Anybody have any ideas on how I could accomplish this?

The simple answer is, you really can't. Tmdean's solution is the only way I can think of either. That said, you can spruce up the input box so it doesn't look horrible. Give this a run, I don't think it's an epic fail:
Dim bullet
Dim response
bullet = Chr(10) & " " & Chr(149) & " "
Do
response = InputBox("Please enter the number that corresponds to your selection:" & Chr(10) & bullet & "1.) Apple" & bullet & "2.) Bannana" & bullet & "3.) Pear" & Chr(10), "Select Thing")
If response = "" Then WScript.Quit 'Detect Cancel
If IsNumeric(response) Then Exit Do 'Detect value response.
MsgBox "You must enter a numeric value.", 48, "Invalid Entry"
Loop
MsgBox "The user chose :" & response, 64, "Yay!"

If you would like to use an hta for this it can be done like this.
The VBScript:
Set WshShell = CreateObject("WScript.Shell")
'Run the hta.
WshShell.Run "Test.hta", 1, true
'Display the results.
MsgBox "Return Value = " & getReturn
Set WshShell = Nothing
Function getReturn
'Read the registry entry created by the hta.
On Error Resume Next
Set WshShell = CreateObject("WScript.Shell")
getReturn = WshShell.RegRead("HKEY_CURRENT_USER\Volatile Environment\MsgResp")
If ERR.Number 0 Then
'If the value does not exist return -1
getReturn = -1
Else
'Otherwise return the value in the registry & delete the temperary entry.
WshShell.RegDelete "HKEY_CURRENT_USER\Volatile Environment\MsgResp"
End if
Set WshShell = Nothing
End Function
Then design the hta as desired, and include the following methods
'Call this when the OK button is clicked.
Sub OK_Click
For Each objradiobutton In Opt
If objradiobutton.Checked Then
WriteResponse objradiobutton.Value
End If
Next
window.Close
End Sub
'Call this when the Cancel button is clicked.
Sub Cancel_Click
WriteResponse("CANCEL")
window.Close
End Sub
'Write the response to the registry
Sub WriteResponse(strValue)
Set WshShell = CreateObject("WScript.Shell")
WshShell.RegWrite "HKEY_CURRENT_USER\Volatile Environment\MsgResp", strValue
Set WshShell = Nothing
End Sub
I used a group of radio buttons named "Opt" to make a choice, but you could use any controls you would like.
Because hta's cannot return values, this will create a temperary registry entry. If you are not comforatable messing with the registry, you could also write the result to a temperary text file.
This approach is nice because you can design the hta any way you like, rather than using the supplied inputbox and choosing numbers (thats so DOS).
This could also be nice if you expanded the hta to create itself based on arguments passed to it, like passing in a title, a message to display, an array of options, a set of buttons. That way you could use the same hta any time you needed to get input from the user.

You can use DialogLib to create forms with dropdowns and checkboxes. DialogLib is still in it's ealy stages, but is's allready quite usefull: http://www.soren.schimkat.dk/Blog/?p=189

Try WshShell.Popup. Depending upon your data that may work for you...
Otherwise you could investigate PowerShell.

One option is to script Internet Explorer. You can use VBScript to launch IE and load a local HTML file, and attach a VBScript sub to a form's submit button (or any other JavaScript events), which can then close the IE window as part of its execution.

You can launch an HTA from a VBScript.
Set shell = CreateObject("WScript.Shell")
shell.Run "Test.hta"
EDIT
Since you have full control of the VBScript, could you make the 3rd party VBScript simply call your HTA? You could put the UI and whatever processing code inside of the HTA.

As an example of #TmDean's suggestion, there's this class that I sometimes use which scripts IE (well, it scripted IE6; I haven't tried the more recent incarnations.)
class IEDisplay
'~ Based on original work by Tony Hinkle, tonyhinkle#yahoo.com
private TEMPORARY_FOLDER
private objShell
private objIE
private objFSO
private objFolder
private strName
private streamOut
private objDIV
private numHeight
private numWidth
private numTop
private numLeft
private sub Class_Initialize()
Dim strComputer
Dim objWMIService
Dim colItems
Dim objItem
Dim arrMonitors( 10, 1 )
Dim numMonitorCount
Set objShell = WScript.CreateObject("WScript.Shell")
Set objIE = CreateObject("InternetExplorer.Application")
strComputer = "."
Set objWMIService = GetObject( "winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery( "Select * from Win32_DesktopMonitor")
numMonitorCount = 0
For Each objItem in colItems
arrMonitors( numMonitorCount, 0 ) = objItem.ScreenHeight
arrMonitors( numMonitorCount, 1 ) = objItem.ScreenWidth
numMonitorCount = numMonitorCount + 1
Next
numHeight = arrMonitors( 0, 0 )
numWidth = arrMonitors( 0, 1 )
Set objFSO = CreateObject("Scripting.FileSystemObject")
TEMPORARY_FOLDER = 2
set objFolder = objFSO.GetSpecialFolder( TEMPORARY_FOLDER )
strName = objFSO.BuildPath( objFolder, objFSO.GetTempName ) & ".html"
WriteFileU strName, Join( Array( "<HTML><HEAD><TITLE>Information</TITLE></HEAD>", _
"<BODY SCROLL='NO'><CENTER><FONT FACE='arial black'> <HR COLOR='BLACK'>", _
"<DIV id='MakeMeAnObject'></DIV>", _
"<HR COLOR='BLACK'></FONT></CENTER></BODY></HTML>" ), vbCRLF ), WF_CREATE
numTop = 0
numLeft = 0
end sub
Sub Init( strPosition )
'NW, N, NE, W, CENTRE, E, SW, S, SE
Select Case strPosition
Case "NW"
numTop = 0
numLeft = 0
Case "N"
numTop = 0
numLeft = ( numWidth / 2 ) - 250
Case "NE"
numTop = 0
numLeft = numWidth - 500
Case "W"
numTop = ( numHeight / 2 ) - 55
numLeft = 0
Case "CENTRE"
numTop = ( numHeight / 2 ) - 55
numLeft = ( numWidth / 2 ) - 250
Case "E"
numTop = ( numHeight / 2 ) - 55
numLeft = numWidth - 500
Case "SW"
numTop = numHeight - 110
numLeft = 0
Case "S"
numTop = numHeight - 110
numLeft = ( numWidth / 2 ) - 250
Case "SE"
numTop = numHeight - 110
numLeft = numWidth - 500
Case Else
numTop = 0
numLeft = 0
End Select
SetupIE( strName )
Set objDIV = objIE.Document.All("MakeMeAnObject")
end sub
private sub Class_Terminate()
'Close IE and delete the file
objIE.Quit
'~ optionally you may want to get rid of the temp file
end sub
public sub Display( strMsg, numMillisec )
objDIV.InnerHTML = strMsg
WScript.Sleep numMillisec
end sub
Private Sub SetupIE(File2Load)
objIE.Navigate File2Load
objIE.ToolBar = False
objIE.StatusBar = False
objIE.Resizable = False
Do
Loop While objIE.Busy
objIE.Width = 500
objIE.Height = 110
objIE.Left = numLeft
objIE.Top = numTop
objIE.Visible = True
objShell.AppActivate("Microsoft Internet Explorer")
End Sub
end class
here is the missing (from the original posting) WriteFileU function
Const WF_APPEND = 1
Const WF_CREATE = 2
Const WF_FOR_APPENDING = 8
Const WF_FOR_WRITING = 2
Const WF_CREATE_NONEXISTING = True
Const CONST_READ = 1, CONST_WRITE = 2, CONST_APPEND = 8
Const AS_SYSTEMDEFAULT = -2, AS_UNICODE = -1, AS_ASCII = 0
Sub WriteFileU( sFilename, sContents, nMode )
Dim oStream
If nMode = WF_APPEND Then
Set oStream = oFSO.OpenTextFile( sFilename, WF_FOR_APPENDING, WF_CREATE_NONEXISTING, AS_UNICODE )
ElseIf nMode = WF_CREATE Then
Set oStream = oFSO.OpenTextFile( sFilename, WF_FOR_WRITING, WF_CREATE_NONEXISTING, AS_UNICODE )
Else
STOP
End If
oStream.Write sContents
oStream.Close
Set oStream = Nothing
End Sub
and then as an example of it's use
set i = new IEDisplay
a = array("NW", "N", "NE", "W", "CENTRE", "E", "SW","S","SE")
for each aa in a
i.init aa
i.display "Here in " & aa & " of screen", 1000
next
Now that's not immediately useful (especially are there are a pile of calls to my own utility routines in there) but it gives a framework. By modifying what HTML is stored, you could add support for listboxes etc.

I know this is eleven years too late, but it sounds like this would be more along the lines of what the original request would be looking for:
Sub CustomMsgBox(msg)
Dim ie, Style, FormExit
Set ie = CreateObject("InternetExplorer.Application")
ie.Navigate "about:blank"
While ie.ReadyState <> 4: WScript.Sleep 100: Wend
ie.Toolbar = False
ie.StatusBar = False
ie.Width = 450
ie.Height = 275
ie.document.body.innerHTML = "<title>Choose a Color</title><p class='msg'>Choose an option:</p>" & "<input type='radio' id='myRadio' name='colors' value='red'>Red</br><input type='radio' id='myRadio' name='colors' value='yellow'>Yellow</br><input type='radio' id='myRadio' name='colors' value='blue'>Blue"
Set Style = ie.document.CreateStyleSheet
Style.AddRule "p.msg", "font-family:calibri;font-weight:bold;"
ie.Visible = True
ie.Quit
End Sub

This code worked for me in an HTA file (that I opened from VBS using WScript.Shell Run). The trick was to get the data back to VBS which I accomplished by having HTA create an XML file that VBS read.
Sub CopySelect(sSrcId, sTargetId)
Dim oTarget: Set oTarget = document.getElementById(sTargetId)
Dim oSrc: Set oSrc = document.getElementById(sSrcId)
Dim j, n, o
oTarget.length = 0
For j = 0 to oSrc.length - 1
Set o = oSrc.options(j)
Set n = document.createElement("option")
n.text = o.text
n.value = o.value
oTarget.add n
Next
End Sub

Related

How Can I pause speak command in vbscript? I have to play it from the same paused position

How Can I pause speak command in vbscript? I have to play it from the same paused position.
Code block:
Dim Speak, Path
Path = "string"
Path = "C:\Users\sony\Desktop\TheReunion.txt"
const ForReading = 1
Set objFileToRead = CreateObject("Scripting.FileSystemObject").OpenTextFile(Path,ForReading)
strFileText = objFileToRead.ReadAll()
Set Speak=CreateObject("sapi.spvoice")
Speak.Speak strFileText
objFileToRead.Close
Set objFileToRead = Nothing
You need to call the speak method asynchronously before using the pause and resume methods as mentioned by LotPings in the comments.
Code:
Dim Speak, Path
Path = "string"
Path = "C:\Users\sony\Desktop\TheReunion.txt"
const ForReading = 1
Set objFileToRead = CreateObject("Scripting.FileSystemObject").OpenTextFile(Path,ForReading)
strFileText = objFileToRead.ReadAll()
Set Speak=CreateObject("sapi.spvoice")
Speak.Speak strFileText,1 '1=Asynchronous. Click the link below for other possible values "SpeechVoiceSpeakFlags"
'Due to async call to speak method, we can proceed with the code execution while the voice is being played in the background. Now we can call pause and resume methods
wscript.sleep 5000 'voice played for 5000ms
Speak.pause 'paused
wscript.sleep 4000 'remains paused for 4000ms
Speak.resume 'resumes
objFileToRead.Close
Set objFileToRead = Nothing
SpeechVoiceSpeakFlags
Intrigue in this led me to take inspiration from Kira's answer and develop it somewhat (in a bad, novice kind of way), to achieve the pause/resume objective interactively, the code below works for me, and hopefully it's of some help to you...
option explicit
dim strpath, fso, strfile, strtxt, user, voice, flag
flag = 2
call init
sub init
do while len(strpath) = 0
strpath = inputbox ("Please enter the full path of txt file", "Txt to Speech")
if isempty(strpath) then
wscript.quit()
end if
loop
'strpath = "C:\Users\???\Desktop\???.txt"
set fso = createobject("scripting.filesystemobject")
on error resume next
set strfile = fso.opentextfile(strpath,1)
if err.number = 0 then
strtxt = strfile.readall()
strfile.close
call ctrl
else
wscript.echo "Error: " & err.number & vbcrlf & "Source: " & err.source & vbcrlf &_
"Description: " & err.description
err.clear
call init
end if
end sub
sub ctrl
user = msgbox("Press ""OK"" to Play / Pause", vbokcancel + vbexclamation, "Txt to Speech")
select case user
case vbok
if flag = 0 then
voice.pause
flag = 1
call ctrl
elseif flag = 1 then
voice.resume
flag = 0
call ctrl
else
call spk
end if
case vbcancel
wscript.quit
end select
end sub
sub spk
'wscript.echo strtxt
set voice = createobject("sapi.spvoice")
voice.speak strtxt,1
flag = 0
call ctrl
end sub

Lookup and copy single column from one excel to another

I have a script which copies the values of columns A and B to column A and B of another Excel. Column headers are same.
What I want is to lookup from first Excel value of Column A in the second Excel and if there is a match then get the value of corresponding
value of Column B in the same row and paste it in the first Excel. If there is no match, then insert #N/A in column B of first Excel.
There should be no change to second Excel(where we look up the value). Colummn B in the first Excel is empty.
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = True
Set objWorkbook = objExcel.Workbooks.Open("C:\TEST.xlsx")
Set objWorkbook2 = objExcel.Workbooks.Open("C:\Desktop\IPT\Test.xlsx")
'objExcel.DisplayAlerts = False
Set objWorksheet = objWorkbook.Worksheets(1)
objWorksheet.Activate
Set objRange = objWorkSheet.Range("A:B").EntireColumn
objWorkSheet.Range("A:B").EntireColumn.Copy
Set objWorksheet2 = objWorkbook2.Worksheets(1)
objWorksheet.Activate
Set objRange = objWorkSheet2.Range("A:B")
objWorkSheet2.Paste objWorkSheet2.Range("A:B")
objWorksheet2.Paste(objRange)
objworkbook2.Save
objWorkbook.close("C:\TEST.xlsx")
objWorkbook2.close("C:\Desktop\IPT\Test.xlsx")
objExcel.Quit
objExcel.DisplayAlerts = True
Here is the first Excel
A B C
101 12
102 13
103 15
Second Excel File
A B C
101 Toy1 small
102 Toy2 medium
103 Toy3 high
Updated code:
ProcessFiles()
Sub ProcessFiles()
Const xlUp = -4162
Const vbCritical = 16
Const BOOK1 = "C:\TEST.xlsx.xls"
Const BOOK2 = "C:\Desktop\IPT\Test.xlsx"
Dim xlApp, xlWB, dict, r
Set dict = CreateObject("Scripting.Dictionary")
Set xlApp = CreateObject("Excel.Application")
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FolderExists(BOOK1) Then
MsgBox BOOK1 & " not found", vbCritical
Exit Sub
ElseIf objFSO.FolderExists(BOOK2) Then
MsgBox BOOK2 & " not found", vbCritical
Exit Sub
End If
Set objFSO = Nothing
Set xlWB = xlApp.Workbooks.Open(BOOK2)
With xlWB.Worksheets(1)
For Each r In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
If Not dict.Exists(r.Text) Then dict.Add r.Text, r.Offset(0, 1).Value
Next
End With
xlWB.Close False
Set xlWB = xlApp.Workbooks.Open(BOOK1)
With xlWB.Worksheets(1)
For Each r In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
'r.Offset(0, 4) = IIf(dict.Exists(r.Text), dict(r.Text), "#N/A")
If dict.Exists(r.Text) Then
r.Offset(0, 4) = dict(r.Text)
Else
r.Offset(0, 4) = "#N/A"
End If
Next
End With
xlWB.Close True
End Sub
Scripting Dictionaries make it easy to compare lists.
Sub ProcessFiles()
Const xlUp = -4162
Const vbCritical = 16
Const BOOK1 = "\\norfile5\Public\Table Games\Spotlights\Back Up\SO\Book1.xlsx"
Const BOOK2 = "\\norfile5\Public\Table Games\Spotlights\Back Up\SO\Book2.xlsx"
Dim xlApp, xlWB, dict, r
Set dict = CreateObject("Scripting.Dictionary")
Set xlApp = CreateObject("Excel.Application")
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FolderExists(BOOK1) Then
MsgBox BOOK1 & " not found", vbCritical
Exit Sub
ElseIf objFSO.FolderExists(BOOK2) Then
MsgBox BOOK2 & " not found", vbCritical
Exit Sub
End If
Set objFSO = Nothing
Set xlWB = xlApp.Workbooks.Open(BOOK2)
With xlWB.Worksheets(1)
For Each r In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
If Not dict.Exists(r.Text) Then dict.Add r.Text, r.Offset(0, 1).Value
Next
End With
xlWB.Close False
Set xlWB = xlApp.Workbooks.Open(BOOK1)
With xlWB.Worksheets(1)
For Each r In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
If dict.Exists(r.Text) then
r.Offset(0, 1) = dict(r.Text)
Else
r.Offset(0, 1) = "#N/A"
End If
Next
End With
xlWB.Save
xlWB.Close False
xlApp.Quit
Msgbox BOOK1 & " has been updated"
End Sub
I can think of two ways to do this.
Create a system to organize your data into arrays, then use several simple algorithms to slide things into place. This would require parsing cell by cell to retrieve the data.
I prefer this method as it has potential to be quite abstract as a program in itself. I also highly suggest using arraylists if you do it.
Insert VLookup() functions into your Book1: Column B cells
I believe this would be more tedious...

Trying to create a key in registry database

I have done this code, but it seems that it dosen't work. I don't why. I have searched on google, but no luck. :(
Set objREG = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\default:StdRegProv")
Const HKEY_LOCAL_MACHINE = &H80000002
Dim lstrKeyPath, lstrValueName, lstrValue
lstrKeyPath = "SOFTWARE\Canon\GARO1\"
lstrValueName = "LocaleInfo"
objReg.GetStringValue HKEY_LOCAL_MACHINE,lstrKeyPath,lstrValueName,lstrValue
msgbox lstrValue <--- This works.
if IsNull(lstrValue) then
lstrKeyPath = lstrKeyPath & lstrValueName
else
lstrValueName = "LocaleTest"
lstrKeyPath = "Software\Test\"
Return = objReg.CreateKey(HKEY_LOCAL_MACHINE,lstrKeyPath)
if Return = 0 Then
msgbox "Yes"
else
msgbox "No"
end if
end if
Set OBJREG = Nothing
I can't see my "Test" key in the registry
I have used the following to check for and insert registry keys if they don't exist:
Dim WshShell, Test, blExists, DQ
Set WshShell = CreateObject("WScript.Shell")
DQ = chr(34)
RegKeyPath = "HKEY_CLASSES_ROOT\LFS\"
RegValueName = "URL:LFS Protocol"
Test = RegKeyExists(RegKeyPath,RegValueName)
If Test = False Then
WshShell.RegWrite RegKeyPath, "URL:LFS Protocol" ,"REG_SZ"
End If
'Function Returns False if the regkey isnt found otherwise it returns
'The registry key value specified
Function RegKeyExists(sRegKey,sRegValueName)
On Error Resume Next
Dim WSHShellRegTest, Test, blExists
Set WSHShellRegTest = CreateObject("WScript.Shell")
blTrueFalse = True
Test = WSHShellRegTest.RegRead (sregkey + sRegValueName)
If Err Then
RegKeyExists = False
Err.clear
Exit Function
End if
Set WSHShellRegTest = Nothing
RegKeyExists = Test
End Function

Excel and Word behaving difrerently in the same code

I have a problem - instances of Excel and Word behave differently in the same procedure. Have a look at the code. The idea there is to have a procedure that handles resaving files in excel and word in various format combinations.
The problem is that I notice that word and excel behave differently - the appWord and appExcel have different type names. At some point appWord is changed from Application to Object, which then makes it impossible to close it. I don't understand the differences in the behaviour, since the code applied to them is identical.
Option Explicit
Dim fso
Dim appWord
Dim appExcel
Set fso = CreateObject("Scripting.FileSystemObject")
startWord
ResaveFiles appWord.Documents, "docx", 12, 0
appWord.quit
startExcel
ResaveFiles appExcel.Workbooks, "xlsx", 51, 56
appExcel.quit
MsgBox "All done."
Sub ResaveFiles(appType, srcExtName, srcExtNum, tmpExtNum)
Dim objFile
Dim objOpenFile
Dim strDirectory
For Each objFile in fso.GetFolder(".").Files
If lcase(fso.GetExtensionName(objFile)) = srcExtName Then
If typeName(appType) = "Documents" Then StartWord
If typeName(appType) = "Workbooks" Then StartExcel
Set objOpenFile = appType.Open(objFile.path)
strDirectory = fso.BuildPath(objOpenFile.path, fso.GetBaseName(objOpenFile.name) & "._temp")
objOpenFile.SaveAs strDirectory, tmpExtNum
objOpenFile.Close
msgBox typename(appType) & objFile
msgBox typename(appWord) 'First typename test
msgBox Typename(appExcel)
If typeName(appType) = "Documents" Then appWord.Quit
If typeName(appType) = "Workbooks" Then appExcel.Quit
set objOpenFile = appType.Open(strDirectory)
objOpenFile.SaveAs objFile.path, srcExtNum
objOpenFile.Close
fso.DeleteFile(strDirectory)
msgBox typename(appWord) 'Second typename test
msgBox Typename(appExcel)
End If
Next
End Sub
'Start Word
Sub StartWord
Set appWord = CreateObject("Word.Application")
appWord.visible = false
appWord.DisplayAlerts = false
End Sub
'Start Excel
Sub StartExcel
Set appExcel = CreateObject("Excel.Application")
appExcel.visible = false
appExcel.DisplayAlerts = false
End Sub
I have tested it in the following way (with two typename tests) - when there are word files available, first appWord is Application and appExcel is empty, then it changes to Object and appExcel stays Empty (in this case we get an error when the subprocedure ends at AppWord.Quit). When there are no word files, and the script is processing Excels, first appWord is Object and appExcel is Application, then appWord is still Object and appExcel is still Application - in this case there are no errors when the subprocedure ends, on the appExcel.Quit.
Maybe i'm wrong, just my opinion:
If typeName(appType) = "Documents" Then appWord.Quit
If typeName(appType) = "Workbooks" Then appExcel.Quit
set objOpenFile = appType.Open(strDirectory)
appType is a reference to what appWord.Documents or appExcel.Workbooks are referencing before entering your ResaveFiles Sub, where you instantiate a new copy of 'Excel.Application' or 'Word.Application', and in each of the cases, you instruct the application TO QUIT. The question is not why in the case of word you got an error. From my point of view YOU SHOULD got an error. The question is why, if instructed to quit, excel keeps open and maintaining references to handle your code.
EDIT - And not tried. Just adapted from OP code. Adapt as needed
Option Explicit
ResaveFiles "Word.Application", "docx", 12, 0
ResaveFiles "Excel.Application", "xlsx", 51, 56
MsgBox "All done."
Sub ResaveFiles(progID, srcExtName, srcExtNum, tmpExtNum )
Dim app, doc
Dim fso, objFile, objOpenFile, strDirectory
Set fso = CreateObject("Scripting.FileSystemObject")
For Each objFile in fso.GetFolder( "." ).Files
If LCase(fso.GetExtensionName( objFile.Name )) = srcExtName Then
' Get references
Set app = GetNewAppInstance( progID )
Set doc = GetDocumentHandler( app )
' Save temp
Set objOpenFile = doc.Open( objFile.Path )
strDirectory = fso.BuildPath( objOpenFile.path, fso.GetBaseName(objOpenFile.name) & "._temp" )
objOpenFile.SaveAs strDirectory, tmpExtNum
objOpenFile.Close
' Release objects
Set objOpenFile = nothing
Set doc = nothing
app.Quit
Set app = nothing
' Get references again
Set app = GetNewAppInstance( progID )
Set doc = GetDocumentHandler( app )
' Resave file
Set objOpenFile = doc.Open( strDirectory )
objOpenFile.SaveAs objFile.path, srcExtNum
objOpenFile.Close
' Release objects
Set objOpenFile = nothing
Set doc = nothing
app.Quit
Set app = nothing
' Clean
fso.DeleteFile(strDirectory)
End If
Next
End Sub
Function GetNewAppInstance( ByVal progID )
Set GetNewAppInstance = CreateObject( progID )
With GetNewAppInstance
.Visible = False
.DisplayAlerts = False
End With
End Function
Function GetDocumentHandler( app )
Dim name
name = app.Name
If InStr(name,"Excel") > 0 Then
Set GetDocumentHandler = app.Workbooks
ElseIf InStr(name,"Word") > 0 Then
Set GetDocumentHandler = app.Documents
Else
Set GetDocumentHandler = app
End If
End Function

VBScript: way to check why the script stopped?

I have this VBScript which runs however, while it is processing, it will randomly stop and require a user to hit the spacebar for it to display the rest of its ongoing output.
How do I figure out why this is happening?
Here is a copy of the script:
'On Error Resume Next
Dim arrFolders()
intSize = 0
Function StampNow()
Dim Hr, Mn, Yr, Mon, Dy, Date1
Date1=Now()
Hr=DatePart("h",Date1)
Mn=DatePart("n",Date1)
Yr = DatePart("yyyy",Date1)
Mon = DatePart("m",Date1)
Dy = DatePart("d",Date1)
StampNow = Yr & "-" & Mon & "-" & Dy
end function
'Output log info.
Function OutputToLog (strToAdd)
Dim strDirectory,strFile,strText, objFile,objFolder,objTextFile,objFSO
strDirectory = "c:\log"
strFile = "\dpadmin_copy2run-"& StampNow & ".bat"
'strText = "dpadmin_copy2"
strText = strToAdd
' Create the File System Object.
Set objFSO = CreateObject("Scripting.FileSystemObject")
' Check that the strDirectory folder exists.
If objFSO.FolderExists(strDirectory) Then
Set objFolder = objFSO.GetFolder(strDirectory)
Else
Set objFolder = objFSO.CreateFolder(strDirectory)
'WScript.Echo "Just created " & strDirectory
End If
If objFSO.FileExists(strDirectory & strFile) Then
Set objFolder = objFSO.GetFolder(strDirectory)
Else
Set objFile = objFSO.CreateTextFile(strDirectory & strFile)
'Wscript.Echo "Just created " & strDirectory & strFile
End If
set objFile = nothing
set objFolder = nothing
' OpenTextFile Method needs a Const value
' ForAppending = 8 ForReading = 1, ForWriting = 2
Const ForAppending = 8
Set objTextFile = objFSO.OpenTextFile _
(strDirectory & strFile, ForAppending, True)
' Writes strText every time you run this VBScript.
objTextFile.WriteLine(strText)
objTextFile.Close
End Function
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
strFolderName = "D:\1\production\Openjobs"
Set colSubfolders = objWMIService.ExecQuery _
("Associators of {Win32_Directory.Name='" & strFolderName & "'} " _
& "Where AssocClass = Win32_Subdirectory " _
& "ResultRole = PartComponent")
dim diffindates
'Init vars for regex.
Dim retVal, retVal2
Dim Lastprop
Dim objRegExpr 'regex variable
Set objRegExpr = New regexp
Set objRegExprX31 = New regexp
objRegExpr.Pattern = "[0-9][0-9][0-9][0-9][0-9][0-9][A-Z][A-Z][A-Z]"
objRegExprX31.Pattern = "[0-9][0-9][0-9][0-9][0-9][0-9]X31"
objRegExpr.Global = True
objRegExprX31.Global = True
objRegExpr.IgnoreCase = True
objRegExprX31.IgnoreCase = True
'Variables for getting last accessed property.
Dim fs, f
Set fs = CreateObject("Scripting.FileSystemObject")
'Current time vars.
Dim currenttime
currenttime = Now()
ParentFolder = "D:\1\Production\Openjobs\ClosedJobs"
For Each objFolder in colSubfolders
intSize = intSize + 1
retVal = objRegExpr.Test(objFolder.Name)
retVal2 = objRegExprX31.Test(objFolder.Name)
if (retVal OR retVal2 ) then
'set filename to array
strFolderName = objFolder.Name
'Get last modified date.
Set f = fs.GetFolder(objFolder.Name)
Lastprop = f.DateLastModified
'MsgBox(Lastprop)
if ( DateDiff("m", f.DateLastModified, Now()) > 4) then
diffindates = DateDiff("m", f.DateLastModified, Now())
Set objShell = CreateObject("Shell.Application")
Set objCopyFolder = objShell.NameSpace(ParentFolder)
OutputToLog("rem " & f.DateLastModified & ":" & objFolder.Name )
outputtolog("move /Y """ & objFolder.Name & """ " & ParentFolder)
wscript.echo(diffindates & ":" & objFolder.Name & vbCr)
end if
end if
Next
Update
It stops at the line:
Set objTextFile = objFSO.OpenTextFile _
(strDirectory & strFile, ForAppending, True)
with the error Microsoft VBScript runtime error: Permission denied
I'm a little confusd by this. The logfile was only 356kb
I was able to run your script several times without it pausing for input. Run your script with the //X flag to start it in the debugger:
>cscript //nologo //X dpadmin_copy2.vbs"
You should be able to then step through the code.
You can also start putting in wscript.echo trace statements everywhere and see if you can narrow down what it's waiting on.
One thing that's gotten me in the past; If your command console is in QuickEdit mode and you accidentally click anywhere in the console window, the console will hang while it waits for you to press a key.
Well the first step is to remove any global On Error Resume Next statements. Better feedback would come if we could see the script.
You usually get an Permission denied when trying to write to a text file when the text file already has an open handle from some other process or because you have previously opened a handle earlier in you code which you have not closed. I haven't tried this but I don't know why this wouldn't work, you can look at using Handle from Sysinternals (Microsoft) to tell you what process has the open handle for the file. Please see here for a further reference of how to use Handle: http://www.orcsweb.com/blog/post/Closing-open-file-handles.aspx You could also write a second script which runs in a loop to monitor the main script. The second script can verify the first script by doing a WMI Process query which returns only processes that match a defined command line. The second script could then restart the main it stops, alert you, log a file, launch a handle search, etc.

Resources