Getting the current tab's URL from Google Chrome using C#
Edit: Seems like the code in my answer here does not work anymore (though the idea of using AutomationElement
does still work) for the later Chrome versions, so look through the other answers for different versions. For example, here's one for Chrome 54: https://stackoverflow.com/a/40638519/377618
The following code seems to work, (thanks to icemanind's comment) but is however resource intensive. It takes about 350ms to find elmUrlBar... a little slow.
Not to mention that we have the problem of working with multiple chrome
processes running at the same time.
// there are always multiple chrome processes, so we have to loop through all of them to find the
// process with a Window Handle and an automation element of name "Address and search bar"
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process chrome in procsChrome) {
// the chrome process must have a window
if (chrome.MainWindowHandle == IntPtr.Zero) {
continue;
}
// find the automation element
AutomationElement elm = AutomationElement.FromHandle(chrome.MainWindowHandle);
AutomationElement elmUrlBar = elm.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.NameProperty, "Address and search bar"));
// if it can be found, get the value from the URL bar
if (elmUrlBar != null) {
AutomationPattern[] patterns = elmUrlBar.GetSupportedPatterns();
if (patterns.Length > 0) {
ValuePattern val = (ValuePattern)elmUrlBar.GetCurrentPattern(patterns[0]);
Console.WriteLine("Chrome URL found: " + val.Current.Value);
}
}
}
Edit: I wasn't happy with the slow method above, so I made it faster (now 50ms) and added some URL validation to make sure we got the correct URL instead of something the user might be searching for on the web, or still being busy typing in the URL. Here's the code:
// there are always multiple chrome processes, so we have to loop through all of them to find the
// process with a Window Handle and an automation element of name "Address and search bar"
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process chrome in procsChrome) {
// the chrome process must have a window
if (chrome.MainWindowHandle == IntPtr.Zero) {
continue;
}
// find the automation element
AutomationElement elm = AutomationElement.FromHandle(chrome.MainWindowHandle);
// manually walk through the tree, searching using TreeScope.Descendants is too slow (even if it's more reliable)
AutomationElement elmUrlBar = null;
try {
// walking path found using inspect.exe (Windows SDK) for Chrome 31.0.1650.63 m (currently the latest stable)
var elm1 = elm.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Google Chrome"));
if (elm1 == null) { continue; } // not the right chrome.exe
// here, you can optionally check if Incognito is enabled:
//bool bIncognito = TreeWalker.RawViewWalker.GetFirstChild(TreeWalker.RawViewWalker.GetFirstChild(elm1)) != null;
var elm2 = TreeWalker.RawViewWalker.GetLastChild(elm1); // I don't know a Condition for this for finding :(
var elm3 = elm2.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, ""));
var elm4 = elm3.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ToolBar));
elmUrlBar = elm4.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Custom));
} catch {
// Chrome has probably changed something, and above walking needs to be modified. :(
// put an assertion here or something to make sure you don't miss it
continue;
}
// make sure it's valid
if (elmUrlBar == null) {
// it's not..
continue;
}
// elmUrlBar is now the URL bar element. we have to make sure that it's out of keyboard focus if we want to get a valid URL
if ((bool)elmUrlBar.GetCurrentPropertyValue(AutomationElement.HasKeyboardFocusProperty)) {
continue;
}
// there might not be a valid pattern to use, so we have to make sure we have one
AutomationPattern[] patterns = elmUrlBar.GetSupportedPatterns();
if (patterns.Length == 1) {
string ret = "";
try {
ret = ((ValuePattern)elmUrlBar.GetCurrentPattern(patterns[0])).Current.Value;
} catch { }
if (ret != "") {
// must match a domain name (and possibly "https://" in front)
if (Regex.IsMatch(ret, @"^(https:\/\/)?[a-zA-Z0-9\-\.]+(\.[a-zA-Z]{2,4}).*$")) {
// prepend http:// to the url, because Chrome hides it if it's not SSL
if (!ret.StartsWith("http")) {
ret = "http://" + ret;
}
Console.WriteLine("Open Chrome URL found: '" + ret + "'");
}
}
continue;
}
}
C# Get the URL of the active tab of browser
I have found solution which works for me for all browsers tested on (Yandex (chromium based) Chrome and Firefox it works on all three).
First I changed from using System.Windows.Automation
to IUIAutomation
because the former was really slow.
So for everyone looking for solution to similar problem first go to dependencies and right click to dependencies and press "Add COM Reference..":
Then find UIAutomationClient you could put UI in the search bar top right to find it easily:
After you have added it here is the code:
private readonly CUIAutomation _automation;
public YourMainClass()
{
_automation = new CUIAutomation();
_automation.AddFocusChangedEventHandler(null, new FocusChangeHandler(this));
}
public class FocusChangeHandler : IUIAutomationFocusChangedEventHandler
{
private readonly YourMainClass _listener;
public FocusChangeHandler(YourMainClass listener)
{
_listener = listener;
}
public void HandleFocusChangedEvent(IUIAutomationElement element)
{
if (element != null)
{
using (Process process = Process.GetProcessById(element.CurrentProcessId))
{
try
{
IUIAutomationElement elm = this._listener._automation.ElementFromHandle(process.MainWindowHandle);
IUIAutomationCondition Cond = this._listener._automation.CreatePropertyCondition(30003, 50004);
IUIAutomationElementArray elm2 = elm.FindAll(TreeScope.TreeScope_Descendants, Cond);
for (int i = 0; i < elm2.Length; i++)
{
IUIAutomationElement elm3 = elm2.GetElement(i);
IUIAutomationValuePattern val = (IUIAutomationValuePattern)elm3.GetCurrentPattern(10002);
if (val.CurrentValue != "")
{
Debug.WriteLine("URL found: " + val.CurrentValue);
}
}
}
catch { }
}
}
}
}
And at the very top put these two lines
using UIAutomationClient;
using TreeScope = UIAutomationClient.TreeScope;
And also you should change "YourMainClass" with your own class as needed.
c# Getting Chrome URL's from all tab
this code is working for me and get URL of active tab of chrome
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process chrome in procsChrome)
{
// the chrome process must have a window
if (chrome.MainWindowHandle == IntPtr.Zero)
{
continue;
}
// find the automation element
AutomationElement elm = AutomationElement.FromHandle(chrome.MainWindowHandle);
AutomationElement elmUrlBar = elm.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.NameProperty, "Address and search bar"));
// if it can be found, get the value from the URL bar
if (elmUrlBar != null)
{
AutomationPattern[] patterns = elmUrlBar.GetSupportedPatterns();
if (patterns.Length > 0)
{
ValuePattern val = (ValuePattern)elmUrlBar.GetCurrentPattern(patterns[0]);
Console.WriteLine("Chrome URL found: " + val.Current.Value);
listbox.Items.Add(val.Current.Value);
}
}
}
How to get the current URL from Chrome 28 from another Windows application?
Chrome supports the Windows accessibility APIs, so you can use those to extract information both from the chrome - including the broswer bar - and also from web pages. Think of this API as a more abstract version of enumerating window controls.
Check out the Inspect Objects tool to explore what information you can get access to - it does look as though the address bar and contents are available.
You can get the same information in C# using the AutomationElement set of classes:
- use AutomationElement windowEl = AutomationElement.FromHandle(new IntPtr(hwnd)); as a starting point if you know the HWND of the tree
- then try AutomationElement editEl = AutomationElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit)) to find the first element that has ControlType of Edit. FindFirst does a depth-first search of the tree, which looks like it will work in this case; can use the TreeWalker classes if you want to walk step-by-step yourself.
- 'cast' the found element to a ValuePattern using: ValuePattern vp = (ValuePattern) editEl.GetCurrentPattern(ValuePattern.Pattern);
- Finally, use string str = vp.Current.Value; to get the value of the edit.
Related Topics
Scraping Webpage Generated by JavaScript with C#
How to Get the Computer Name in .Net
How to Get All Classes Within a Namespace
Adding Stylesheets Programmatically in ASP.NET
Duplicate Keys in .Net Dictionaries
Nullable Type as a Generic Parameter Possible
Ide's for C# Development on Linux
Bundler Not Including .Min Files
Accessing MVC's Model Property from JavaScript
How to Post an Array of Complex Objects with JSON, Jquery to ASP.NET MVC Controller
Why Are Unsigned Int's Not Cls Compliant
Accessing Password Protected Network Drives in Windows in C#
Why Firefox Requires Geckodriver
What Does $ Mean Before a String