user6879072
user6879072

Reputation: 441

How to get a list of open tabs from chrome? | C#

So I want to extract the open tabs from google chrome (title, URL) and list theme out kind of like in the chrome task manager. So far I have tried to filter all the chrome processes and get the window titles but that doesn't work:

var procs = Process.GetProcesses();

...

foreach (var proc in procs)
{
   if (Convert.ToString(proc.ProcessName) == "chrome")
   {
      Console.WriteLine("{0}: {1} | {2} | {3} ||| {4}\n", i, proc.ProcessName, runtime, proc.MainWindowTitle, proc.Handle);
   }
}

This doesn't give me the address or the title of the tab, is there another way to do it?

Upvotes: 6

Views: 21474

Answers (6)

Nearon
Nearon

Reputation: 81

So the fusion of validated Mostafiz's answer with the CodeWarrior adjustement is :

  Process[] procsChrome = Process.GetProcessesByName("chrome");
    if ( (procsChrome?.Length ?? 0) <= 0)
    {
    Console.WriteLine("Chrome is not running");
                }
                else
                {
                    foreach (Process proc in procsChrome)
                    {
                        // the chrome process must have a window 
                        if (proc.MainWindowHandle == IntPtr.Zero)
                        {
                            continue;
                        }
                        // to find the tabs we first need to locate something reliable - the 'New Tab' button 
                        AutomationElement root = AutomationElement.FromHandle(proc.MainWindowHandle);
                        Condition condition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
                        AutomationElementCollection tabs = root?.FindAll(TreeScope.Descendants, condition);
                        foreach(AutomationElement ae in tabs)
                        {
                            Trace.WriteLine(ae.Current.Name);       
                        }
                    }
                }

Upvotes: 2

Ammar Bukhari
Ammar Bukhari

Reputation: 2122

This is what worked for me in finding all the Chrome tabs that are separate windows.

  [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", SetLastError = true)]
        static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        const uint SWP_NOSIZE = 0x0001;
        const uint SWP_NOZORDER = 0x0004;
        const int SWP_SHOWWINDOW = 0x0040;


        // get all the process id's of the running chrome processes
        Process[] chromeProcesses = Process.GetProcessesByName("chrome");
        List<uint> chromeProcessIds = chromeProcesses.Select(xx => (uint)xx.Id).ToList();

        // a list to store the handles of the Google Chrome windows that we'll find
        List<IntPtr> windowHandles = new List<IntPtr>();

        EnumWindowsProc enumerateHandle = delegate (IntPtr hWnd, int lParam)
        {
            // get the id of the process of the window we are enumerating over
            uint id;
            GetWindowThreadProcessId(hWnd, out id);

            // if the process we're enumerating over has an id in our chrome process ids, we need to inspect it to see if it is a window or other process
            if (chromeProcessIds.Contains(id))
            {
                // get the name of the class of the window we are inspecting
                var clsName = new StringBuilder(256);
                var hasClass = GetClassName(hWnd, clsName, 256);
                if (hasClass)
                {
                    // get the text of the window we are inspecting
                    var maxLength = (int)GetWindowTextLength(hWnd);
                    var builder = new StringBuilder(maxLength + 1);
                    GetWindowText(hWnd, builder, (uint)builder.Capacity);

                    var text = builder.ToString();
                    var className = clsName.ToString();

                    // actual Google Chrome windows have text set to the title of the active tab
                    // in my testing, this needs to be coupled with the class name equaling "Chrome_WidgetWin_1". 
                    // i haven't tested this with other versions of Google Chrome
                    if (!string.IsNullOrWhiteSpace(text) && className.Equals("Chrome_WidgetWin_1", StringComparison.OrdinalIgnoreCase))
                    {
                        // if we satisfy the conditions, this is a Google Chrome window. Add the handle to the list of handles to use later.
                        windowHandles.Add(hWnd);
                    }
                }
            }
            return true;
        };

        EnumDesktopWindows(IntPtr.Zero, enumerateHandle, 0);

        int ctabs = windowHandles.Count;
        int screens = Screen.AllScreens.Length;
        int ctabsonscreen = ctabs / screens;
        Screen screen = Screen.AllScreens[0];
        //int x = screen.WorkingArea.X - 10, y = screen.WorkingArea.Y, w = screen.WorkingArea.Width + 40, h = screen.WorkingArea.Height + 10;
        int x = screen.WorkingArea.X , y = screen.WorkingArea.Y, w = screen.WorkingArea.Width , h = screen.WorkingArea.Height ;
        int ww = (w / ctabs);

        sb("Start: " + ww + " " + x + " " +y + " " + w + " " + h);

        foreach (IntPtr ptr in windowHandles)
        {
            AutomationElement root = AutomationElement.FromHandle(ptr);
            //sb(root.Current.Name);

            if (ptr != IntPtr.Zero)
            {                                        
                sb(" " + x + " " + y + " " + ww + " " + h + " " + root.Current.Name);
                SetWindowPos(ptr, IntPtr.Zero, x, y, ww, h, SWP_NOZORDER | SWP_SHOWWINDOW);
                x += ww;
            }

        }

Upvotes: 0

KarlsonxD
KarlsonxD

Reputation: 23

didn't found a way to get all URLS, seems like only current active is possible... but here is my code sample to get all Tab Names even if you seperated them in different windows:
you need

UIAutomationClient.dll
UIAutomationTypes.dll 

added to your References as seen above and
using System.Windowsw.Automation

Process[] procsEdge = Process.GetProcessesByName("msedge");
if (procsEdge.Length <= 0)
{
   Console.WriteLine("Edge is not running");
}
else
{
   foreach (Process proc in procsEdge)
   {
        //the Edge process must have a window
        if (proc.MainWindowHandle != IntPtr.Zero)
        {
            AutomationElement root = AutomationElement.FromHandle(proc.MainWindowHandle);
            TreeWalker treewalker = TreeWalker.ControlViewWalker;
            AutomationElement rootParent = treewalker.GetParent(root);
            Condition condWindow = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window);
            AutomationElementCollection edges = rootParent.FindAll(TreeScope.Children, condWindow);
            Condition condNewTab = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
            foreach (AutomationElement e in edges)
            {
                //check if the root element is named with *Edge*
                if (e.Current.Name.Contains("Edge"))
                {
                    //var beb = e.FindAll(TreeScope.Children, condNewTab);
                    foreach (AutomationElement tabitem in e.FindAll(TreeScope.Descendants, condNewTab))
                    {
                        Console.WriteLine("TABNAME: " + tabitem.Current.Name);
                    }
                }
            }
        }
   }
} 

maybe that is helping somebody i realized to late that without the URL's it's not helping me...

Upvotes: 1

Jeremi Martini
Jeremi Martini

Reputation: 81

You can try this:

AutomationElement root = AutomationElement.FromHandle(process.MainWindowHandle);
Condition condition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
var tabs = root.FindAll(TreeScope.Descendants, condition);

Upvotes: 7

nombrote
nombrote

Reputation: 41

It's looking for a english content "new tab", if your browser it's not in english it will not find the text and not work

Upvotes: 3

Mostafiz
Mostafiz

Reputation: 7352

First Reference two dll

UIAutomationClient.dll
UIAutomationTypes.dll

Located: C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0 (or 3.5)

Then

using System.Windows.Automation;

and the code

Process[] procsChrome = Process.GetProcessesByName("chrome");
if (procsChrome.Length <= 0)
{
   Console.WriteLine("Chrome is not running");
}
else
{
   foreach (Process proc in procsChrome)
   {
      // the chrome process must have a window 
      if (proc.MainWindowHandle == IntPtr.Zero)
      {
          continue;
      }
      // to find the tabs we first need to locate something reliable - the 'New Tab' button 
      AutomationElement root = AutomationElement.FromHandle(proc.MainWindowHandle);
      Condition condNewTab = new PropertyCondition(AutomationElement.NameProperty, "New Tab");
      AutomationElement elmNewTab = root.FindFirst(TreeScope.Descendants, condNewTab);
      // get the tabstrip by getting the parent of the 'new tab' button 
      TreeWalker treewalker = TreeWalker.ControlViewWalker;
      AutomationElement elmTabStrip = treewalker.GetParent(elmNewTab);
      // loop through all the tabs and get the names which is the page title 
      Condition condTabItem = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
      foreach (AutomationElement tabitem in elmTabStrip.FindAll(TreeScope.Children, condTabItem))
      {
          Console.WriteLine(tabitem.Current.Name);
      }
   }
}

Upvotes: 12

Related Questions