How can I get the url from a running instance of Chrome or Opera using C# .NET windows form app? Thanks!
-
Can you describe a little more of what you're trying to accomplish? – Yuriy Faktorovich Aug 26 '10 at 21:27
-
2Choose IE and we can help you out. – Hans Passant Aug 26 '10 at 21:39
-
1Yes, of course :) I'm trying to do app, that will be getting url of (current tab) active website (neutrally which one: Firefox, IE, Chrome etc.) to my app. In Firefox I use NDde.dll and DdeClient class - is very simple but it's works only with Firefox. Similary a DllImport of user32.dll help me to get url from IE...only IE :) (or I don't know how to extend this for other browsers) Do you know how to do this in other browsers? Any general method or specifically to particular browser. – Saint Aug 26 '10 at 21:39
-
Look here the answer with Microsoft UI Automation. Worked for me for Firefox 41.0 and Chromium 48 ---> http://stackoverflow.com/questions/5317642/retrieve-current-url-from-c-sharp-windows-forms-application/33191637#33191637 – Oct 17 '15 at 21:40
7 Answers
Part 2:
Basically I have too much code to separate out the minimum for this example, but I have provided my own algorithm below for you to pour over.
This one also keeps track of tabs in browsers, as and when they reappear (IE only), so you will need to strip out the bits you don't want. I seem to remember I fixed this for IE8, but not sure if that fix went in this code, so don't be surprised if it needs a little tweak :)
// Iterate all browsers and record the details
IntPtr hWnd = IntPtr.Zero;
NativeWIN32.EnumChildWindows(hWnd, new NativeWIN32.Win32Callback(BrowserEnumCallback), hWnd);
/// <summary>
/// Called back for each IE browser.
/// </summary>
/// <param name="hWnd"></param>
/// <param name="lParam"></param>
/// <returns></returns>
static bool BrowserEnumCallback(IntPtr hWnd, IntPtr lParam)
{
// Is this app IE?
if (NativeWIN32.GetClassName(hWnd) == "IEFrame")
{
// If this is a new browser, add it
if (!BrowserWindows.ContainsKey(hWnd))
{
// Record the Browser
BrowserWindow browser = new BrowserWindow()
{
hWnd = hWnd
};
// Store the browser in the temp list and temp member
TempCurrentBrowser = browser;
BrowserWindows.Add(hWnd, browser);
}
else
{
// Store the browser in the temp list and temp member
TempCurrentBrowser = BrowserWindows[hWnd];
}
TempCurrentBrowser.WindowText = NativeWIN32.GetWindowText(hWnd);
TempCurrentBrowser.Found = true;
// Now that we know it is a browser, look for tabbed windows and address bar
NativeWIN32.EnumChildWindows(hWnd, new NativeWIN32.Win32Callback(BrowserEnumChildrenCallback), hWnd);
}
return true;
}
/// <summary>
/// Called back for each child window in the browser
/// </summary>
/// <param name="hWnd"></param>
/// <param name="lParam"></param>
/// <returns></returns>
static bool BrowserEnumChildrenCallback(IntPtr hWnd, IntPtr lParam)
{
string classname = NativeWIN32.GetClassName(hWnd);
switch (classname)
{
// This is the main address bar
case "Edit":
{
string url = NativeWIN32.GetWindowText(hWnd);
if (url.StartsWith(@"http://") || url.StartsWith(@"https://") || url.StartsWith("about:"))
{
TempCurrentBrowser.Url = url;
return true;
}
}
break;
case "ComboBoxEx32":
{
string url = NativeWIN32.GetWindowText(hWnd);
if (url.StartsWith(@"http://") || url.StartsWith(@"https://") || url.StartsWith("about:"))
{
TempCurrentBrowser.Url = url;
return true;
}
}
break;
// Record any sub pages still active, by title to avoid revisiting popup
// If this name matches the name of the browser, it is the current window
// If so, record the browser url for reference in that tab window
case "TabWindowClass":
{
string title = NativeWIN32.GetWindowText(hWnd);
BrowserTabWindow tabWindow;
if (!TempCurrentBrowser.TabWindows.ContainsKey(hWnd))
{
// Create a new tabbed window for the current browser
tabWindow = new BrowserTabWindow()
{
hWnd = hWnd
};
TempCurrentBrowser.TabWindows.Add(hWnd, tabWindow);
}
else
{
tabWindow = TempCurrentBrowser.TabWindows[hWnd];
}
tabWindow.WindowText = title;
tabWindow.Found = true;
}
break;
}
return true;
}
Part 1:
If Microsoft Spy++ can see the address control, then yes it is possible.
I don't have Opera installed, but the Chrome control hierarchy in Spy++ looks like this:
I have done similar things with Internet Explorer:
- To record a diary the sites visited - then a popup asks the user what they were doing
- To display a widget that pops up when certain known sites were visited
Firefox was the problem child as it renders the address bar internally and not via a windows control but I see you have already found the solution to that one.
In C# you need to make unmanaged calls to Windows API methods. As you can see from the C# API code alone (below) it can get a little involved:
const int WM_GETTEXT = 0xD;
// used for an output LPCTSTR parameter on a method call
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct STRINGBUFFER
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string szText;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindowEx(IntPtr parent /*HWND*/,
IntPtr next /*HWND*/,
string sClassName,
IntPtr sWindowTitle);
/// <summary>
///
/// </summary>
/// <param name="hWnd">handle to destination window</param>
/// <param name="msg">message</param>
/// <param name="wParam">first message parameter</param>
/// <param name="lParam"second message parameter></param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd,
int msg, int wParam, out STRINGBUFFER ClassName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, out STRINGBUFFER ClassName, int nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, out STRINGBUFFER ClassName, int nMaxCount);
//[DllImport("user32.dll")]
//[return: MarshalAs(UnmanagedType.Bool)]
//static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.Dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
/// <summary>
/// Helper to get window classname
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
static public string GetClassName(IntPtr hWnd)
{
NativeWIN32.STRINGBUFFER sLimitedLengthWindowTitle;
NativeWIN32.GetClassName(hWnd, out sLimitedLengthWindowTitle, 256);
return sLimitedLengthWindowTitle.szText;
}
/// <summary>
/// Helper to get window text
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
static public string GetWindowText(IntPtr hWnd)
{
NativeWIN32.STRINGBUFFER sLimitedLengthWindowTitle;
SendMessage(hWnd, WM_GETTEXT, 256, out sLimitedLengthWindowTitle);
//NativeWIN32.GetWindowText(hWnd, out sLimitedLengthWindowTitle, 256);
return sLimitedLengthWindowTitle.szText;
}
The algorithm involved basically searches all windows from the Desktop on down until it finds Browser windows (based on specific class or window attributes). It then searches for specific child elements based on the type of browser. When you finally get to the address control you can extract the address from the control. Hopefully my helper class code will speed your development.
"NativeWIN32" Followup - Dec 2013
The NativeWIN32
references are simply to a wrapper class containing useful constants and methods for other Win32 features. I have added it here in full:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace YourProject
{
/// <summary>
/// Wrapper for native win32 calls
/// </summary>
public class NativeWIN32
{
const int WM_GETTEXT = 0xD;
// used for an output LPCTSTR parameter on a method call
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct STRINGBUFFER
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string szText;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindowEx(IntPtr parent /*HWND*/,
IntPtr next /*HWND*/,
string sClassName,
IntPtr sWindowTitle);
/// <summary>
///
/// </summary>
/// <param name="hWnd">handle to destination window</param>
/// <param name="msg">message</param>
/// <param name="wParam">first message parameter</param>
/// <param name="lParam"second message parameter></param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd,
int msg, int wParam, out STRINGBUFFER ClassName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, out STRINGBUFFER ClassName, int nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, out STRINGBUFFER ClassName, int nMaxCount);
//[DllImport("user32.dll")]
//[return: MarshalAs(UnmanagedType.Bool)]
//static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.Dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
/// <summary>
/// Helper to get window classname
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
static public string GetClassName(IntPtr hWnd)
{
NativeWIN32.STRINGBUFFER sLimitedLengthWindowTitle;
NativeWIN32.GetClassName(hWnd, out sLimitedLengthWindowTitle, 256);
return sLimitedLengthWindowTitle.szText;
}
/// <summary>
/// Helper to get window text
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
static public string GetWindowText(IntPtr hWnd)
{
NativeWIN32.STRINGBUFFER sLimitedLengthWindowTitle;
SendMessage(hWnd, WM_GETTEXT, 256, out sLimitedLengthWindowTitle);
//NativeWIN32.GetWindowText(hWnd, out sLimitedLengthWindowTitle, 256);
return sLimitedLengthWindowTitle.szText;
}
}
}

- 92,391
- 25
- 181
- 202
-
How do you programatically identify which one you want? Just look for "http"? or is there some more reliable way that I'm not aware of? – Davy8 Aug 26 '10 at 22:14
-
Yes, it's good solution but unfortunately only by IE, because in Chrome every tab hasn't hidden url. I checked this now and to 10 tabs there is only one has url on this tree in spy++. So it's not this way, or I have specific version of browser ;) Check this out and let me know if I was wrong. – Saint Aug 26 '10 at 22:44
-
@Davy8 - in IE only one control has url. Control where ClassName is "edit". So if you go from parent to child, from parent to child...you meet this class and then you know there's a url. In example of Chrome by HiTech Magic this class has name Chrome_AutocompleteEditView. But I suppose it's probably in this tab ...only this tab :) – Saint Aug 26 '10 at 22:53
-
1@Saint... why would you want to know the URL of a tab the user is not looking at? You might need to explain your requirements a bit further? (are they nefarious?) :) – iCollect.it Ltd Aug 27 '10 at 07:45
-
Aaaa, everything's ok :) It was because lack of refreshing Spy++ result window. I thought that a Chrome_AutocompleteEditView is still in one of tabs, and it's not make changes :) Now I know that was wrong :) But I still have a little problem, because a way of getting url from IE doesn't work here...and I don't know why. The handle of mainWindow is other than I want. Can you tell me how to get handle another window...that with a child named Chrome_AutocompleteEditView. Code below: – Saint Aug 27 '10 at 15:08
-
1http://img840.imageshack.us/img840/8938/chromee.png I should go to the next Window Chrome_WidgetWin_0, but don't what is the best way to do this. Any idea? :) – Saint Aug 27 '10 at 15:17
-
@Saint, I have added more of my actual algorithm for you (IE version). It does a lot more than you need so please feel free to strip out the bits you don't want/need. Cheers – iCollect.it Ltd Aug 27 '10 at 17:52
-
Ok, thank you very much. It's look nice and helpfull, but I analyse this code tomorrow. Thanks one more time :) – Saint Aug 28 '10 at 01:06
-
Thank you HiTech Magic for yours second code. It doesn't help me but btw showed me way to solve my problem :) I'm looking for a main process FindWindow("Chrome_WidgetWin_0", null) and in loop while() until this returned handle != IntPtr.Zero...I'm searching next and next process by GetWindow(...). If one of children contents "Chrome_AutocompleteEditView" I get url :) Now it's so easy :) Maybe this help someone by similar problem :) DllImport("user32.dll") rules ;) – Saint Sep 01 '10 at 21:31
-
-
@nawfal: NativeWIN32 is just a class/wrapper for useful methods and constants. I will dig out a copy and add it to the answer now. – iCollect.it Ltd Dec 28 '13 at 18:19
-
1@TrueBlueAussie oops, in that case, I think you have written your wrapper twice. I think you should remove the first one. – nawfal Dec 28 '13 at 19:51
-
9 years later, it seems that chrome doesn't have a window with its title as the url as in Gone Coding's screenshot. At least I couldn't find it using Spy++. – Dave Aug 26 '22 at 00:05
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr parentHandle,
IntPtr childAfter, string className, IntPtr windowTitle);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd,
int msg, int wParam, StringBuilder ClassName);
private static string GetURL(IntPtr intPtr, string programName, out string url)
{
string temp=null;
if (programName.Equals("chrome"))
{
var hAddressBox = FindWindowEx(intPtr, IntPtr.Zero, "Chrome_OmniboxView", IntPtr.Zero);
var sb = new StringBuilder(256);
SendMessage(hAddressBox, 0x000D, (IntPtr)256, sb);
temp = sb.ToString();
}
if (programName.Equals("iexplore"))
{
foreach (InternetExplorer ie in new ShellWindows())
{
var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(ie.FullName);
if (fileNameWithoutExtension != null)
{
var filename = fileNameWithoutExtension.ToLower();
if (filename.Equals("iexplore"))
{
temp+=ie.LocationURL + " ";
}
}
}
}
if (programName.Equals("firefox"))
{
DdeClient dde = new DdeClient("Firefox", "WWW_GetWindowInfo");
dde.Connect();
string url1 = dde.Request("URL", int.MaxValue);
dde.Disconnect();
temp = url1.Replace("\"","").Replace("\0","");
}
url = temp;
return temp;
}
Please do following to run this code Add Reference > Com > Microsoft.Internet.Controls from VS.NET in your project
Download the bin from http://ndde.codeplex.com/ for DdeClient class and add it to your project

- 795
- 4
- 13
-
1I have tested the above code for Firefox, works fine !! however it only gets me the URL and the Page-Title. I am more interested in the HTML content of that Page. Is there any way i can get the entire page(HTML content) parsed into a string ?? – LetsKickSomeAss in .net Jun 09 '13 at 19:56
Unless the browsers are documented to provide that information themselves I don't think there's a reliable way to do so.
That being said, I'm pretty sure at least Chrome stores history information on disk somewhere, so your best bet may be to figure out where, what format it's in, and how to read it.

- 30,868
- 25
- 115
- 173
-
Yes, it is kind of solution but it doesn't work with portable browsers. You can delete folder or use this on the pendrive and there's no mark of visited website. So it's not good solution for me :) – Saint Aug 26 '10 at 21:45
IE11, Chrome, Firefox, Opera, Safari all have interfaces to get URL and even the DOM, or at least the document/HTML buffer. FF actually has a DLL with exports to do it for you, I forget how to reliably do it under the others, but I know it is done.

- 109
- 6
-
4As it stands, a tidbit of info like this is best as a comment to the OP. If you can edit in some details after you remember, then it could qualify as a good answer. – bland Dec 24 '13 at 16:41
Another way to tackle this problem might be using the UI Automation framework.
This example reads Chrome's current url:
var app = AutomationElement.FromHandle(new IntPtr(chrome_hwnd));
var propFindText = new PropertyCondition(AutomationElement.NameProperty, "Address and search bar");
var textbox = app.FindFirst(TreeScope.Descendants, propFindText);
Debug.WriteLine( textbox.GetCurrentPropertyValue(ValuePattern.ValueProperty).ToString());
Here is an excellent tutorial on UI automation.

- 1,940
- 3
- 19
- 27
Find out open Url´s from IE
Add the reference "Microsoft Internet Controls" from the COM tab, then:
using SHDocVw;
My full directive´s list look like this:
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using SHDocVw;
and now to find out tab urls from IE, do this:
Dictionary<int, string> ieUrlsDictionary = new Dictionary<int, string>();
ShellWindows ieShellWindows = new SHDocVw.ShellWindows();
string sProcessType;
int i = 0;
foreach (InternetExplorer ieTab in ieShellWindows)
{
sProcessType = Path.GetFileNameWithoutExtension(ieTab.FullName).ToLower();
if (sProcessType.Equals("iexplore") && !ieTab.LocationURL.Contains("about:Tabs"))
{
ieUrlsDictionary[i] = ieTab.LocationURL;
i++;
}
}
//show list of url´s
for (int j = 0; j < ieUrlsDictionary.Count; j++)
{
Console.WriteLine(ieUrlsDictionary[j]);
}

- 21
- 1
- 1
- 6
I just use something like this usually:
//as soon as you open the browser: browserHandle = GetForegroundWindow();
SetFocus(browserHandle);
// send ctrl-d to get in address bar
SendKeys.SendWait("%{d}");
// send ctrl- to copy
SendKeys.SendWait("%{c}");
// then paste it where you want it
You need a DLL Import:
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();