使用c#获取chrome浏览器标题
本文关键字:浏览器 标题 chrome 获取 使用 | 更新日期: 2023-09-27 18:17:06
假设我打开了多个chrome窗口(不是选项卡),
如何查看浏览器标题?
我试了如下:
Process[] p = Process.GetProcessesByName("chrome");
foreach (Process item in p)
{
Console.WriteLine(item.MainWindowTitle);
}
但是它只返回最后一个打开的窗口名,其他都是空白。
我不得不做这样的事情,但它涉及到调用Windows API函数,这是令人惊讶的繁琐。问题是Chrome似乎对多个窗口使用一个进程或其他一些奇怪的东西,这意味着简单的方法对我不起作用。
无论如何,试试这个,看看它是否有效。基本上,它使用Chrome窗口类名(可能是Chrome_WidgetWin_0
或Chrome_WidgetWin_1
)来枚举具有该类名的所有窗口,并返回那些非空白的窗口标题。
请注意,由于某种原因,这也总是返回一个名为"Chrome App Launcher"
的窗口标题,所以您可能需要过滤掉它。
注意:你也可以在Firefox中使用"MozillaWindowClass",在IE中使用"IEFrame"(尽管这些都可能随着不同的版本而改变)。
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
namespace Demo
{
class WindowsByClassFinder
{
public delegate bool EnumWindowsDelegate(IntPtr hWnd, IntPtr lparam);
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public extern static bool EnumWindows(EnumWindowsDelegate lpEnumFunc, IntPtr lparam);
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
[DllImport("User32", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int GetWindowText(IntPtr windowHandle, StringBuilder stringBuilder, int nMaxCount);
[DllImport("user32.dll", EntryPoint = "GetWindowTextLength", SetLastError = true)]
internal static extern int GetWindowTextLength(IntPtr hwnd);
/// <summary>Find the windows matching the specified class name.</summary>
public static IEnumerable<IntPtr> WindowsMatching(string className)
{
return new WindowsByClassFinder(className)._result;
}
private WindowsByClassFinder(string className)
{
_className = className;
EnumWindows(callback, IntPtr.Zero);
}
private bool callback(IntPtr hWnd, IntPtr lparam)
{
if (GetClassName(hWnd, _apiResult, _apiResult.Capacity) != 0)
{
if (string.CompareOrdinal(_apiResult.ToString(), _className) == 0)
{
_result.Add(hWnd);
}
}
return true; // Keep enumerating.
}
public static IEnumerable<string> WindowTitlesForClass(string className)
{
foreach (var windowHandle in WindowsMatchingClassName(className))
{
int length = GetWindowTextLength(windowHandle);
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(windowHandle, sb, sb.Capacity);
yield return sb.ToString();
}
}
public static IEnumerable<IntPtr> WindowsMatchingClassName(string className)
{
if (string.IsNullOrWhiteSpace(className))
throw new ArgumentOutOfRangeException("className", className, "className can't be null or blank.");
return WindowsMatching(className);
}
private readonly string _className;
private readonly List<IntPtr> _result = new List<IntPtr>();
private readonly StringBuilder _apiResult = new StringBuilder(1024);
}
class Program
{
void run()
{
ChromeWindowTitles().Print();
}
public IEnumerable<string> ChromeWindowTitles()
{
foreach (var title in WindowsByClassFinder.WindowTitlesForClass("Chrome_WidgetWin_0"))
if (!string.IsNullOrWhiteSpace(title))
yield return title;
foreach (var title in WindowsByClassFinder.WindowTitlesForClass("Chrome_WidgetWin_1"))
if (!string.IsNullOrWhiteSpace(title))
yield return title;
}
static void Main()
{
new Program().run();
}
}
static class DemoUtil
{
public static void Print(this object self)
{
Console.WriteLine(self);
}
public static void Print(this string self)
{
Console.WriteLine(self);
}
public static void Print<T>(this IEnumerable<T> self)
{
foreach (var item in self)
Console.WriteLine(item);
}
}
}
我知道这已经回答了,但我也做了一个解决方案,枚举一个线程内的所有Windows。
它是根据Matthew Watson的解决方案构建的,因此有一些相似之处。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Chrome_Windows
{
class Program
{
[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(uint dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("User32", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr windowHandle, StringBuilder stringBuilder, int nMaxCount);
[DllImport("user32.dll", EntryPoint = "GetWindowTextLength", SetLastError = true)]
internal static extern int GetWindowTextLength(IntPtr hwnd);
private static List<IntPtr> windowList;
private static string _className;
private static StringBuilder apiResult = new StringBuilder(256); //256 Is max class name length.
private delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
static void Main(string[] args)
{
List<IntPtr> ChromeWindows = WindowsFinder("Chrome_WidgetWin_1", "chrome");
foreach (IntPtr windowHandle in ChromeWindows)
{
int length = GetWindowTextLength(windowHandle);
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(windowHandle, sb, sb.Capacity);
Console.WriteLine(sb.ToString());
}
}
private static List<IntPtr> WindowsFinder(string className, string process)
{
_className = className;
windowList = new List<IntPtr>();
Process[] chromeList = Process.GetProcessesByName(process);
if (chromeList.Length > 0)
{
foreach (Process chrome in chromeList)
{
if (chrome.MainWindowHandle != IntPtr.Zero)
{
foreach (ProcessThread thread in chrome.Threads)
{
EnumThreadWindows((uint)thread.Id, new EnumThreadDelegate(EnumThreadCallback), IntPtr.Zero);
}
}
}
}
return windowList;
}
static bool EnumThreadCallback(IntPtr hWnd, IntPtr lParam)
{
if (GetClassName(hWnd, apiResult, apiResult.Capacity) != 0)
{
if (string.CompareOrdinal(apiResult.ToString(), _className) == 0)
{
windowList.Add(hWnd);
}
}
return true;
}
}
}
我知道这是一个旧的线程,但我已经找到了这个问题的答案,至少对于我的用例。我想找到所有打开的chrome窗口/标签的标题,以及,但在我的情况下,我想关闭那些我发现包含x标题。在阅读了icbytes和dor-cohen的帖子之后,我意识到我可以通过多次调用Process.GetProcessesByName()来实现我所需要的。当做这个调用,你得到一个数组的所有正在运行的chrome进程,但只有一个实例将包含MainWindowTitle的值。出于几个原因,这有点烦人。你可以有多个chrome会话打开和"active"显示标签",但仍然调用只返回一个chrome进程的数组,在该数组中只有一个实例具有MainWindowTitle的值。再一次,我的解决方案不一定是OP的意图,因为他只是想列出标题。我的解决方案是关闭每个找到的标题。
我所做的如下:
一旦我找到了我正在寻找的标题的第一个chrome进程,我在该进程上调用CloseMainWindow()。不要调用Kill(),因为它会使浏览器完全崩溃。我只是关闭了活动窗口或顶层窗口。我在下面张贴我的代码。我希望这将帮助别人!谢谢!
bool foundAll = false;
do
{
bool foundOne = false;
procs = Process.GetProcessesByName("chrome");
foreach (Process p in procs)
{
if (p.MainWindowTitle.Length > 0)
{
string t = p.MainWindowTitle.Replace(" - Google Chrome", "");
if (t.ToLower().Contains(this.BrowserTabText.ToLower()))
{
foundOne = true;
this.WriteEventLogEntry($"Found Tab Title: {this.BrowserTabText} with PID: {p.Id}. 'r'nWe will close it.", EventLogEntryType.Information);
p.CloseMainWindow();
break;
}
}
}
if (!foundOne)
{
foundAll = true;
}
} while (!foundAll);
你必须得到一个进程列表。
只遍历name为"chrome"的列表。
这将允许您获得所有标题。
因为如果你有一个以上的chrome进程,你的调用将只给你一个,因为你只调用一次。
返回哪个可能是另一个问题。