Last active
January 27, 2023 09:30
-
-
Save Jiiks/fa224592af04cb2dea8a57cbfaaa0a9d to your computer and use it in GitHub Desktop.
Browser tab title grabber
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* C# Browser Title Grabber by Jiiks | |
* Grabs titles of all tabs. | |
* Tested with Chrome and Firefox. | |
*/ | |
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Runtime.InteropServices; | |
using System.Windows.Automation; | |
namespace YourNameSpace { | |
public static class BrowserTitleGrabber { | |
public static readonly Condition TabControlCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Tab); | |
public static readonly Condition TabItemCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem); | |
private delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam); | |
[DllImport("user32.dll")] | |
private static extern bool EnumThreadWindows(uint dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam); | |
public static IEnumerable<string> GetTabTitles(EBrowser browser) { | |
switch (browser) { | |
case EBrowser.Chrome: | |
return GetTabTitles("chrome"); | |
case EBrowser.Firefox: | |
return GetTabTitles("firefox"); | |
default: | |
throw new ArgumentOutOfRangeException(nameof(browser), browser, null); | |
} | |
} | |
public static IEnumerable<string> GetTabTitles(string procName) { | |
_cBt = new List<string>(); | |
foreach (var process in Process.GetProcessesByName(procName)) { | |
foreach (ProcessThread processThread in process.Threads) { | |
EnumThreadWindows((uint) processThread.Id, EnumThreadWindowsCb, IntPtr.Zero); | |
} | |
} | |
return _cBt; | |
} | |
private static List<string> _cBt; | |
private static bool EnumThreadWindowsCb(IntPtr hWnd, IntPtr lParam) { | |
try { | |
_cBt.AddRange(GetTabTitles(hWnd)); | |
} | |
catch (Exception) { | |
// ignored | |
} | |
return true; | |
} | |
private static IEnumerable<string> GetTabTitles(IntPtr handle) { | |
if (handle == IntPtr.Zero) return new List<string>(); | |
var rootElement = AutomationElement.FromHandle(handle); | |
if(rootElement == null) return new List<string>(); | |
var tabControl = rootElement.FindFirst(TreeScope.Descendants, TabControlCondition); | |
return tabControl == null ? new List<string>() : (from AutomationElement tab in tabControl.FindAll(TreeScope.Children, TabItemCondition) select tab.Current.Name).ToList(); | |
} | |
public enum EBrowser { | |
Chrome, | |
Firefox | |
} | |
} | |
} |
epic
Seems not to be working anymore on latest chrome 109 😢
New solution:
using interop.UIAutomationCore;
public static List<string> GetTabs()
{
List<String> result = new List<string>();
Process[] allChromeProcesses = Process.GetProcessesByName("chrome");
if (allChromeProcesses.Length == 0)
return result;
Process[] mainChromes = allChromeProcesses.Where(p => !String.IsNullOrEmpty(p.MainWindowTitle)).ToArray();
if (mainChromes.Length == 0)
return result;
var uiaClassObject = new CUIAutomation();
for (int c = 0; c < mainChromes.Length; c++)
{
IUIAutomationElement chromeMainUIAElement = uiaClassObject.ElementFromHandle(mainChromes[c].MainWindowHandle);
//UIA_ControlTypePropertyId =30003, UIA_TabItemControlTypeId = 50019
IUIAutomationCondition chromeTabCondition = uiaClassObject.CreatePropertyCondition(30003, 50019);
var chromeTabCollection = chromeMainUIAElement.FindAll(interop.UIAutomationCore.TreeScope.TreeScope_Descendants, chromeTabCondition);
for (int i = 0; i < chromeTabCollection.Length; i++)
{
//UIA_LegacyIAccessiblePatternId = 10018, 0 -> Number of Chrome tab you want to activate
var lp = chromeTabCollection.GetElement(i).GetCurrentPattern(10018) as IUIAutomationLegacyIAccessiblePattern;
//lp.DoDefaultAction(); // to activate tab
String tabTitle = lp.CurrentName;
result.Add(tabTitle);
}
}
return result;
}
To generate the interop, start a "Developer Command Prompt" and execute:
tlbimp C:\Windows\System32\UIAutomationCore.dll -out:interop.UIAutomationCore.dll
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks very much for this very useful snippet.
Anyway I found an issue on Chrome.
Indeed if the chrome window is minimized, no tabs are returned.
To fix it, when the "tabControl" object isn't null, I check the Window state with "GetWindowPlacement" api.
If the window is minimized, then I invoke "ShowWindow(handle, 4)", before to continue...
In other words I show the window on last position ;)