使用c#获取chrome浏览器标题

本文关键字:浏览器 标题 chrome 获取 使用 | 更新日期: 2023-09-27 18:17:06

假设我打开了多个chrome窗口(不是选项卡),
如何查看浏览器标题?

我试了如下:

Process[] p = Process.GetProcessesByName("chrome");
foreach (Process item in p)
{
    Console.WriteLine(item.MainWindowTitle);
}

但是它只返回最后一个打开的窗口名,其他都是空白。

使用c#获取chrome浏览器标题

我不得不做这样的事情,但它涉及到调用Windows API函数,这是令人惊讶的繁琐。问题是Chrome似乎对多个窗口使用一个进程或其他一些奇怪的东西,这意味着简单的方法对我不起作用。

无论如何,试试这个,看看它是否有效。基本上,它使用Chrome窗口类名(可能是Chrome_WidgetWin_0Chrome_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进程,你的调用将只给你一个,因为你只调用一次。

返回哪个可能是另一个问题。