There used to be a way to get the active tab's URL from Google Chrome by using FindWindowEx
in combination with a SendMessage
call to get the text currently in the omnibox. A recent (?) update seems to have broken this method, since Chrome seems to be rendering everything itself now. (You can check with Spy++, AHK Window Spy or Window Detective)
To get the current URL on Firefox and Opera, you can use DDE and WWW_GetWindowInfo
. This doesn't seem to be possible on Chrome (anymore?).
This question has an answer with more info about how it used to work, which is this piece of code (which, as I explained, doesn't work anymore - hAddressBox
is 0
):
var hAddressBox = FindWindowEx( intPtr, IntPtr.Zero, "Chrome_OmniboxView", IntPtr.Zero); var sb = new StringBuilder(256); SendMessage(hAddressBox, 0x000D, (IntPtr)256, sb); temp = sb.ToString();
So my question is: Is there a new way to get the currently focused tab's URL? (Just the title is not enough)
Just right-click in Chrome's address bar select “Always show full URLs” to make Chrome show full URLs. Chrome will now always show the full URL of every web address you open. To disable this feature, right-click in the address bar again and uncheck it.
Chrome doesn't allow you to configure a new tab URL. It always opens its New Tab Page with a search bar and some browsing history. With this extension, you can use the options page to store a link to a page or even a path to a local file that will be loaded when a new tab is created.
Press Ctrl+C on Windows and Linux or Command+C on Mac to copy all your bookmarks. You can also right-click the list of selected bookmarks and choose “Copy.” Now, open the program where you want to paste all your open tab URLs (such as Notepad or TextEdit).
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; } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With