Get an active IE window by partial URL - vba

I currently am running some VBA to navigate an intranet site, perform some actions, etc. I have completed the actions I need to take, and now I have 2 IE windows open. One window, my original, I want to remain open. The second window, I want to close.
I have been having issues closing the second window. Using simple SendKeys "%{F4}" doesn't close the window at all, although it would if I did the steps manually rather than through VBA. Also, ieApp.Quit keeps closing the first IE window, which I want to remain open to use again. Which is strange because it isn't the active window at the time.
My question is...is there a way to find/select an open IE window based on a partial URL? I know the URL will start with http://ctdayppv02/PVEShowDocPopup.aspx? but everything after that will change each time.
I've seen plenty online about launching IE with a URL, or returning the URL of an already open IE instance, but I'm not trying to do either of those at this point. I just want to activate a specific open IE window, so then I can close that one only.
Here is part of my code, which isn't closing anything as of now, but also doesn't result in any errors. It's the very last part that doesn't work, everything else is good.:
'***** Click the Search button *****
ieApp.Document.all.Item("btnSubmitProjectSearch").Click: DoEvents: Sleep 1000
'***** Click the Print button *****
ieApp.Document.all.Item("printLink").Click: DoEvents: Sleep 1000
'***** Setting variables for Windows API. Will be used to find the proper windows box by name *****
Dim windowHWND As LongPtr
Dim buttonHWND As LongPtr
Dim hwnd As String
Dim hwindow2 As String
''***** Will click the Print button. MUST HAVE MICROSOFT PDF AS DEFAULT PRINTER *****
windowHWND = getWindowPointer("Print", "#32770")
If windowHWND > 0 Then
'***** Add a small delay to allow the window to finish rendering if needed *****
Sleep 250
buttonHWND = FindWindowEx(windowHWND, 0, "Button", "&Print")
If buttonHWND > 0 Then
SendMessage buttonHWND, BM_CLICK, 0, 0
Else
Debug.Print "didn't find button!"
End If
End If
'***** Locate the "Save Print Output As" window, enter the filepath/filename and press ENTER *****
hwnd = FindWindow(vbNullString, "Save Print Output As")
Do
DoEvents
hwindow2 = FindWindow(vbNullString, "Save Print Output As")
Loop Until hwindow2 > 0
SendKeys "C:\Users\NAME\Documents\" & Range("G2").Value
SendKeys "{ENTER}"
'***** Locate the Viewer Control box that appears after saving and press ENTER to advance *****
hwnd = FindWindow(vbNullString, "PaperVision Document Viewer Control")
Do
DoEvents
hwindow2 = FindWindow(vbNullString, "PaperVision Document Viewer Control")
Loop Until hwindow2 > 0
SendKeys "{Enter}"
'***** Locate the "PaperVision - View Document" IE window and close it *****
hwnd = FindWindow(vbNullString, "PaperVision - View Document - Internet Explorer")
Do
DoEvents
hwindow2 = FindWindow(vbNullString, "PaperVision - View Document - Internet Explorer")
Loop Until hwindow2 > 0
'ieApp.Quit
SendKeys "%{F4}"
Any advice on how to close just that one page? Thanks in advance!

As per the first suggestion by QHarr, try...
Option Explicit
Sub test()
Dim oShell As Object
Dim oShellWindows As Object
Dim oShellWindow As Object
Dim sPartialURL As String
sPartialURL = "http://ctdayppv02/PVEShowDocPopup.aspx?"
Set oShell = CreateObject("Shell.Application")
Set oShellWindows = oShell.Windows
For Each oShellWindow In oShellWindows
If oShellWindow.Name = "Internet Explorer" Then
If InStr(oShellWindow.Document.URL, sPartialURL) > 0 Then
Exit For
End If
End If
Next oShellWindow
If Not oShellWindow Is Nothing Then
'Do stuff
'
'
oShellWindow.Quit
Else
MsgBox "The specified Internet Explorer window was not found!", vbExclamation
End If
Set oShell = Nothing
Set oShellWindows = Nothing
Set oShellWindow = Nothing
End Sub

I like Domenic's response more, but I wanted to post another way I came across online for anybody who may be looking at this down the road and wants another method.
This way uses a function that is called in the primary sub. The "View Document" is the wording that appears in the IE window caption, NOT in the URL. This will close any IE that contains that specific phrase somewhere in the window caption. I only tested this a few times but it seems to work.
Sub CloseWindow()
Do Until Not CloseIeIf("View Document"): Loop
End Sub
Function CloseIeIf(Str As String) As Boolean
Dim ie As Object
For Each ie In CreateObject("Shell.Application").Windows
If InStr(ie.LocationName, Str) <> 0 Then
ie.Quit
CloseIeIf = True
End If
Next
End Function

Related

Bring Internet Explorer Download Window to Focus - Foreground via VBA

I've got a macro which currently works but I'm trying to automate the final "quirk" that I have had to live with up till now. Basically it opens IE to a URL which then closes the window and spits back a download window and I have excel use SENDKEYS to download file.
I'm struggling to bring the download window to focus, currently my end users click on the DL window for sendkeys to work as expected.
I have read through the following and tried utilizing the code to no avail:
vbscript - Bring Internet Explorer Application window to front
VBA to Activate Internet Explorer Window
Bringing Internet Explorer window to foreground
Set Focus to Internet Explorer Object in Visual Basic
There a few things to note:
I can't download the file via batch as I need IE to pass along the credentials.
The file is not static, the URL runs a script on the backend and then presents the file back to end terminal
I can't have any requirement to "Enable Reference Library" on end users computers
The macro is as follows:
Public Sub DLFILE()
'This will load a webpage in IE
Dim i As Long
Dim URL As String
Dim ie As Object
Dim objElement As Object
Dim objCollection As Object
'Create InternetExplorer Object
Set ie = CreateObject("InternetExplorer.Application")
'Define URL
URL = "http://example.com/"
'Navigate to URL
ie.navigate URL
' Statusbar let's user know website is loading
Application.StatusBar = URL & " is loading. Please wait..."
'IE ReadyState = 4 signifies the webpage has loaded (the first loop is set to avoid inadvertently skipping over the second loop)
Do While ie.ReadyState = 4: DoEvents: Loop 'Do While
Application.Wait (Now() + TimeValue("00:00:04"))
SendKeys "{RIGHT}{RIGHT}{ENTER}{TAB}{TAB}{TAB}{TAB}{ENTER}"
'Do Until IE.ReadyState = 4: DoEvents: Loop 'Do Until
'Unload IE
Set ie = Nothing
Set objElement = Nothing
Set objCollection = Nothing
End Sub
Also note, this doesn't bring up the prompt in the bottom of the IE window, but closes that window and brings up the "Full Downloads Window" like below.
As the shortcut for the "View Downloads" window is Ctrl+J in IE so I think we can use sendkeys to click Ctrl+J to bring the window to the front.
Sample code:
Sub LOADIE()
Set ieA = CreateObject("InternetExplorer.Application")
ieA.Visible = True
ieA.navigate "https://www.bing.com/"
Do Until ieA.readyState = 4
DoEvents
Loop
Application.Wait (Now + TimeValue("00:00:03"))
Application.SendKeys "^{j}"
End Sub
Result:
What I ended up doing was using an ObjURL to open the IE instance and then a DLUrl which I opened after. This made a few important adjustments, it's similar to opening a second tab in IE which would close, but instead of using the "Downloads Window" it would use the prompt at the bottom of the IE Window. This allowed me to continue to control the IEObj as the original ObjURL was still open. I couldn't get excel VBA to consistently control the "Downloads Window", but I was able to get consistent results using the following snippets. Between the two adjustments I now have consistent results.
Public Declare Function SetForegroundWindow Lib "user32" (ByVal HWND As Long) As Long
And
'Bring IEObj to Focus
HWNDSrc = IEObj.HWND
SetForegroundWindow HWNDSrc
Full Sub:
Public Declare Function SetForegroundWindow Lib "user32" (ByVal HWND As Long) As Long
Public Sub DL_File_IE()
Dim DLUrl As String, ObjURL As String
Dim IEObj As Object, objElement As Object, objCollection As Object
Set IEObj = CreateObject("InternetExplorer.Application")
IEObj.Visible = True
ObjURL = "http://google.com"
DLUrl = "http://example.com/file
IEObj.navigate ObjURL
Do Until IEObj.readyState = 4
DoEvents
Loop
IEObj.navigate DLUrl
'Bring IEObj to Focus
HWNDSrc = IEObj.HWND
SetForegroundWindow HWNDSrc
Application.Wait (Now() + TimeValue("00:00:02"))
SendKeys "{TAB}{TAB}{ENTER}", True ' Select "Save" in DL Window
Application.Wait (Now() + TimeValue("00:00:02"))
SendKeys "%{f4}", True ' Alt + F4 = Close IEObj
'Unload IE
Set IEObj = Nothing
Set objElement = Nothing
Set objCollection = Nothing
End Sub

Office 2016 VBA fails to open Internet Explorer shell window but works in Office 2013

I inherited this VBA script from my predecessor. It works fine for me in Excel 2013 up until recently when I was told I may need to work from home. Come to find out, the Office 2016 environment of my newly accessed VPN desktop does not like this script. I keep getting "The remote server machine is unknown or unavailable" when it reaches .ReadyState <> READYSTATE_COMPLETE.
The navigation did not fail as I can see the window where it successfully navigated to the URL and I can interact with it correctly. The strange thing is if I change the URL to "www.google.com" I get a valid ready state result.
I also need to figure out how to late bind the Shell Windows so it will work with both the v15 and v16 libraries simultaneously.
The intent of this script is to automate a process that
1. Opens an internal database at DBurl via web interface
2. Manipulates and runs a java script located on the web page
3. Close the browser window without closing any other browser windows
This could be modified for someone else's use by looking for a page element, such as a search box or specific button on a page, and interacting with it.
Edit:
Additional testing has revealed that a pause at and skipping the Do While loop and resuming at IETab1 = SWs.Count results in this script working in Office 2016. The only issue, then, is without the loop, the page isn't yet ready for the next step when the script tries to run the interaction. A wait for 5 seconds in place of the loop band-aid's this issue. Finding why the .ReadyState won't read will fix this issue.
Declare PtrSafe Function apiShowWindow Lib "user32" Alias "ShowWindow" _
(ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Sub OpenWebDB()
Dim ieApp As Object
Dim SWs As ShellWindows
Dim IETab1 As Integer
Dim JScript As String
Dim CurrentWindow As Object
Dim DBurl As String
Dim tNow As Date, tOut As Date
DBurl = "My.Database.url"
Set SWs = New ShellWindows
tNow = Now
tOut = tNow + TimeValue("00:00:15")
If ieApp Is Nothing Then
Set ieApp = CreateObject("InternetExplorer.Application")
With ieApp
.Navigate DBurl
Do While tNow < tOut And .ReadyState <> READYSTATE_COMPLETE
DoEvents
tNow = Now
Loop
IETab1 = SWs.Count
End With
End If
If Not tNow < tOut Then GoTo DBFail
On Error GoTo DBFail
Set CurrentWindow = SWs.Item(IETab1 - 1).Document.parentWindow
JScript = "javascript: DoSomething"
Call CurrentWindow.execScript(JScript)
On Error GoTo 0
SWs.Item(IETab1 - 1).Quit
Set ieApp = Nothing
Set SWs = Nothing
Exit Sub
DBFail:
MsgBox (DBurl & vbCrLf & "took too long to connect or failed to load correctly." & vbCrLf & _
"Please notify the Database manager if this issue continues."), vbCritical, "DB Error"
SWs.Item(IETab1 - 1).Quit
Set ieApp = Nothing
Set SWs = Nothing
End Sub
Try to remove the tNow < tOut from the Do While condition. Or, using the While statement to wait page complete:
While IE.ReadyState <> 4
DoEvents
Wend
The intent of this script is to automate a process that
1. Opens an internal database at DBurl via web interface
2. Manipulates and runs a java script located on the web page
3. Close the browser window without closing any other browser windows
Besides, according to the intent of the script, I suggest you could refer the following code (it could loop through the tabs, and close specific tab according the title):
Sub TestClose()
Dim IE As Object, Data As Object
Dim ticket As String
Dim my_url As String, my_title As String
Set IE = CreateObject("InternetExplorer.Application")
With IE
.Visible = True
.Navigate "https://www.microsoft.com/en-sg/" '1st tab
.Navigate "https://www.bing.com", CLng(2048) '2nd
.Navigate "https://www.google.com", CLng(2048) '3rd
While IE.ReadyState <> 4
DoEvents
Wend
'wait some time to let page load
Application.Wait (Now + TimeValue("0:00:05"))
'get the opened windows
Set objShell = CreateObject("Shell.Application")
IE_count = objShell.Windows.Count
'loop through the window and find the tab
For x = 0 To (IE_count - 1)
On Error Resume Next
'get the location and title
my_url = objShell.Windows(x).Document.Location
my_title = objShell.Windows(x).Document.Title
'debug to check the value
Debug.Print x
Debug.Print my_title
'find the special tab based on the title.
If my_title Like "Bing" & "*" Then
Set IE = objShell.Windows(x)
IE.Quit 'call the Quit method to close the tab.
Exit For 'exit the for loop
Else
End If
Next
End With
Set IE = Nothing
End Sub

Controlling IE11 “Do you want to Open/Save” VBA

I have issues with a code I am writing on VBA. I am basically using vba to open a website, input information and then click a download button, which downloads a csv that I can then copy and put onto my excel file. I do manage to get everything done up to the clicking download button. When I do that a Dialogue window shows up for IE11 asking me whether I want to save or open the file. I have no idea how solve this issue and how to click open or save. I have tryed everything mentioned in a solution for the same problem in Controlling IE11 "Do you want to Open/Save" dialogue window buttons in VBA , but even though I use this solution, the code runs but just does not do anything.
I have tried using the UIAutomation but I have been unsuccessful . I used the solution provided in Controlling IE11 "Do you want to Open/Save" dialogue window buttons in VBA. I have also tried using Sendkeys but I am not entirely sure how to set the focus on Internet explorer so that the sendkeys do what they are supposed to.
Code is actually very simple
Sub GetHTMLDocument()
Dim ie As New SHDocVw.InternetExplorer
Dim HTMLDoc As HTMLDocument
Dim HTMLInput As MSHTML.IHTMLElement
Dim HTMLButtons As MSHTML.IHTMLElementCollection
Dim HTMLButton As MSHTML.IHTMLElement
ie.Visible = True
ie.Navigate "this is where i put the website"
Do While ie.ReadyState <> READYSTATE_COMPLETE
Loop
Set HTMLDoc = ie.Document
Set HTMLInput = HTMLDoc.getElementById("Search")
HTMLInput.Value = "Hello"
Set HTMLInput = HTMLDoc.getElementById("downloadCSV")
HTMLInput.Click
End Sub
Unfortunately I cannot give the website and I cannot use a public one, after that I get the message whether to open or save it on internet explorer
Possible duplicate of VBA interaction with internet explorer
Though this answer may be more clear for this specific question.
1) add this to top of your module - It creates a function that will allow you to give any window focus. I have no idea on the details.
Public Declare Function SetForegroundWindow Lib "user32" (ByVal HWND As Long) As Long
2) Modify this code to taste in order to use SendKeys
'give IE focus to prepare for SendKeys
' IE.HWND = the handle of the Windows Internet Explorer main window.
Dim HWNDSrc As Long
HWNDSrc = IE.HWND
SetForegroundWindow HWNDSrc
'Make sure IE is not busy
Do While IE.Busy
Application.Wait DateAdd("s", 1, Now)
Loop
'send Alt-S to save
Application.SendKeys "%{S}"
'Make sure IE is not busy
Do While IE.Busy
Application.Wait DateAdd("s", 1, Now)
Loop

How can I make sure my IE tab name is correct?

I'm using this code to grab the instance of Internet Explorer from word VBA and scraping some values from a webpage. I'm looping through 4 items (just in case, sometimes I've accidentally grabbed something called "Windows Explorer", which I have no idea what that is) to grab Internet Explorer. But before I begin scraping values, I want to make sure my tab name is "Overview - City". How can I test against the tab names?
Dim shellWins As ShellWindows, IE As InternetExplorer
Dim i As Long
Set shellWins = New ShellWindows
'Find Internet Explorer - if it can't find it, close the program
If shellWins.Count > 0 Then
For i = 0 To 3
On Error Resume Next
If shellWins.Item(i).Name = "Internet Explorer" Then
Set IE = shellWins.Item(i)
Exit For
End If
On Error GoTo 0
If i = 3 Then
MsgBox "Could not find Internet Explorer.", vbExclamation, "Error"
Exit Sub
End If
Next i
Else
MsgBox "Could not find Internet Explorer.", vbExclamation, "Error"
Exit Sub
End If
I tried following the guide here and used this bit to try and Debug.Print all the active tab names in IE once I had found it:
Dim IE_Tab As SHDocVw.InternetExplorer
Dim SH_Win As SHDocVw.ShellWindows
For each IE_Tab in SH_Win
Debug.Print IE_Tab.Name 'This returns nothing?
Next IE_Tab
But the immediate window returns blank with no error. What am I doing wrong?
Here is some code that should find a reference to the open Internet Explorer tab. It does this by looping through the Shell.Application.Windows collection. The function supports looking for just the WindowName, the URL and WindowName, and supports specifying the compare method or if you want to do a like match. I kept this code late bound, to avoid needing references.
The code is commented, somewhat, let me know if there are questions.
Code
Option Explicit
Private Function GetIEWindow(WindowName As String, _
ExactMatch As Boolean, _
Optional CompareMethod As VbCompareMethod = vbTextCompare, _
Optional URL As String) As Object
Dim Window As Object
Dim Windows As Object: Set Windows = CreateObject("Shell.Application").Windows
For Each Window In Windows
'Make sure the app is Internet Explorer. Shell Windows can include other apps
If InStr(1, Window.FullName, "IEXPLORE.EXE", vbTextCompare) > 0 Then
'Perform exact matches, where the title or url and title match exactly
If ExactMatch Then
If Len(URL) = 0 Then
If Window.LocationName = WindowName Then
Set GetIEWindow = Window
Exit Function
End If
Else
If Window.LocationName = WindowName And Window.LocationUrl = URL Then
Set GetIEWindow = Window
Exit Function
End If
End If
Else
'Otherwise do a In String match
If Len(URL) = 0 Then
If InStr(1, Window.LocationName, WindowName, CompareMethod) > 0 Then
Set GetIEWindow = Window
Exit Function
End If
Else
If InStr(1, Window.LocationName, WindowName, CompareMethod) > 0 And InStr(1, Window.LocationUrl, URL, CompareMethod) > 0 Then
Set GetIEWindow = Window
Exit Function
End If
End If
End If
End If
Next
End Function
Sub ExampleUsage()
Dim IE As Object: Set IE = GetIEWindow("exe", True)
If Not IE Is Nothing Then
Debug.Print "I found the IE window"
Else
Debug.Print "I didn't find the IE window"
End If
End Sub
The tab is just another window. You can use the GetWebPage function below to loop through the windows and get the URL you are looking for.
References are
Microsoft Internet Controls
Microsoft Shell Controls and Automation
Sub Example()
Dim ieWin As InternetExplorer
Set ieWin = CreateObject("InternetExplorer.Application")
With ieWin
.Navigate "https://www.google.com/"
.Visible = True
.Silent = True
End With
Set ieWin = GetWebPage("https://www.google.com/")
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Desc: The Function gets the Internet Explorer window that has the current
' URL from the sURL Parameter. The Function Timesout after 30 seconds
'Input parameters:
'String sURL - The URL to look for
'Output parameters:
'InternetExplorer ie - the Internet Explorer window holding the webpage
'Result: returns the the Internet Explorer window holding the webpage
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Function GetWebPage(sUrl As String) As InternetExplorer
Dim winShell As Shell
Dim dt As Date
dt = DateAdd("s", 300, DateTime.Now)
Dim ie As InternetExplorer
Do While dt > DateTime.Now
Set winShell = New Shell
'loop through the windows and check the internet explorer windows
For Each ie In winShell.Windows
If ie.LocationURL = sUrl Then
Set GetWebPage = ie
Do While ie.Busy
DoEvents
Loop
Exit Do
Set winShell = Nothing
End If
Next ie
Set winShell = Nothing
DoEvents
Loop
End Function

VBA Automation - Downloading a file using IE 11 (64bit)

This question seems to have been asked dosens of times, however none of the solutions I have found seem to be able to solve my problem.
As the webpage is using a certificate token I am forced to log on to the webpage manually before I can activate the VBA script, which is no problem. An important note is that the link to the report is dynamic and therefore I cannot link directly to the report itself and therefore I have to navigate the webpage with my Script. Below you find the script i am using to locate the window I have logged on to the webpage with:
Sub WebPageOpen()
Dim HTMLDoc As HTMLDocument
Dim oHTML_Element As IHTMLElement
On Error GoTo Err_Clear
Set objShell = CreateObject("Shell.Application")
IE_count = objShell.Windows.Count
For X = 0 To (IE_count - 1)
On Error Resume Next ' sometimes more web pages are counted than are open
my_url = objShell.Windows(X).document.Location
my_title = objShell.Windows(X).document.Title
If my_title Like "MY Webpage name" Then 'compare to find if the desired web page is already open
Set IE = objShell.Windows(X)
marker = 1
Exit For
Else
End If
Next
If marker = 0 Then
MsgBox ("Webpage is not open - Please log on to webpage")
Exit Sub
Else
End If
Do
' Wait till the Browser is loaded
Loop Until IE.readyState = READYSTATE_COMPLETE
' I have removed all my navigation commands here,as it would just be bloating the query. It clicks the link and the Save/open ribbon appears in IE.
End sub
Can anyone help me with some sort of solution to how I can interact with the Open/Save as ribbon which appears when I download the file?
That ribbon is called Notification bar.
You can use Alt+N to focus on the Notification Bar. And then send {tab} key to navigate to the specific button.
With VBA, you may use Autohotkey.dll or AutoItX3.dll to send these hotkey combinations.
Add reference to AutoItX3.dll (for both 32-bit and 64-bit OS)
Append the following
set X=CreateObject("AutoItX3.Control")
X.send !N{tab}{down 2}{enter} 'This is for Save-as