Close all IE windows except 1 in VBA - vba

I'm using the following code to close all IE windows. This is part of error handling, when my larger function hangs or crashes, it automatically starts a new window. When that happens, I want to close all IE windows, except 1 (I want to keep that last one open to maintain the session, so the browser doesn't have to re-authenticate when it opens again).
Can I update the loop below so it closes all IE windows except for the last one (it doesn't matter which specific one it leaves open, just that it leaves one open).
Function closeallIE()
Dim objWMI As Object, objProcess As Object, objProcesses As Object
Set objWMI = GetObject("winmgmts://.")
Set objProcesses = objWMI.ExecQuery( _
"SELECT * FROM Win32_Process WHERE Name = 'iexplore.exe'")
For Each objProcess In objProcesses
Call objProcess.Terminate
Next
Set objProcesses = Nothing: Set objWMI = Nothing
Debug.Print wait(3)
End Function

You could use the Count property and use the PID with Taskkill:
Sub closeallIE()
Dim objWMI As Object, objProcess As Object, objProcesses As Object
Set objWMI = GetObject("winmgmts://.")
Set objProcesses = objWMI.ExecQuery( _
"SELECT * FROM Win32_Process WHERE Name = 'iexplore.exe'")
Dim j As Integer
j = objProcesses.Count
For Each objProcess In objProcesses
If j > 1 Then Shell "taskkill /f /PID " & CStr(objProcess.ProcessID), vbHide
j = j - 1
Next
Set objProcesses = Nothing
Set objWMI = Nothing
End Sub

This code snippet taken from HP UFT Website regarding closing browser tabs.
This works without any tweaks and uses creation time to close all tabs except the oldest by creation time.
On error resume next
Set oDesc = Description.Create
oDesc( "micclass" ).Value = "Browser"
oDesc( "application version" ).Value = browserPropertyApplicationVersion
Set vIE= Desktop.ChildObjects(oDesc)
vIECount=vIE.count
z=vIECount
For m=1To vIECount - 1
z=z-1
If Browser("creationtime:="&z).Exist(0) Then
Browser("creationtime:=1").Close
End If
If err.number > 0 Then
message = message & " #######Error shown by application is : " & err.description
icon_flag=0
End If
Next
Set oDesc = Nothing
Set vIE=Nothing

Related

VBA: save handle, open browser, do stuff, then close window?

Trying to programmatically open a browser from VBA (success) and then close it again using the handle (where I am stuck).
I found this post:
Access VBA to Close a Chrome window opened via Shell
but it does not seem to be working the way I expected. It opens each URL in a new window (and I would rather have all URLs opened in the same window. So I split the code up into two subroutines (see bottom of post).
I am passing the saved pHandle to "StopProcess", but the objLest.Count is always zero. What am I missing here? Thanks.
----------------------- 8< -----------------------------
Sub LaunchProcess(sCommandString, pHandle)
pHandle = Shell(sCommandString)
End Sub
and
Sub StopProcess(pHandle)
' Note: Shell pass the Process Handle to the PID variable
Dim objWMIcimv2 As Object
Dim objProcess As Object
Dim objList As Object
Dim ProcToTerminate As String
Dim intError As Integer
Set objWMIcimv2 = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\.\root\cimv2")
Set objList = objWMIcimv2.ExecQuery("select * from win32_process where Handle='" & CStr(pHandle) & "'")
'
' ObjList contains the list of all process matching the Handle (normally your chrome App, if running)
'
If objList.Count = 0 Then ' <---------- THIS is always 0 so it never closes anything
' No matching Process
' Set all objects to nothing
Set objWMIcimv2 = Nothing
Set objList = Nothing
Set objProcess = Nothing
Exit Sub
Else
'
' Parse all matching Processes
'
For Each objProcess In objList
' additionally check with actual user
colProperties = objProcess.getowner(strNameofUser, strUserdomain)
If strUserdomain + "\" + strNameofUser = Environ$("userdomain") + "\" + Environ$("username") Then
intError = objProcess.Terminate
If intError <> 0 Then
'
' Trap Error or do nothing if code run unattended
'
Else
' Confirm that process is killed or nothing if code run unattended
End If
End If
Next
Set objWMIcimv2 = Nothing
Set objList = Nothing
Set objProcess = Nothing
End If
End Sub

VBA objShell.windows.title not finding title

I run this function with two IE browsers open. IE_count finds six objects, but it does not find any titles (my_title) within the for loop for objShell. They all return an empty string.
Any idea as to why this could be? Relevant code below:
' code below adapted from ron's answer here: https://stackoverflow.com/questions/21407340/how-to-read-text-from-an-already-open-webpage-using-vba
Function SecondBrowserSearchForAndClick(ElementID As String, searchFor As String)
Dim objShell
Set objShell = CreateObject("Shell.Application")
Dim IE_count As Integer
IE_count = objShell.Windows.Count
Dim x As Integer
For x = 0 To (IE_count - 1)
On Error Resume Next ' sometimes more web pages are counted than are open
Dim my_url As String
my_url = objShell.Windows(x).document.Location
Dim my_title As String
my_title = objShell.Windows(x).document.Title
If my_title Like "*Select Process*" Then 'compare to find if the desired web page is already open
Dim tagColl_TR As Object
Set tagColl_TR = objShell.Windows(x).document.getElementById(ElementID).contentDocument.getElementsByTagName("tr")
Dim f
While f < tagColl_TR.Length
If tagColl_TR(f).Children.Length = 5 Then
If tagColl_TR(f).Children(3).Children(0).innerText Like "*" & searchFor & "*" Then
tagColl_TR(f).Children(1).Children(0).Children(1).Focus
tagColl_TR(f).Children(1).Children(0).Children(1).Click
Exit Function
End If
End If
f = f + 1
Wend
End If
Next
End Function
Any help would be appreciated.
It's easier to put the "find document by title" functionality in its own function:
Sub Tester()
Dim doc As Object
Set doc = IEDocumentByTitle("Google")
If Not doc Is Nothing Then
Debug.Print "Found window at: " & doc.Location
'work on doc here
End If
End Sub
'Return an open IE document based on its Title property
Function IEDocumentByTitle(title As String)
Dim w As Object, ttl As String
For Each w In CreateObject("Shell.Application").Windows
If w.Application.Name = "Internet Explorer" Then 'filter out Windows Explorer
ttl = ""
On Error Resume Next
ttl = w.document.title
On Error GoTo 0
If ttl Like title Then
Set IEDocumentByTitle = w.document
Exit Function
End If
End If
Next w
End Function
This works fine for me.
BTW the shell Windows collection also includes Windows Explorer instances in addition to IE windows/tabs.
Also you should really cancel On Error Resume Next as soon as possible or it will silently swallow all errors in your code, possibly leading to unexpected results.

Tackle the 'Not responding application outside of Microsoft Access' error in the calling Access VBA

I am using the ScriptControl in Access VBA to load the scripts (.vbs files) and execute them for extracting data from a SAP system. For the small data the code works fine.
However, when there is a big data which takes time or stops responding then Access opens a popup window asking me to switch to the app or retry. If I click on retry button or by hand switch to that window, then the script resumes!
Is there any way to tackle this access popup window or a code to press this retry button? Thanks
Mycode:
Open scriptPath For Input As #1
vbsCode = Input$(LOF(1), 1)
Close #1
On Error GoTo ERR_VBS
With CreateObject("ScriptControl")
.Language = "VBScript"
.AddCode vbsCode '>>>>>>>>>>>>>>>> I get this popup window at this line
End With
Tried :
Sub Test()
Dim oSC As Object
Set oSC = CreateObjectx86("ScriptControl") ' create ActiveX via x86 mshta host
Debug.Print TypeName(oSC) ' ScriptControl
' do some stuff
CreateObjectx86 Empty ' close mshta host window at the end
End Sub
Function CreateObjectx86(sProgID)
Static oWnd As Object
Dim bRunning As Boolean
Dim vbsCode As String, result As Variant, Script As Object
Open "\My Documents\\Desktop\x.vbs" For Input As #1
vbsCode = Input$(LOF(1), 1)
Close #1
Set oWnd = CreateWindow()
oWnd.execScript vbsCode, "VBScript" '>>>>>>>>>Gets an Error says "Error on Script page"
Set CreateObjectx86 = oWnd.CreateObjectx86(sProgID)
End Function
Function CreateWindow()
' source http://forum.script-coding.com/viewtopic.php?pid=75356#p75356
Dim sSignature, oShellWnd, oProc
On Error Resume Next
Do Until Len(sSignature) = 32
sSignature = sSignature & Hex(Int(Rnd * 16))
Loop
CreateObject("WScript.Shell").Run "%systemroot%\syswow64\mshta.exe about:""<head><script>moveTo(-32000,-32000);document.title='x86Host'</script><hta:application showintaskbar=no /><object id='shell' classid='clsid:8856F961-340A-11D0-A96B-00C04FD705A2'><param name=RegisterAsBrowser value=1></object><script>shell.putproperty('" & sSignature & "',document.parentWindow);</script></head>""", 0, False
Do
For Each oShellWnd In CreateObject("Shell.Application").Windows
Set CreateWindow = oShellWnd.GetProperty(sSignature)
If Err.Number = 0 Then Exit Function
Err.Clear
Next
Loop
End Function
So after lot of headache, I found the solution! The solution is to use waitToReturn. This will make Access VBA wait for the Script to be completed no matter how long it take! Hence, this tackled the problem of Access popup window asking to switch to window or Retry!
Solution code:
Dim wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 1
Dim errorCode As Integer
errorCode = wsh.Run("C:\path\x.vbs", windowStyle, waitOnReturn)
If errorCode = 0 Then
MsgBox "Script successful. "
Else
MsgBox "Script exited with error code " & errorCode & "."
End If
with cases like this you would always try to get the focus via the object you are manipulating, usually it is done by .setFocus or .active.
the below is code that will help you out. I would try the session.setFocus.
Session.ActiveWindow.SetFocus
the below code will also help:
Dim SapGuiAuto As Object
Dim Application As SAPFEWSELib.GuiApplication
Dim Connection As SAPFEWSELib.GuiConnection
Dim Session As SAPFEWSELib.GuiSession
Dim UserArea As SAPFEWSELib.GuiUserArea
' Dim oWindow As SAPFEWSELib.GuiConnection
Dim oUserAreaOfMobileWindow As SAPFEWSELib.GuiUserArea
Dim oGuiSimpleContainer As SAPFEWSELib.GuiSimpleContainer
Set SapGuiAuto = GetObject("SAPGUI")
If Not IsObject(SapGuiAuto) Then
Exit Sub
End If
Set Application = SapGuiAuto.GetScriptingEngine()
If Not IsObject(Application) Then
Exit Sub
End If
Set Connection = Application.Connections(0)
If Not IsObject(Connection) Then
Exit Sub
End If
Set Session = Connection.Sessions(0)
If Not IsObject(Session) Then
Exit Sub
End If

AdvancedInstaller - Custom Action VBScript - Property not passed through

I am currently facing an issue when trying to set a public variable through an VBscript in an Custom Action.
Its regarding the Property "MYDOMAIN".
No matter what I am doing, the value is always 0.
Even setting an ";" after (example) Session.Property("MYDOMAIN")="1" does not solve the issue.
When the VBScript is executed locally the value can be retrieved (at least in the variable).
Please find my script below:
'~~~ Query My Domain
Option Explicit
'On Error Resume Next
Dim objWMISvc : Set objWMISvc = GetObject( "winmgmts:\\.\root\cimv2" )
Dim colItems : Set colItems = objWMISvc.ExecQuery( "Select * from Win32_ComputerSystem" )
Dim objSysInfo : Set objSysInfo = CreateObject("ADSystemInfo")
Dim objComp : Set objComp = GetObject("LDAP://" & objSysInfo.ComputerName)
Dim objCompDN : objCompDN = objComp.distinguishedName
Dim objItem
Dim strComputerDomain
Dim Session
For Each objItem in colItems
strComputerDomain = objItem.Domain
' If objItem.PartOfDomain Then
' WScript.Echo "Computer Domain: " & strComputerDomain
' Wscript.Echo "Computername: " & strComputerName
' End If
Next
If strComputerDomain = "DOMAIN1.loc" Then
Session.Property("MYDOMAIN")="1"
elseif strComputerDomain = "DOMAIN2.loc" Then
call CheckIRL(objCompDN,"(?:Division-)(8[0-9]\d{1,2}|982)-")
elseif strComputerDomain = "DOMAIN3.loc" Then
Session.Property("MYDOMAIN")="3"
Else
if strComputerDomain = "" then
Session.Property("MYDOMAIN")="0"
End if
End if
Sub CheckIRL(strReturnValue, strPattern)
Dim objRegEx : set objRegex = new RegExp
objRegex.pattern = strPattern
objRegex.global = true
If objRegex.Test( strReturnValue ) Then
Session.Property("MYDOMAIN") = "6"
Else
Session.Property("MYDOMAIN") = "7"
End If
End Sub
Sub CheckSLO(strReturnValue, strPattern)
Dim objRegEx : set objRegex = new RegExp
objRegex.pattern = strPattern
objRegex.global = true
If objRegex.Test( strReturnValue ) Then
Session.Property("MYDOMAIN") = "4"
Else
Session.Property("MYDOMAIN") = "5"
End If
End Sub
To be honest: I am out of ideas...
A friend inserted the script into an InstallShield project and the Property could be resolved. Any idea is appreciated :)
I would recommend you trying to debug your VBS action code by inserting a message box (MsgBox function) in each of your IF block of your VBS code. This is just to make sure your VBS code do indeed set the related property to a value different than 0 before it exits.
Just use a MsgBox statement like this:
MsgBox Session.Property("MYDOMAIN")
to display the property value.
Then if the VBS do indeed set the property to a value different than 0 before exiting, in this case we will need more details about the exact execution sequence when the property is reverted back to 0.
I will give this a try and will come back to you once checked.
In the meantime I created a second msi file to do the config...not the best solution but it seems to work :)

VBA - Unable to map drive to sharepoint on another computer

I'm mapping to the company's sharepoint drive using VBA. The intention is to save local file to sharepoint, and delete local file and unmapped the drive after success.
On my machine(Windows 10 64bits), the code works perfectly fine, successfully mapped the drive, created folder and file, successfully uploaded to sharepoint and unmap the drive.
However, when I run the same excel workbook that contains the same code on my colleague's computer(Window 7), it failed. There's no error being shown, except that it keeps on loading and loading until Excel Not Responsive. I tried manually mapping the drive, it success.
I tried to debug and found out that the code stops (keeps on loading) at MsgBox "Hello" but could not figure out what's missing.
Both are using Excel 2016
Any help and suggestions are appreciated. let me know if more info is needed. Thanks in advance.
This is my vba code
Sub imgClicked()
Dim fileName As String
Dim SharePointLib As String
Dim MyPath As String
Dim folderPath As String
Dim objNet As Object
Dim copyPath As String
Dim copyFilePath As String
folderPath = Application.ThisWorkbook.path
MyPath = Application.ThisWorkbook.FullName
Dim objFSO As Object
Dim strMappedDriveLetter As String
Dim strPath As String
Dim spPath As String
strPath = "https://company.com/sites/test/test 123/" 'example path
spPath = AvailableDriveLetter + ":\test.xlsm" 'example path
copyPath = folderPath + "\copyPath\"
'Add reference if missing
Call AddReference
Set objFSO = CreateObject("Scripting.FileSystemObject")
With objFSO
strMappedDriveLetter = IsAlreadyMapped(.GetParentFolderName(strPath))
If Not Len(strMappedDriveLetter) > 0 Then
strMappedDriveLetter = AvailableDriveLetter
If Not MapDrive(strMappedDriveLetter, .GetParentFolderName(strPath)) Then
MsgBox "Failed to map SharePoint directory", vbInformation, "Drive Mapping Failure"
Exit Sub
End If
End If
' Check file/folder path If statement here
End With
Set objFSO = Nothing
End Sub
Code for getting available drive
' Returns the available drive letter starting from Z
Public Function AvailableDriveLetter() As String
' Returns the last available (unmapped) drive letter, working backwards from Z:
Dim objFSO As Object
Dim i As Long
Set objFSO = CreateObject("Scripting.FileSystemObject")
For i = Asc("Z") To Asc("A") Step -1
Select Case objFSO.DriveExists(Chr(i))
Case True
Case False
Select Case Chr(i)
Case "C", "D" ' Not actually necessary - .DriveExists should return True anyway...
Case Else
AvailableDriveLetter = Chr(i)
Exit For
End Select
End Select
Next i
Set objFSO = Nothing
MsgBox "This is the next available drive: " + AvailableDriveLetter ' returns Z drive
MsgBox "Hello" ' After this msgBox, starts loading until Not Responsive
End Function
Function to Map drive
Public Function MapDrive(strDriveLetter As String, strDrivePath As String) As Boolean
Dim objNetwork As Object
If Len(IsAlreadyMapped(strDrivePath)) > 0 Then Exit Function
Set objNetwork = CreateObject("WScript.Network")
objNetwork.MapNetworkDrive strDriveLetter & ":", strDrivePath, False
MapDrive = True
MsgBox "Successfully Created the Drive!"
Set objNetwork = Nothing
End Function
Code for MappedDrive
Public Function GetMappedDrives() As Variant
' Returns a 2-D array of (1) drive letters and (2) network paths of all mapped drives on the users machine
Dim objFSO As Object
Dim objDrive As Object
Dim arrMappedDrives() As Variant
Dim i As Long
Set objFSO = CreateObject("Scripting.FileSystemObject")
ReDim arrMappedDrives(1 To 2, 1 To 1)
For i = Asc("A") To Asc("Z")
If objFSO.DriveExists(Chr(i)) Then
Set objDrive = objFSO.GetDrive(Chr(i))
If Not IsEmpty(arrMappedDrives(1, UBound(arrMappedDrives, 2))) Then
ReDim Preserve arrMappedDrives(1 To 2, 1 To UBound(arrMappedDrives, 2) + 1)
End If
arrMappedDrives(1, UBound(arrMappedDrives, 2)) = Chr(i) ' Could also use objDrive.DriveLetter...
arrMappedDrives(2, UBound(arrMappedDrives, 2)) = objDrive.ShareName
End If
Next i
GetMappedDrives = arrMappedDrives
Set objDrive = Nothing
Set objFSO = Nothing
End Function
Public Function IsAlreadyMapped(strPath As String) As String
' Tests if a given network path is already mapped on the users machine
' (Returns corresponding drive letter or ZLS if not found)
Dim strMappedDrives() As Variant
Dim i As Long
strMappedDrives = GetMappedDrives
For i = LBound(strMappedDrives, 2) To UBound(strMappedDrives, 2)
If LCase(strMappedDrives(2, i)) Like LCase(strPath) Then
IsAlreadyMapped = strMappedDrives(1, i)
Exit For
End If
Next i
Set objNetwork = Nothing
End Function
Add Reference
Sub AddReference()
'Macro purpose: To add a reference to the project using the GUID for the
'reference library
Dim strGUID As String, theRef As Variant, i As Long
'Update the GUID you need below.
strGUID = "{420B2830-E718-11CF-893D-00A0C9054228}"
'Set to continue in case of error
On Error Resume Next
'Remove any missing references
For i = ThisWorkbook.VBProject.References.Count To 1 Step -1
Set theRef = ThisWorkbook.VBProject.References.Item(i)
If theRef.isbroken = True Then
ThisWorkbook.VBProject.References.Remove theRef
End If
Next i
'Clear any errors so that error trapping for GUID additions can be evaluated
Err.Clear
'Add the reference
ThisWorkbook.VBProject.References.AddFromGuid _
GUID:=strGUID, Major:=1, Minor:=0
'If an error was encountered, inform the user
Select Case Err.Number
Case Is = 32813
'Reference already in use. No action necessary
Case Is = vbNullString
'Reference added without issue
Case Else
'An unknown error was encountered, so alert the user
MsgBox "A problem was encountered trying to" & vbNewLine _
& "add or remove a reference in this file" & vbNewLine & "Please check the " _
& "references in your VBA project!", vbCritical + vbOKOnly, "Error!"
End Select
On Error GoTo 0
End Sub
Procedure imgClicked is calling function AvailableDriveLetter multiple times. Remember that the function has to execute each time you refer to it.
I ran imgClicked (assuming that's the procedure you start with) and I was told, twice, "Next available letter = Z" and "Hello" and then it crashed Excel (perhaps getting stuck in a loop of creating FileSystem objects to look for an available drive letter?)
Try assigning AvailableDriveLetter to a variable (string) at the beginning of the procedure and referring to the variable each time you need the value, and see if you still have the issue.
(Remember to save before execution -- I get frustrated when troubleshooting "application hanging" issues because I keep forgetting to save my changes and then lose them on the crash!)
If this doesn't work, add a breakpoint (F9) on the End Function line after your "Hello" box and see if the code stops there. (I have trouble believing the MsgBox or End Function are the culprit.) If not, which procedure runs after that?
One more thing whether the issue is resolved or not:
Add Option Explicit at the very beginning of your module and then Compile the project and fix your missing variable declaration(s).
This is recommended whenever troubleshooting an issue as a means to eliminate variable declaration issues as a possible cause.