I am limited to using VBA to accomplish this. The goal is to programmatically Open a new IE window which is a duplicate of a window already open.
I need to display this window for limited amount of time (in this example I am waiting 15 seconds), then I want to close one of the two IE windows I have open.
I have cobbled together code fragments from a few examples I have found and this is partially working, but the results are not as I would expect.
First I am able to find the IE instances but even though I think I have coded an exit, both windows are closed.
The MsgBox I am using for debugging never appears.
With each run of the code the error message below appears
Below is the code I am trying to get to work, but failing with.
Private Sub OpenReport()
Dim IE
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
IE.Navigate "http://~~~~~~~~~.net/reports/views/result/reportResult.faces"
' Wait for a period of time contained in TimeValue
Application.Wait (Now + TimeValue("00:00:15"))
' Now close ONE of the IE windows (Currently closing all of them)
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * From Win32_Process")
' Find IE Instances
For Each objItem In colItems
If objItem.Name = "iexplore.exe" Then
On Error Resume Next
objItem.Terminate ' Terminates all instead of exiting after finding one IE window
MsgBox objItem.Name & " " & objItem.ProcessID & " " & objItem.CommandLine 'Doesn't appear
Exit For
End If
Next
End Sub
I appreciate the input but had to go a slightly different route to get this working as it should...
The key to getting one instance of IE to close was solved by using TaskKill (commandline WScript).
Below is the full solution
Private Sub OpenReport()
Dim IE
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
IE.Navigate "http://~~~~~~~~~~~net/reports/views/result/reportResult.faces"
' Wait for a period of time contained in TimeValue
Application.Wait (Now + TimeValue("00:00:15"))
' Now close ONE of the IE windows (Currently closing all of them)
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * From Win32_Process")
' Find an IE instance
For Each objitem In colItems
If objitem.Name = "iexplore.exe" Then
On Error Resume Next
Shell ("TaskKill /PID " & objitem.ProcessID)
Exit For
End If
Next
End Sub
Related
The following VBA code gets stuck at the While loop:
Sub SaveAsText2(MyMail As MailItem)
' Export email (with PowerShell script in body) as a text file
MyMail.SaveAs "c:\scripts\outlook.ps1", olTXT
' Create a response email
Dim reMail As Outlook.MailItem
Set reMail = MyMail.Reply
' wait till transcript is available
Dim MyFSO As FileSystemObject
Set MyFSO = New FileSystemObject
If MyFSO.FileExists("C:\Scripts\email_transcript.txt") Then
' This bit works correctly
' MsgBox "The file Exists"
Else
' This bit works correctly as well
' MsgBox "The file Does Not Exist"
End If
' This part fails to evaluate regardless if the file is there or not
While Not MyFSO.FileExists("C:\Scripts\email_transcript.txt")
' WScript.Sleep 1000
Application.Wait (Now + TimeValue("0:00:01"))
MsgBox "The file Does Not Exist"
Wend
Set fs = CreateObject("Scripting.FileSystemObject")
Set a = fs.CreateTextFile("c:\scripts\testfile.txt", True)
a.WriteLine ("This is a test.")
a.Close
' attach the transcript and send it back
reMail.Attachments.Add "C:\Scripts\email_transcript.txt"
reMail.Send
MyFSO.DeleteFile ("C:\Scripts\email_transcript.txt")
End Sub
If the email_transcript.txt file exists, then the While loop gets skipped (which is correct) and the rest of the script runs. No issues here.
If the email_transcript.txt file does NOT exist, then the While loop will wait until the file exists. However, even when the file exists at this point, the While loop never validates and therefore it doesn't process the rest of the script.
The MsgBox in the While loop doesn't trigger when the file does NOT exist.
The MsgBox call stops any code execution until it is closed:
' This part fails to evaluate regardless if the file is there or not
While Not MyFSO.FileExists("C:\Scripts\email_transcript.txt")
' WScript.Sleep 1000
Application.Wait (Now + TimeValue("0:00:01"))
MsgBox "The file Does Not Exist"
Wend
Try to replace it with a Debug.Print statements, so the loop could continue:
' This part fails to evaluate regardless if the file is there or not
While Not MyFSO.FileExists("C:\Scripts\email_transcript.txt")
' WScript.Sleep 1000
Application.Wait (Now + TimeValue("0:00:01"))
Debug.Print "The file Does Not Exist"
Wend
The While/Wend structure has a logic fail: if at the moment of the first evaluation the expected file yet don't exists, the MsgBox alert will be fired, even if in the next second the file became properly saved.
You can change this as follows:
lngTimer = Timer
Do
DoEvents
Application.Wait (Now + TimeValue("0:00:01"))
If Timer > lngTimer + 10 Then Exit Do
Loop Until MyFSO.FileExists("C:\Scripts\email_transcript.txt") = True
Using a Do/Loop structure with a 'scape valve' of a Timer comparison will ensure a correct check for the file's existence, avoiding an eternal loop. Adapt the timeout parameter for the file to be saved (10 in the example).
Fixed the issue. It's to do with Application.Wait, which doesn't work in Outlook. Solution is here:
Wait for 5-10 seconds then run Outlook code
Sub SaveAsText2(MyMail As MailItem)
' Export email (with PowerShell script in body) as a text file
MyMail.SaveAs "c:\scripts\outlook.ps1", olTXT
' Create a response email
Dim reMail As Outlook.MailItem
Set reMail = MyMail.Reply
' wait till transcript is available
Dim MyFSO As FileSystemObject
Set MyFSO = New FileSystemObject
While Not MyFSO.FileExists("C:\Scripts\email_transcript.txt")
Sleep 1
Wend
Set fs = CreateObject("Scripting.FileSystemObject")
Set a = fs.CreateTextFile("c:\scripts\testfile.txt", True)
a.WriteLine ("This is a test.")
a.Close
' attach the transcript and send it back
reMail.Attachments.Add "C:\Scripts\email_transcript.txt"
reMail.Send
MyFSO.DeleteFile ("C:\Scripts\email_transcript.txt")
End Sub
Public Sub Sleep(ByVal SleepSeconds As Single)
Dim Tmr As Single
Tmr = Timer
Do While Tmr + SleepSeconds > Timer
DoEvents
Loop
End Sub
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
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
Thanks in advance for your answers.
I have a little Excel document that is made so that the naïve user can enter web pages in an Excel sheet, hit a button, and play the videos from that page in their browser, in full screen, and automatically loop the videos without any further user interaction. It basically creates a slide show of videos.
I originally made it for YouTube and it works fine there. I'm now trying to expand it to use another site. It works as planned but needs an extra step.
Whereas YouTube was made with a Full Screen mode that I can access programatically, this website has embedded videos. (An example: https://www.sharecare.com/video/health-topics-a-z/copd/what-can-i-do-to-prevent-my-copd-from-getting-worse).
You can see in the code that I open IE in full screen mode (which it does) but that's the full web page (header, side banner etc.). I want the video from that page to be the only element, full screen.
If I physically go into the page I can select for the video to play full screen. I've tried searching for various ways to do this, but most of the posts are for something else or how to get a video to play inside Excel rather than what I'm doing.
Sub StartLooping()
Dim IEapp As Object
Dim VidAddr1, VidAddr2 As String
Dim AddrStrStart, AddrStrEnd As Long
Dim AddrFudge1, AddrFudge2 As Integer
Dim TimeStart, DurMin, DurSec, DurTot As Single
Dim LRAll, LRVid, LRMin, LRSec, LRVidB, LRMinB, LRSecB As Integer
Dim I As Integer
Application.EnableCancelKey = xlErrorHandler
On Error GoTo ErrorHandle
'Review Sheet
LRVid = Cells(Rows.Count, "D").End(xlUp).Row
LRMin = Cells(Rows.Count, "E").End(xlUp).Row
LRSec = Cells(Rows.Count, "F").End(xlUp).Row
LRVidB = Cells(Rows.Count, "I").End(xlUp).Row
LRMinB = Cells(Rows.Count, "J").End(xlUp).Row
LRSecB = Cells(Rows.Count, "K").End(xlUp).Row
LRAll = Cells(Rows.Count, "S").End(xlUp).Row
If LRVid <> LRMin Then
MsgBox "You have to include video address and how long (the minutes and the seconds - use 0 if needed)"
Exit Sub
End If
If LRVid <> LRSec Then
MsgBox "You have to include video address and how long (the minutes and the seconds - use 0 if needed)"
Exit Sub
End If
If LRVidB <> LRMinB Then
MsgBox "You have to include video address and how long (the minutes and the seconds - use 0 if needed)"
Exit Sub
End If
If LRVidB <> LRSecB Then
MsgBox "You have to include video address and how long (the minutes and the seconds - use 0 if needed)"
Exit Sub
End If
'Start of For-Next Loop
For I = 20 To LRAll
'Set Addr
'VidAddr1
If Len(Range("S" & I).Text) = 0 Then
Exit Sub
Else
VidAddr1 = Range("S" & I).Text
End If
VidAddr2 = VidAddr1
'Set Timer
TimeStart = Timer 'Start time
DurMin = Range("T" & I).Value
DurSec = Range("U" & I).Value
DurTot = (DurMin * 60) + DurSec
'Open the web page
Set IEapp = CreateObject("Internetexplorer.Application") 'Set IEapp = InternetExplorer
With IEapp
.Silent = True 'No Pop-ups
.Visible = True
.FullScreen = True
.Navigate VidAddr2 'Load web page
'Keep it open for the duration
Do While Timer < (TimeStart + DurTot)
'Check for Esc - refers to a public function
If KeyDown(vbKeyEscape) Then
IEapp.Quit
Set IEapp = Nothing
Exit Sub
End If
Loop
'Close the page
IEapp.Quit
Set IEapp = Nothing
End With
If I = LRAll Then I = 19
Next I
ErrorHandle:
MsgBox Err.Number & " " & Err.Description
Exit Sub
End Sub
I copied the code. It works fine. It's just that extra bit of "Oh, I did that, here's how to go about it" that I need.
The browser used is IE so I can keep it simple, but if this were possible in another common browser that would be good to know.
Here's the second set that I tried today (9/12)
Dim IEapp As Object
Dim IEAppColl As HTMLButtonElement
'Open doc
Set IEapp = CreateObject("Internetexplorer.Application") 'Set IEapp = InternetExplorer
With IEapp
.Silent = True 'No Pop-ups
.Visible = True
'.FullScreen = True
.navigate "https://www.sharecare.com/video/health-topics-a-z/copd/got-copd-ask-your-doctor-about-vitamin-d"
Do While .readyState < 4 Or .Busy
Loop
Set IEAppColl = IEapp.Document.getElementsByTagName("BUTTON")
If IEAppColl.Name = "Fullscreen" Then
IEAppColl.Click
End If
End With
For the example COPD page given this works with Selenium basic. You install from here and then go VBE > Tools > References > and add a reference to Selenium Type Library. You can also use an IEDriver to work with InternetExplorer rather than Chrome (which uses ChromeDriver).
Option Explicit
Public Sub PlayFullScreen()
Dim d As WebDriver, t As Date, ele As Object
Const MAX_WAIT_SEC As Long = 10
Set d = New ChromeDriver
Const URL = "https://www.sharecare.com/video/health-topics-a-z/copd/what-can-i-do-to-prevent-my-copd-from-getting-worse"
With d
.Start "Chrome"
.get URL
Do
DoEvents
On Error Resume Next
Set ele = .FindElementByCss("[title='Accept Cookies']")
If Timer - t > MAX_WAIT_SEC Then Exit Do
On Error GoTo 0
Loop While ele Is Nothing
Application.Wait Now + TimeSerial(0, 0, 1)
If Not ele Is Nothing Then ele.Click
.FindElementByCss("#myExperience").Click
Application.Wait Now + TimeSerial(0, 0, 1)
.FindElementByCss("[Title=Fullscreen]", timeout:=7000).Click
Stop '<==Delete me later
.Quit
End With
End Sub
My suggestion is to, instead of using a browser to play video, use a video player.
Under "More Controls" you should have a "Windows Media Player", and likely others, depending on what you have installed.
For example, I've used the VLC control on Access forms. When you install VLC it automatically adds the control to Office (so I assume Office has to be installed first.)
Here's a tutorial I found online:
Link: How to Play Video on Access Form
Random Tip Time:
It can be tricky to Google about a website because, for example, using the search term *YouTube* in a Google search results in a list of YouTube content (videos).
Exclude results from a specific site with Google's site: and - operators like:
"microsoft access" form play youtube video -site:youtube.com
...which is how I found the tutorial above, and several others.
Using the search term access can also be tricky to search for since it's such a common word, which is why I'll often enclose it in quotes like "MS Access" or "Microsoft Access" (like above), which makes Google search for those words in that order.
(More Google tips)
I want to read web pages using Excel VBA. How do I carry out this task? Is it even possible?
Coming from Excel 2003, yes this is possible - you may use the SHDocVw.InternetExplorer and MSHTML.HTMLDocument objects to call a web page, gain control over and interact with the DOM object. After creating references to Microsoft HTML Object Library (...\system32\MSHTML.TLB) and Microsoft Internet Control (...\system32\ieframe.dll) you can play with the following example:
Sub Test()
Dim Browser As SHDocVw.InternetExplorer
Dim HTMLDoc As MSHTML.HTMLDocument
Set Browser = New SHDocVw.InternetExplorer ' create a browser
Browser.Visible = True ' make it visible
Application.StatusBar = ".... opening page"
Browser.navigate "http://www.google.com" ' navigate to page
WaitForBrowser Browser, 10 ' wait for completion or timeout
Application.StatusBar = "gaining control over DOM object"
Set HTMLDoc = Browser.document ' load the DOM object
WaitForBrowser Browser, 10
' at this point you can start working with the DOM object. Usefull functions are
' With HTMLDoc
' .getElementByID(string)
' .getElementsByTagName(string)
' .getElementsByName(string)
' .getAttribute(string)
' .setAttribute string, string .... to change field values, click a button etc.
' End With
Application.StatusBar = "" ' time to clean up
Browser.Quit
Set HTMLDoc = Nothing
Set Browser = Nothing
End Sub
Sub WaitForBrowser(Browser As SHDocVw.InternetExplorer, Optional TimeOut As Single = 10)
Dim MyTime As Single
MyTime = Timer
Do While Browser.Busy Or (Timer <= MyTime + TimeOut)
DoEvents
Loop
' if browser still busy after timeout, give up
If Browser.Busy Then
MsgBox "I waited for " & Timer - MyTime & " seconds, but browser still busy" & vbCrLf & _
"I give up now!"
End
End If
End Sub
You can use VBA to automate IE (plenty of examples via Google) or you can fetch the page directly using an instance of MSHTTP (ditto plenty of examples on the web). Which is best for your needs will depend on exactly what you want to do. Hard to say more without more detailed requirements.