问题
So I have code that extracts all the tabs from a window of chrome.
However if I there are multiple windows open, only the most recent one is recognised.
Is it possible to extract the tabs from multiple windows instead of only the most recent one?
EDIT: The code that I use and needs fixing:
public List<string> ChromeTabs()
{
List<string> ret = new List<string>();
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); // <- Error on this line
// 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))
{
ret.Add(tabitem.Current.Name);
//Console.WriteLine(tabitem.Current.Name);
}
continue;
}
}
return ret;
}`
回答1:
I was also running into this issue where only the most recent used Google Chrome window was returning a non-zero MainWindowHandle
which was in turn preventing me from getting tab information from other Google Chrome windows.
I ended up fixing this by enumerating through the desktop windows and finding the Handle
of each Google Chrome process that adhered to a set of rules that I found (through hours of debugging) that reliably returns browser windows.
I was able to pass the Handles
found during desktop window enumeration to the typical AutomationElement
method used to get the tab information of all running Google Chrome windows.
delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);
[DllImport("user32.dll")]
private static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumWindowsProc ewp, int lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern bool GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
private static extern uint GetWindowText(IntPtr hWnd, StringBuilder lpString, uint nMaxCount);
[DllImport("user32.dll")]
private static extern uint GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
// get all the process id's of the running chrome processes
Process[] chromeProcesses = Process.GetProcessesByName("chrome");
List<uint> chromeProcessIds = chromeProcesses.Select(x => (unit)x.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);
foreach (IntPtr ptr in windowHandles)
{
AutomationElement root = AutomationElement.FromHandle(ptr);
// continue grabbing Chrome tab information using the AutomationElement method
...
}
来源:https://stackoverflow.com/questions/44602890/c-sharp-how-to-get-tabs-from-chrome-in-multiple-windows