Reputation: 85
I am trying to enumerate and get the URLs of all open tabs in chrome. With lots of help from google (well..actually from Stackoverflow :-)) I could manage to enumerate and get the "Names" of all open tabs using the code below..
Imports System.Windows.Automation
Imports System.Runtime.InteropServices
Imports System.Text
Public Class Form1
Public Declare Auto Function GetClassName Lib "User32.dll" (ByVal hwnd As IntPtr, _
<Out()> ByVal lpClassName As System.Text.StringBuilder, ByVal nMaxCount As Integer) As Integer
Public Delegate Function CallBack(ByVal hwnd As Integer, ByVal lParam As Integer) As Boolean
Public Declare Function EnumWindows Lib "user32" (ByVal Adress As CallBack, ByVal y As Integer) As Integer
Public Declare Function IsWindowVisible Lib "user32.dll" (ByVal hwnd As IntPtr) As Boolean
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
GetActiveWindows()
End Sub
Public Sub GetActiveWindows()
EnumWindows(AddressOf Enumerator, 0)
End Sub
Private Function Enumerator(ByVal hwnd As IntPtr, ByVal lParam As Integer) As Boolean
'//Only active windows
If IsWindowVisible(hwnd) Then
Dim sClassName As New StringBuilder("", 256)
GetClassName(hwnd, sClassName, 256)
'//Only want visible chrome windows
If sClassName.ToString = "Chrome_WidgetWin_1" Then
FindChromeTabsURL(hwnd)
End If
End If
Return True
End Function
Private Sub FindChromeTabs(hwnd As IntPtr)
'//To find the tabs we first need to locate something reliable - the 'New Tab' button
Dim rootElement As AutomationElement = AutomationElement.FromHandle(hwnd)
Dim condNewTab As Condition = New PropertyCondition(AutomationElement.NameProperty, "New Tab")
'//Find the 'new tab' button
Dim elemNewTab As AutomationElement = rootElement.FindFirst(TreeScope.Descendants, condNewTab)
'//No tabstrip found
If elemNewTab = Nothing Then Exit Sub
'//Get the tabstrip by getting the parent of the 'new tab' button
Dim tWalker As TreeWalker = TreeWalker.ControlViewWalker
Dim elemTabStrip As AutomationElement = tWalker.GetParent(elemNewTab)
'//Loop through all the tabs and get the names which is the page title
Dim tabItemCondition As Condition = New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem)
For Each tabItem As AutomationElement In elemTabStrip.FindAll(TreeScope.Children, tabItemCondition)
Debug.WriteLine(tabItem.Current.Name)
Next
End Sub
Private Sub FindChromeTabsURL(ByVal hwnd As IntPtr)
'//To find the tabs we first need to locate something reliable - the 'New Tab' button
Dim rootElement As AutomationElement = AutomationElement.FromHandle(hwnd)
Dim condNewTab As Condition = New PropertyCondition(AutomationElement.NameProperty, "New Tab")
'retURL(hwnd)
'Exit Sub
'//Find the 'new tab' button
Dim elemNewTab As AutomationElement = rootElement.FindFirst(TreeScope.Descendants, condNewTab)
'//No tabstrip found
If elemNewTab = Nothing Then Exit Sub
'//Get the tabstrip by getting the parent of the 'new tab' button
Dim tWalker As TreeWalker = TreeWalker.ControlViewWalker
Dim elemTabStrip As AutomationElement = tWalker.GetParent(elemNewTab)
'//Loop through all the tabs and get the names which is the page title
Dim tabItemCondition As Condition = New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem)
For Each tabItem As AutomationElement In elemTabStrip.FindAll(TreeScope.Children, tabItemCondition)
Debug.WriteLine(tabItem.Current.Name)
Next
End Sub
And using the below code I am able to get the URL of the selected "active" tab in chrome browser.
Dim procsChrome As Process() = Process.GetProcessesByName("chrome")
For Each chrome As Process In procsChrome
If chrome.MainWindowHandle = IntPtr.Zero Then Continue For
Dim elm As AutomationElement = AutomationElement.FromHandle(hwnd)
Dim elmUrlBar As AutomationElement = elm.FindFirst(TreeScope.Descendants, New PropertyCondition(AutomationElement.NameProperty, "Address and search bar"))
If elmUrlBar IsNot Nothing Then
Dim patterns As AutomationPattern() = elmUrlBar.GetSupportedPatterns()
If patterns.Length > 0 Then
Dim val As ValuePattern = DirectCast(elmUrlBar.GetCurrentPattern(patterns(0)), ValuePattern)
If Not elmUrlBar.GetCurrentPropertyValue(AutomationElement.HasKeyboardFocusProperty) Then MsgBox(LCase(val.Current.Value).Trim)
'Exit For
End If
End If
Next
I am unable to figure out how to get the URLs of all open tabs instead of only names as its done by the first code above.Any help will be much useful.. thanks in advance :-)
I have tried all examples and methods in the below post and it does not seem to produce correct results..
Stackoverflow post similar to this post
Regards,
Sen
Upvotes: 1
Views: 2150
Reputation: 2617
You can get the value of the address box relatively easily. Something along these lines will work:
Dim rootElement As AutomationElement = AutomationElement.FromHandle(hwnd)
Dim addressCondition As Condition = New PropertyCondition(AutomationElement.NameProperty, "Address and search bar")
Dim addressBar = rootElement.FindFirst(TreeScope.Descendants, addressCondition)
Debug.WriteLine(addressBar.GetCurrentPattern(ValuePattern.Pattern).Current.Value)
This will give you the URL of the currently selected tab. Note: There is only one address box for all tabs - the value in the box changes as the user selects each tab (ie. there isn't a seperate address box for each tab).
You could select each tab and then take the value from the address box. Something like this should work:
Dim tabItemCondition As Condition = New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem)
For Each tabItem As AutomationElement In elemTabStrip.FindAll(TreeScope.Children, tabItemCondition)
Dim selectionItemPattern As SelectionItemPattern = tabItem.GetCurrentPattern(SelectionItemPattern.Pattern)
selectionItemPattern.Select()
... (Grab the address box value here)
Next
A very quick try of this on Chrome 55 didn't work for me and threw an error that the SelectionItem pattern was not supported even though it is shown as available using Inspect.exe. There seems to be a related question here: Control pattern availability is set to true but returns `Unsupported pattern.` exception
You can also use SendKeys
to move through the tabs. Add the following declaration at the start of your code:
Private Declare Function SetForegroundWindow Lib "user32" (ByVal hWnd As IntPtr) As Boolean
Then your FindChromeTabsURL() looks like this:
Private Sub FindChromeTabsURL(ByVal hwnd As IntPtr)
Dim rootElement As AutomationElement = AutomationElement.FromHandle(hwnd)
Dim condNewTab As Condition = New PropertyCondition(AutomationElement.NameProperty, "New Tab")
Dim elemNewTab As AutomationElement = rootElement.FindFirst(TreeScope.Descendants, condNewTab)
If elemNewTab = Nothing Then Exit Sub
'//Get the tabstrip by getting the parent of the 'new tab' button
Dim tWalker As TreeWalker = TreeWalker.ControlViewWalker
Dim elemTabStrip As AutomationElement = tWalker.GetParent(elemNewTab)
SetForegroundWindow(hwnd)
Dim addressCondition As Condition = New PropertyCondition(AutomationElement.NameProperty, "Address and search bar")
Dim addressBar = rootElement.FindFirst(TreeScope.Descendants, addressCondition)
Dim tabItemCondition As Condition = New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem)
For Each tabItem As AutomationElement In elemTabStrip.FindAll(TreeScope.Children, tabItemCondition)
SendKeys.Send("^{TAB}")
Debug.WriteLine(addressBar.GetCurrentPattern(ValuePattern.Pattern).Current.Value)
Next
End Sub
Upvotes: 1