Close Open Excel Instance - vbscript

Could someone please let me know if the following simple VBScript is correct?
It is supposed to close Excel after other processes have run (and left Excel open), but it doesn't work.
Set MyApp = CreateObject("Excel.Application")
MyApp.Quit

CreateObject creates a new object. If I understand your question correctly you want to attach to already running (orphaned) Excel processes to terminate them. You can do that with GetObject:
On Error Resume Next
Do
Set xl = GetObject(, "Excel.Application")
status = Err.Number
If status = 0 Then
For Each wb in xl.Workbooks
wb.Close False 'discard changes in open workbooks
Next
xl.Quit
ElseIf status <> 429 Then
WScript.Echo Err.Number & ": " & Err.Description
WScript.Quit 1
End If
Until status = 429
On Error Goto 0
Note that this will try to close all running Excel instances, discarding all changes in open workbooks. If you want it to save changes in open workbooks change the argument of the Close method to True. If you have Excel instances you want to keep running, you need to add code to exclude them from being closed.
Note also, that this will not forcibly terminate unresponsive instances. You'd need to kill the process for that:
Set wmi = GetObject("winmgmts://root/cimv2")
For Each xl In wmi.ExecQuery("SELECT * FROM Win32_Process WHERE Name = 'excel.exe'")
xl.Terminate
Next

Try this please.
ThisWorkbook.Saved = True
Application.Quit

CreateObject creates a COM object, so your
Set MyApp = CreateObject("Excel.Application")
starts a new Excel process. Use GetObject to "retrieve an existing object with the specified ProgID". See this for theory and praxis.

Related

Is it possible to hide an error message generated by VBS script?

I have a customisation on an application that opens the comport to start reading data from the GPS. Now that I am using a Bluetooth GPS receiver the port doesn't always open the first time. If it fails it give the message "Error 121 when attempting to open communications port COM(comport number):"
Now when it does this I can check to see if the command worked, and if it didn't fire it again... (see code for the button below) However it displays an error.
This mimics what happens when you do it manually... sometimes it takes the Bluetooth stack multiple tries to connect to the GPS... It doesn't display an error though...
Anyway, it works, but it would be great to not show the error message on the times where the comport doesn't open...
Any and all suggestions are welcome, and appreciated.
Notes:
-The program is working without problems on everything but new units which have to use the Microsoft Bluetooth stack.
-While this error is annoying, the system is otherwise working, and when the Bluetooth connection is made after 1-3 attempts, all is well...
-Before I added "On Error Resume Next" the process would stop whenever the connection didn't get made.
Sub subGPSOnOffButton
'turns the GPS and tracklog on (or off) from a custom button...
'if the gps is on, make sure the user wants it off...
'if the gps is off, turn it on, and tell the user when done.
Dim iRes
If Application.GPS.IsOpen = True Then
iRes = msgbox("GPS is already on!" & vbnewline & vbnewline & "Turn it off?", vbYesNo, "GPS Active:")
If iRes = 6 then
Application.GPS.Close()
Else
Exit Sub
End if
Else
subGPSOn
msgbox "GPS is now on!", vbOKOnly, "GPS Active:"
End If
End Sub
Sub subGPSOn
On Error Resume Next
Do While Application.GPS.IsOpen = False
' Turn the GPS on
Application.GPS.Open()
Loop
' Turn the tracklog on
Application.ExecuteCommand("gpstracklog")
End Sub

Test Complete Automation - Issue with waiting for an object to load

Background:
I have a JAVA application on which we run our Test Complete scripts(We have recently moved from UFT to TestComplete, so TC is a bit new for us). The scripting language used is VBScript.
Issue:
In order to handle the slow application behavior, I have created a function which waits for an object to get loaded and become visible on the screen before any operation is performed on that object. But, at times, the function does not work. By this, I mean that even though the object is loaded and is visible on the screen, the function still keeps on waiting for the object i.e., uiObject.exists keeps on returning false due to which it keeps on waiting until the timeout value is reached. Has someone here faced this issue before?
Paramter values passed:
uiObject = Aliases.ParentObj.Login_Window
intMaxTimeOut = 120
Code
'============================================================================================================
'Function Name: fn_waitForObject
'Purpose: To wait for an object to exist and become visible on screen
'Creation Date: 04-06-2018
'Return type: true, if the object exists and is visible; false, if the object doesn't exist
'Parameters: uiObject - The object for which the script waits to get visible on screen
' intMaxTimeOut - Maximum timeout in seconds
'============================================================================================================
function fn_waitForObject(uiObject,intMaxTimeOut)
Dim intCounter : intCounter = 0
Do While (intCounter < intMaxTimeOut)
If uiObject.exists then
Exit Do
Else
intCounter = intCounter + 1
delay 1000
End If
Loop
'If the object exists, make sure that it is visible on screen
If uiObject.exists then
Do While (intCounter < intMaxTimeOut)
If uiObject.visibleonscreen then
Log.Message "The object """&uiObject.toString&""" exists and is visible on screen"
Exit Do
Else
intCounter = intCounter + 1
delay 1000
End If
Loop
End If
fn_waitForObject = uiObject.visibleonscreen
End Function
Object Spy
Maybe the information on this link can help you!
whats is the difference between UIObject and UIObject2 other than UIAutomator 2.0 version name?
What is the actual error saying in TC?
Have you seen this link? https://support.smartbear.com/testcomplete/docs/app-objects/common-tasks/waiting-process-or-window-activation.html
I would also suggest trying to use the record keyword test, then convert it to script
For now you could increase your max timeout value, but your while loop will still have a hard upper limit. I recommend using one of the methods listed in the article above, as they will make TestComplete wait until your process/objects have fully loaded, no matter how much time has passed. That way, you won't run into your current problem anymore.
It is the Name Mapping creating a 2nd version of the same object.
Go into the Name Mapping and edit the properties to only use static properties, so new versions of the same UIObject are not being created.

VB6 ADODB.Connection Execute() Retry until successful

I'm trying to fix a little utility which seems to be losing connection to the database after some idle time. I already set the timeout to 0 but that didn't seem to work.
Instead of simply crashing and displaying a couple of error messages I would like to try to re-establish the connection and execute the query until successful (I realize this is probably a bad use of resources) but even then that's what I'm trying to accomplish here. Or if possible display a Message Box saying that connection was lost which will then be closed once connection is established.
Any suggestions would be greatly appreciated.
Public connMain As ADODB.Connection
Public rsMain As ADODB.Recordset
......
Function Picture_Exists() As Boolean
On Error Resume Next
sqlstr = "select * .... "
Set rsMain = connMain.Execute(sqlstr)
Your connection is probably being dropped at the database end due to non-use. It isn't good practice to maintain a connection when it isn't being used; connections are expensive in terms of resources so any such practice wouldn't scale well. Dbadmins aren't likely to leave unused connections open for very long.
Your potential solution says to try to connect and if you can't ignore the error. We don't say "never" in this business very often, but you should never use "On Error Resume Next" without also evaluating Err.Number to see whether it equals 0 (if it does, there's no error). This is called "inline error handling."
In any case, I wouldn't use this method. I would evaluate the Connection object's State Property, and if it's closed (cn.State = adoStateClosed) then I would reopen it.
You can try the following:
On Error Resume ''''instead of On Error Resume Next
Dim rsMain As New ADODB.Recordset
sqlstr = "select * .... "
If rsMain.State = adStateOpen Then rsMain.Close
rsMain.Open sqlstr, sProvider, adOpenKeyset, adLockOptimistic

VBScript alternative of PHP's debug_backtrace

I have an old VBScript project I need to debug and due to it's complexity I cannot see where are some functions being called from. Is there any VBScript alternative to PHP's debug_backtrace function or similar to see the stack trace?
So at this point, after a lot of searching, I am going to answer my own question as follows: VBScript is relatively old language and does not seem to have any built-in function/method or other means which would reliably return stack trace of function call (similar to PHP's debug_backtrace() function.
I managed to track the execution path with a simple, custom Function logBreakPointToFile() which I wrote and I placed throughout 100s of .asp files (everywhere where the method in question was referenced directly and indirectly - nested). This gave me a very messy idea what was actually happening. However is cost me a lot of prep. time and clean-up time which I was trying to avoid in the first place.
If anyone finds a better solution, please share.
Thx
VBScript does not throw any exception with stacktrace information in case of error.
#Runtime, in case of error, VBScript throws an Err object.
Ex: Below script will throw 'Division by zero' error & script will not get executed further.
Msgbox 5/0
Msgbox "Hello" 'This will not execute
On Error:
VBScript uses 'On Error Resume Next' statement which starts the error handler. It means, in case of error just skip current line and goto the next line. 'On Error GoTo 0' disables the current error handler. (like you are closing an 'if' block). Please check MSDN for more details.
Consider this example.
On Error Resume Next
Msgbox 5/0
Msgbox "Hello" 'This will say "Hello"
Msgbox Err.Number '11
Msgbox err.Description 'division by zero
On Error GoTo 0 'stops the error handler. any run time error after this will stop the program
Err.Number will be 0 in case no error is found.
So, You can have function like
Function Divide(ByVal A, ByVal B)
On Error Resume Next
Dim Result
Result = A/B
If Err.Number = 0 Then
Divide = Result
Else
Divide = "Infinite"
End If
On Error GoTo 0
End function
Remember this - as it simply goes to the next line in case of error,
On Error Resume Next
If 5/0 Then
Msgbox "???" 'This will get executed. It does not go to Else
Else
Msgbox "Hello" 'It will not show this
End If
On Error GoTo 0
You need to configure IIS to send errors to the browser. Its under Classic ASP settings on IIS 7 - 8. You have the option to send errors to browser on local requests, or all requests. For testing on a dev box usually its set for local. It will tell you what line number you are erroring out on.
As for getting more detail on what functions are slowing your application down. With classic asp you need to write your own timing code to measure such metrics.

Visio automation: get process ID

I'm running Visio using automation and I'm having trouble getting the process ID of the Visio process to check when its complete. Here's my VB script:
Set visio = CreateObject("Visio.InvisibleApp")
Wscript.Echo visio.ProcessID
Set document = visio.Documents.OpenEx("somefile.vsd", &H88)
document.ExportAsFixedFormat 1, "somefile.pdf", 1, 0
visio.Quit
and running it with cscript // nologo.
The problem is that visio.ProcessID returns a number that isn't the actual Windows process ID (e.g. 6613 when the actual process ID is 8146). The cscript host seems to finish before the Visio process exits causing problems cleaning up temp files.
Here is the Visio reference notes for:
ProcessID
Quit
So the question is: how can I get the Visio process ID or detect when it has properly exited?
Thanks!
Just noticed this in the help for Visio.Application.ProcessID:
"The value returned by ProcessID is not the same as the Windows Process ID of the current Visio instance."
So I guess these are just so you can distinguish between multiple instances of Visio.
There are also Visio.Application.WindowHandle32 and Visio.Application.WindowHandle, which might be helpful, although maybe not so much for an invisible app instance.
Can't see how this id would help you. I suspect you get an error in visio. Have you tried with
on error resume next
and after each line that could give an error
if err.number <> 0 then
wscript.echo err.description
err.clear
end if
There seems to be an issue if you omit parameters, so use them all.
See http://msdn.microsoft.com/en-us/library/office/ms409271(v=office.12).aspx for the values.
Before quiting use document.saved = true, you could check first if the result file exists.
EDIT: check if a process is running, could be you have to adapt the name of the service (check your téaskmanager)
set service = GetObject ("winmgmts:")
for each Process in Service.InstancesOf ("Win32_Process")
If lcase(Process.Name) = "visio.exe" then
wscript.echo "visio still running"
wscript.quit
End If
next
wscript.echo "visio no longer running"
EDIT2: to get the processid of the active visio app (If more than one Visio instance is running, GetObject returns the active instance. When a program is run as an add-on or by double-clicking a shape, the active instance is the one that the program was run from. Otherwise, it is the instance that was most recently run or brought to the front. If no Visio instance is running, GetObject causes an error)
cfr http://webmail.vh.com.tw/Microsoft/Developing%20Microsoft%20Visio%20Solutions/27.htm
set appObj = GetObject(, "visio.application")
if appObj Is Nothing Then
wscript.echo "There is no active Visio."
else
wscript.echo "ProcessID: " & appObj.ProcessID
end if

Resources