question

J710-9247 avatar image
0 Votes"
J710-9247 asked DAVIDalvarez-5780 commented

VBA automation with Edge IE mode

I have been using VBA to automate IE in the past and I understand that IE with be demised soon. I heard that ActiveX can be used in Edge IE mode until 2029. May I know how can I do so? Do I have to change any of my old code? My code which worked with IE will only open IE browser and will not interact with Edge IE mode. Do I have to amend anything to tell VBA to interact with Edge IE mode instead of IE? My computer is in Win10 20H2 and KB5011487 have been installed to it.

My code is something like this:
‘opened the XXXX website manually before running the code
‘Search for tab named XXXX
Set ieApp = FindIEObject(“XXXXX”)
‘Send the text to the yyy text box
ieApp.document.all.Item(“yyy”).Value = ThisWorkbook.Sheets(“Sheet1”).Range(“A” & 1)
‘Press click
ieApp.document.getElementById(“zzz”).Click

office-vba-devms-edge
· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

OP, @J710-9247

I found out an alternative method that allows HTMLDocuments and/or UIAutomation Windows API libraries that does NOT require Edge IEMode, Selenium, or Webdriver. So far it works only in Edge, with or without IEMode. I haven't tested yet on Chrome. It also is significantly less code than what @KelvinYeung-7479 has.

If you're welling to try something different, I can post what I have (it's not quite complete)

1 Vote 1 ·
vingasoline-3643 avatar image vingasoline-3643 AHRIONGALLEGOS-4483 ·

definitely post it up!

0 Votes 0 ·

Hey there, checking back on this, running into the same problem hoping to see what you've cooked up.

0 Votes 0 ·

Hello AHRIONGALLEGOS

I'm very curious about your alternative method.

I'm having some compatibility issues with origin in the security policy and workstations setup of the organization I work in.

if possible to you please share that method you refer.´

TIA

0 Votes 0 ·
Reza-Ameri avatar image
0 Votes"
Reza-Ameri answered J710-9247 commented

In general, it is recommended to move from Active X and everything related to the Internet Explorer and re-design your application with modern web standards or as Microsoft Edge Extensions.
Internet Explorer Mode is just for backward compatibility and to give more time to developers to move into Microsoft Edge.

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I understand that it will be better to move forward from ActiveX. However, I am currently working in a company computer which Selenium is not a possible option. Therefore, I still have to stick with ActiveX first until my company allow us to download Selenium.

0 Votes 0 ·
YuZhou-MSFT avatar image
0 Votes"
YuZhou-MSFT answered

Hi @J710-9247

If Selenium is not an option, I think you can't automate with Edge IE mode.

The only way to automate with Edge IE mode is using IEDriver. You can't do it with only VBA. You need to:

  1. Define InternetExplorerOptions with additional properties that point to the Microsoft Edge browser.

  2. Start an instance of InternetExplorerDriver and pass it InternetExplorerOptions. IEDriver launches Microsoft Edge and then loads your web content in IE mode.

For more information, you can refer to this doc.


If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

Regards,
Yu Zhou

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

KelvinYeung-7479 avatar image
1 Vote"
KelvinYeung-7479 answered DAVIDalvarez-5780 commented

Automation on Edge Browser Webpage : Win API to Retrieve HTMLDocuments of Webpages in Existing Edge Browser Windows
| By Kelvin Yeung | May 9, 2022 | VBA Programming – Win API & Edge Browser Automation

I had been using IE and Internet Object Model (IOM) to achieve automation with internal web-based systems in my works at bank. Since the announcement that IE will be no longer supported by Microsoft at 15 June 2022, I started to look for possible alternative solutions on the internet.
After investigation, I found that there are two solutions to achieve automation on Edge browser : 1) SeleniumBasic or 2) Win API. Though SelenimBasic seems to be the mainstream suggestion at forums, Win API can be regarded as better solution in several different ways, especially for my own situations.

Pros of Win API Solution :
- No need installation and regular update of Edge driver.
- Able to automate with multiple existing Edge browser windows (which have been opened before program start).
- Most of codes in existing IOM solution can be preserved and re-applied. It is because both solutions of IOM and Win API should use HTML Document Object Model (DOM) at last to achieve automation on webpage. The difference is on the way to find browser and attain HTMLDocument from browser.

Cons of Win API Solution :
- We can automate with “webpage” on Edge browser but not the “Edge browser” itself. It is not like IOM and SeleniumBasic that can control web browser. For this, I use Shell function and DOS commands to achieve automation of opening and closing Edge browser.
- The webpage has to be opened in IE mode at Edge browser which means this solution is subject to Microsoft’s future direction on IE mode of Edge browser.

Sharing on my experiences to use Win API on Edge browser webpage automation :
1) Place the following codes in a new blank module. I name this module as “MsEdge” usually. The codes in this module are no need to modify for usage. You can directly use the codes even if you don’t know much about Win API.

 Public lngProcessID_Close As Long
    
 'Part 1 --- Locate IES
    
 Private strHwndIES As String
    
 Private lngHwndIndex As Long
    
 Private Declare Function EnumWindows Lib "user32" ( _
     ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
    
 Private Declare Function EnumChildWindows Lib "user32" ( _
     ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
    
 Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" ( _
     ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
    
 'Part 2 --- Get HTMLDocument from IES
    
 Private Const SMTO_ABORTIFHUNG = &H2
    
 Private Const GUID_IHTMLDocument2 = "{332C4425-26CB-11D0-B483-00C04FD90119}"
    
 Private Declare Function RegisterWindowMessage Lib "user32" Alias "RegisterWindowMessageA" ( _
     ByVal lpString As String) As Long
    
 Private Declare Function SendMessageTimeout Lib "user32" Alias "SendMessageTimeoutA" ( _
     ByVal hWnd As Long, _
     ByVal msg As Long, _
     ByVal wParam As Long, _
     lParam As Any, _
     ByVal fuFlags As Long, _
     ByVal uTimeout As Long, _
     lpdwResult As Long) As Long
    
 Private Declare Function IIDFromString Lib "ole32" ( _
     lpsz As Any, lpiid As Any) As Long
    
 Private Declare Function ObjectFromLresult Lib "oleacc" ( _
     ByVal lResult As Long, _
     riid As Any, _
     ByVal wParam As Long, _
     ppvObject As Any) As Long
        
 'Part 3 --- Check Process Name
    
 Private Declare Function GetWindowThreadProcessId Lib "user32" ( _
     ByVal hWnd As Long, lpdwProcessId As Long) As Long
        
    
 Public Function findEdgeDOM(Title As String, URL As String) As HTMLDocument
    
     'Find criteria-hitting Edge page in IE mode
    
     Dim hwndIES As Long
                
     Do
        
         hwndIES = enumHwndIES
                    
         If hwndIES Then
            
             Set findEdgeDOM = getHTMLDocumentFromIES(hwndIES)

             If Not findEdgeDOM Is Nothing Then
                
                 If InStr(findEdgeDOM.Title, Title) * InStr(findEdgeDOM.URL, URL) Then
                
                     Do
                    
                         hwndIES = enumHwndIES
                        
                     Loop While hwndIES
                
                     Exit Function
                    
                 Else
                
                     Set findEdgeDOM = Nothing
                    
                 End If

             End If
                
         End If
        
     Loop While hwndIES
        
 End Function
    
 Public Function enumHwndIES() As Long
    
     'Get all hwnds of IES
    
     If Len(strHwndIES) = 0 Then
        
         EnumWindows AddressOf EnumWindowsProc, 0
        
         lngHwndIndex = 0
        
     End If
        
     'Exit function when overflow
        
     If lngHwndIndex + 1 > (Len(strHwndIES) - Len(Replace(strHwndIES, ",", ""))) Then
        
         enumHwndIES = 0
            
         strHwndIES = ""
            
         Exit Function
            
     End If
        
     'Return IES hwnd one by one
    
     enumHwndIES = CLng(Split(Left(strHwndIES, Len(strHwndIES) - 1), ",")(lngHwndIndex))
    
     lngHwndIndex = lngHwndIndex + 1
            
 End Function
    
 Private Function EnumWindowsProc(ByVal hWnd As Long, ByVal lParam As Long) As Boolean
                
     Dim lngProcessID As Long
                
     GetWindowThreadProcessId hWnd, lngProcessID
                            
     EnumChildWindows hWnd, AddressOf EnumChildProc, lngProcessID
                    
     EnumWindowsProc = True
        
 End Function
    
 Public Function EnumChildProc(ByVal hWnd As Long, ByVal lParam As Long) As Boolean
            
     Dim strTargetClass As String, strClassName As String
                
     strTargetClass = "Internet Explorer_Server"
            
     strClassName = getClass(hWnd)
        
     If strClassName = strTargetClass Then
        
         If GetObject("winmgmts:").ExecQuery("Select Name from Win32_Process WHERE ProcessId='" & lParam & "' AND Name='msedge.exe'").Count Then
                
             strHwndIES = strHwndIES & hWnd & ","
                
             lngProcessID_Close = lParam
                
             EnumChildProc = False
        
             Exit Function
                
         End If
                    
     End If
            
     EnumChildProc = True
        
 End Function
    
 Private Function getClass(hWnd As Long) As String
    
     Dim strClassName As String
        
     Dim lngRetLen As Long
        
        
     strClassName = Space(255)
        
     lngRetLen = GetClassName(hWnd, strClassName, Len(strClassName))
        
     getClass = Left(strClassName, lngRetLen)
    
 End Function
    
 Public Function getHTMLDocumentFromIES(ByVal hWnd As Long) As Object
    
     Dim iid(0 To 3) As Long
        
     Dim lMsg As Long, lRes As Long
        
     lMsg = RegisterWindowMessage("WM_HTML_GETOBJECT")
        
     SendMessageTimeout hWnd, lMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, lRes
    
     If lRes Then
        
         IIDFromString StrPtr(GUID_IHTMLDocument2), iid(0)
                
         ObjectFromLresult lRes, iid(0), 0, getHTMLDocumentFromIES
        
     End If
    
 End Function
    
 Public Sub closeEdge(Title As String, URL As String)
    
     'Close a Edge browser (the last one in EnumWindows order) with criteria-hitting webpage
        
     lngProcessID_Close = 0
    
     Dim findEdgeDOM As Object
        
     Dim hwndIES As Long
                
     Do
        
         hwndIES = enumHwndIES
                    
         If hwndIES Then
            
             Set findEdgeDOM = getHTMLDocumentFromIES(hwndIES)
                            
             If InStr(findEdgeDOM.Title, Title) * InStr(findEdgeDOM.URL, URL) Then
                
                 Shell "TaskKill /pid " & lngProcessID_Close
                    
                 Do
                    
                     hwndIES = enumHwndIES
                        
                 Loop While hwndIES
                
                 Exit Sub
                                                
             End If
                
         End If
        
     Loop While hwndIES
        
 End Sub





2) Apply the functions in “MsEdge” module. There are a few application examples for you. Suggest to place and test below codes at another module:

 Sub findEdgeDOM_DemoProc()
    
     'Demo Proc : Use findEdgeDOM Function to get DOM of specific Edge webpage by Title AND URL
    
     'Dim docHTML As MSHTML.HTMLDocument     '--- Early Binding
            
     Dim docHTML As Object                   '--- Late Binding
        
     Set docHTML = findEdgeDOM("Enter Part of Webpage Title Here", "Enter Part of Webpage URL Here")
     ‘You can fill just one argument with either part of webpage title or URL as keyword to search for the target browser and leave another one blank (“”). If you provide both title and URL, the funcitons return DOM of the only browser that meets both criteria.
    
     If Not docHTML Is Nothing Then Debug.Print docHTML.Title, docHTML.URL
    
 End Sub
    
 Sub goEdge()
    
     'Go through every Edge webpage (opened in IE mode) and print out hwndIES, webpage Title & webpage URL
    
     Dim hwndIES As Long
        
     'Dim docHTML As MSHTML.HTMLDocument     '--- Early Binding
            
     Dim docHTML As Object                   '--- Late Binding
            
     Do
        
         hwndIES = enumHwndIES
                    
         If hwndIES Then
            
             Set docHTML = getHTMLDocumentFromIES(hwndIES)
                
             Debug.Print hwndIES, docHTML.Title, docHTML.URL
                
         Else
            
             Debug.Print "Procedure End"
            
         End If
        
     Loop While hwndIES
        
 End Sub
    
 Sub openEdgeByURL_DemoProc()
    
     openEdgeByURL "Input Webpage URL Here"
            
 End Sub
    
 Public Sub openEdgeByURL(URL As String)
    
     'Please change the path to your msedge.exe location in your PC
    
     Shell "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe -url " & URL, vbNormalFocus
    
 End Sub
    
 Sub closeEdge_DemoProc()
    
     closeEdge "Enter Part of Webpage Title Here", "Enter Part of Webpage URL Here"
        
 End Sub
· 17
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

This is good stuff, Kevin! I was able to use your code to have Edge do some data input. Do you know if it's at all possible to execute events with this? Like "on click", etc. It didn't sound like it was, since we can't control the browser itself...

0 Votes 0 ·

Yes, I think it may not be able to do so. No event related function can be seen in HTMLDocument. Also, it is hard to imagine VBA can keep monitoring the activities on website and trigger back any one of its procedures.

0 Votes 0 ·

Kelvin,

I'm trying to make this work with W10 64 bits, to get an Edge instance.

Still have some issues...
Had change all Declare Function to Declare PtrSafe Function

But changing the Long type to LongPtr because of the Type mismatch in the EnumWindows AddressOf EnumWindowsProc, 0

I have made some mistake because couldn't make it work.

Any hint would be appreciated.

With IE only I use to do:

Dim GetOpenIEByURL As InternetExplorer
Dim objShellWindows As ShellWindows
Dim owIE As InternetExplorerMedium

Set objShellWindows = New ShellWindows
For Each GetOpenIEByURL In objShellWindows
'if the document is of type HTMLDocument, it is an IE window
MsgBox TypeName(GetOpenIEByURL.Document)
If TypeName(GetOpenIEByURL.Document) = "HTMLDocument" Then
Set owIE = GetOpenIEByURL
If MsgBox("This one? " & vbCrLf & owIE.Document.Title, vbYesNo) = vbYes Then Exit For
End If
Next
If owIE Is Nothing Then
MsgBox "No IE", vbCritical
Exit Sub
End If

Thanks


0 Votes 0 ·
KelvinYeung-7479 avatar image KelvinYeung-7479 JoaoSimplicioRodrigues ·

As far as I know about changing from 32-bit to 64-bit environment, you have worked on right directions :
1. Change Declare to Declare PtrSafe in Win API declarations
2. Change Long type to LongPtr for some variables

Sorry that my home and office are still using 32-bit. I cannot test how to work out in 64-bit this moment. But if you can fix Win API conversion, you can modify "goEdge" procedure like this in your case:

  ... ...
  Do
     hwndIES = enumHwndIES
     If hwndIES Then
         Set docHTML = getHTMLDocumentFromIES(hwndIES)
         If MsgBox("This one? " & vbCrLf & docHTML.Title, vbYesNo) = vbYes Then
             Do
                 hwndIES = enumHwndIES
             Loop While hwndIES
             Exit Do
         Else
             Set docHTML = Nothing
         End If
     End If
 Loop While hwndIES
    
 If docHTML Is Nothing Then
     MsgBox "No Edge", vbCritical
     Exit Sub
 End If
1 Vote 1 ·

This has been very helpful - thank you. My follow up question is about working with frames. I cannot get it to work using HTMLDocument - only when using the InternetExplorer object. Do you have any suggestions on how to find and work with frames using HTMLDocument instead?

0 Votes 0 ·

I didn't work with frames by InternetExplorer object but by HTMLDocument as well. I once faced two kinds of frames over the web systems i worked with. Give you some sample codes below :

Dim docHTML_F As MSHTML.HTMLDocument

1) Frame

Set docHTML_F = docHTML.frames(1).document 'Argument in frames() is determined by which frame you want to get


2) iFrame

Dim frHTML As MSHTML.HTMLFrameElement 'Step 1 : Declare HTMLFrameElement Object

For Each frHTML In docHTML.getElementsByTagName("iframe")

Set docHTML_F = frHTML.contentDocument 'Step 2 : Retrieve frame's HTMLDocument by the property contentDocument

...

Next

0 Votes 0 ·

While I can download Selenium and webdriver, my organization blocks the port/host functions within them so I can't use that method. I've tired this other CDP method which also had this problem. I had problems with redirects stopping iemode so I had to study the Microsoft docs and found a registry that my organization doesn't include in their group policy. This isn't on Google anywhere. I then changed another registry value that sends all intranet to iemode. Being that I have to work around the organization group policy, finding these were a challenge.

Then I found your code. It's ingenious. It's perfect. I was previously using HTMLDoc with UIAutomation and I'm on 64bit. Your code gave me minimal edits to my previous automation code. I've only tested HTMLDocs but I'm assuming that since we now have a hwnd, we can use find window and UIAutomation just fine. I've adapted your code for 64bit, but you can't change everything to ptrsafe or many errors will be received.

Where are you hosting your code? GitHub? Do you have a link? I've seen our posts on like 3 different forums with the same info (I think GitHub too) and out of 4 solutions, yours is the only one that worked for my case with my organizational rules.

0 Votes 0 ·
KelvinYeung-7479 avatar image KelvinYeung-7479 AHRIONGALLEGOS-4483 ·

It's good to hear your story. I faced kind of exact same thing. Believe all of us suffering from IE demise. That's why i am so determined to share my solution out.

In order to let more people able to reach my post, i shared over several web forums. What is the meaning of "host"? I am a total newbie for technical forum.

0 Votes 0 ·

You can use websites such as GitHub to share/host your code so people can help improve upon it. It's used mainly as a developer hosting service, but can be used for JSON, C, Java, VBA, etc.

Maybe you can partner with me on the solution I have that gets rid of Edge IEMode (but is compatible with Edge or Edge/IEMode). It also doesn't require Webdriver or Selenium. Only a few of the basic VBA library references that should be available in the list on both 32/64bit. It can use both IUIAutomation or HTMLDocument.

0 Votes 0 ·
Show more comments

Kelvin - I think your post is what I've been looking for. However, I'm unable to compile it. Line 188 in the first code window references IID_IHTMLDocument, and the Excel VBA compiler doesn't recognize it. Is this a typo, a missing declaration, or a missing reference? Thanks in advance.

0 Votes 0 ·

Kevin, I can send you what I used to make it work. I had the same issue.

0 Votes 0 ·
KS-3525 avatar image KS-3525 AHRIONGALLEGOS-4483 ·

That would be great! It would be a big help. If it's a short bit of code, just post it here.

0 Votes 0 ·

IID_IHTMLDocument should be replaced with iid(0). It is my mistake. Originally I wanted to declare IID_IHTMLDocument directly. However, on second thought, retrieving by API seems more enduring so i changed but not completely. Thanks for telling this issue.
AHRION, let us know if you work it out in another way.

0 Votes 0 ·

Hi, could you please post the part of the code where should be repalaced with the fix. Thanks.

0 Votes 0 ·
Show more comments
AHRIONGALLEGOS-4483 avatar image
0 Votes"
AHRIONGALLEGOS-4483 answered AHRIONGALLEGOS-4483 published

This works Win 10, 64-bit. For reference, I changed cosmetically a few things (for my eyes), simply added PtrSafe and LongPtr only where necessary, and added .dll, as sometimes 64-bit recognizes original 32-bit libraries funky:

 ' [ Prefix --- Declare global variables ]
    
 Global lngProcessID_Close As Long
        
 ' [ Part 1 --- Locate IES ]
        
 Public strHwndIES As String
       
 Public lngHwndIndex As Long
       
 Public Declare PtrSafe Function EnumWindows Lib "user32.dll" (ByVal lpEnumFunc As LongPtr, ByVal lParam As Long) As Long
       
 Public Declare PtrSafe Function EnumChildWindows Lib "user32.dll" (ByVal hWndParent As Long, ByVal lpEnumFunc As LongPtr, ByVal lParam As Long) As Long
       
 Public Declare PtrSafe Function GetClassName Lib "user32.dll" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
        
 ' [ Part 2 --- Get HTMLDocument from IES ]
        
 Public Const SMTO_ABORTIFHUNG = &H2
       
 Public Const GUID_IHTMLDocument2 = "{332C4425-26CB-11D0-B483-00C04FD90119}"
       
 Public Declare PtrSafe Function RegisterWindowMessage Lib "user32.dll" Alias "RegisterWindowMessageA" (ByVal lpString As String) As Long
        
 Public Declare PtrSafe Function SendMessageTimeout Lib "user32.dll" Alias "SendMessageTimeoutA" ( _
     ByVal hWnd As Long, _
     ByVal msg As Long, _
     ByVal wParam As Long, _
     lParam As Any, _
     ByVal fuFlags As Long, _
     ByVal uTimeout As Long, _
     lpdwResult As Long) As Long
        
 Public Declare PtrSafe Function IIDFromString Lib "ole32.dll" (lpsz As Any, lpiid As Any) As Long
       
 Public Declare PtrSafe Function ObjectFromLresult Lib "oleacc.dll" (ByVal lResult As Long, riid As Any, ByVal wParam As Long, ppvObject As Any) As Long
           
 ' [ Part 3 --- Check Process Name ]
    
 Public Declare PtrSafe Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

MateuszKornet-8332 avatar image
0 Votes"
MateuszKornet-8332 answered MateuszKornet-8332 commented

Thanks Kelvin!

Right now I'm using IE via VBA
I spawn one browser window. Log in to the web page and keep it opened.
Then I follow about hundred links from that page and get part of HTML. I open these links in separate windows by using:

 Dim appIE As InternetExplorerMedium

to keep the session.
Is it possibe to achieve the same with your code?

Humble thanks.

· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks. Unfortunately this option is disabled in my organization. With your code I can open a webpage with IE mode Edge, but is it possible to follow a link? To mimic mouse click? Thanks.

0 Votes 0 ·
RogerScorefun-9603 avatar image
0 Votes"
RogerScorefun-9603 answered

Kelvin, your Code is wonderful and works fine - many thanks

I'm now able to read the rows of a html-table including download-links for pdf-files (as it works earlier with IE webbrowser-control)
but it doesn't work to download the files using URLDownloadToFile

It's a webpage where I'm logged in with username and password

Any idea?
Many thanks for reading
Regards Roger


5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.