C#使用API和UIA获取当前已打开的浏览器选项卡并关闭指定界面


说明:若是仅有IE或者edge浏览器,则可不用以下方法,可以使用SHDocVw去操作,不过用也可以。

在edge中,若已知目标标题,则可直接使用FindWindow找到句柄,使用PostMessage直接关闭。

[DllImport("user32.dll", EntryPoint = "FindWindow", CharSet = CharSet.Auto)]
        private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int PostMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam);
        public const int WM_CLOSE = 0x10;

string title = "百度一下,你就知道";
            ptr = FindWindow(null, title);
            if (ptr != IntPtr.Zero)
            {
                PostMessage(ptr, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
            }

优点

可以获取到当前电脑已打开的所有浏览器的所有选项卡。

缺点

1.因为调用了UIA,所以在获取选项卡的时候需要使浏览器窗口不是最小化状态;
2.可能有bug,可以一试。

使用

调用API

        [DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]
        private static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);
        [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
        private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
        const UInt32 SWP_NOMOVE = 0x0002;
        [DllImportAttribute("user32.dll", EntryPoint = "SetForegroundWindow")]
        [return: MarshalAsAttribute(UnmanagedType.Bool)]
        private static extern bool SetForegroundWindow([InAttribute()] IntPtr hWnd);
        [DllImport("user32.dll")]
        private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
        [DllImport("user32.dll", SetLastError = false)]
        private static extern IntPtr GetDesktopWindow();
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd);
        private enum GetWindow_Cmd : uint
        {
            GW_HWNDFIRST = 0,
            GW_HWNDLAST = 1,
            GW_HWNDNEXT = 2,
            GW_HWNDPREV = 3,
            GW_OWNER = 4,
            GW_CHILD = 5,
            GW_ENABLEDPOPUP = 6
        }
        [DllImport("User32.dll", EntryPoint = "GetWindowText")]
        private static extern int GetWindowText(IntPtr hwnd, StringBuilder lpString, int nMaxCount);
        [DllImport("user32.dll")]
        private static extern int GetWindowTextLength(IntPtr hWnd);
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
        private struct WINDOWPLACEMENT
        {
            public int length;
            public int flags;
            public int showCmd;
            public System.Drawing.Point ptMinPosition;
            public System.Drawing.Point ptMaxPosition;
            public System.Drawing.Rectangle rcNormalPosition;
        }
        [DllImport("user32.dll")]
        static extern IntPtr GetForegroundWindow();

引用UIA

在这里插入图片描述

新建相关变量

因为我是在实时去走这个方法,所以使用了tempTabs 和tempTabs HWND进行中转一下,若不用实时走此方法,则可不使用这两个遍历,在BrowserTabs()中遍历tabs时即可放入listBrowserTabs中。

        private static string[] Browsers = { "chrome", "iexplore" };
        private static string[] BrowsersFullName = { "Google Chrome", "Internet Explorer" };
        private static AutomationElement root;//UI自动化相关
        private static Condition condition;//UI自动化相关
        private static AutomationElementCollection tabs;//UI自动化相关
        private static int length;
        private static IntPtr ptr = IntPtr.Zero;
        private static StringBuilder stringBuilder;
        private static List<IntPtr> intptr_childs = new List<IntPtr>();
        private static List<string> string_childs = new List<string>();
        private static Process[] browser;
        private static int[] times = new int[10], NowTab = new int[10], TargetTab = new int[10];
        private static List<string> tempTabs = new List<string>();
        private static List<IntPtr> tempTabsHWND = new List<IntPtr>();
        public static List<string> listBrowserTabs = new List<string>();//放置现存的网页标题
        private static List<IntPtr> listBrowserTabsHWND = new List<IntPtr>();//放置和listBrowserTabs对应的窗口句柄

新建GetMinimized()方法,获取窗口当前状态

private static bool GetMinimized(IntPtr handle)
        {
            WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
            placement.length = Marshal.SizeOf(placement);
            GetWindowPlacement(handle, ref placement);
            return placement.showCmd == 2;
            //1 = normal;2 = minimized;3 = maximized
        }

新建BrowserTabs()方法,存储现有网页

原理:
1.首先新建for循环,遍历所有浏览器,即Browsers变量;
2.然后使用Process.GetProcessesByName(Browsers[a]),获取所有的此浏览器相关进程;
3.若存在此浏览器相关进程,则去获取桌面窗口句柄,即GetDesktopWindow(),然后使用GetWindow(ptr, GetWindow_Cmd.GW_CHILD)获取第一个子窗口句柄;
4.然后进入while循环,只要ptr不为0,则就去获取同级窗口句柄,即GetWindow(ptr, GetWindow_Cmd.GW_HWNDNEXT);
5.然后在while循环中,根据GetWindowText(ptr, stringBuilder, stringBuilder.Capacity)去获取窗口标题;
6.若获取的窗口标题中包含BrowsersFullName[a](此变量意思为某浏览器进程的后缀名,例如谷歌浏览器后缀为“Google Chrome”),则将其放入intptr_childs和string_childs中,在此之前要if判断一下intptr_childs是否包含相同句柄,若包含,则表示重复运行了,直接break即可(这个只是以防万一,若同时重复进入此方法,则会重复记录,亦可以不要此if判断);
7.此时,intptr_childs和string_childs中已经分别存放了此浏览器的所有窗口句柄和标题,以上几步“赘余”是为了防止此浏览器同时打开多个“窗口”,但是这多个“窗口”仍只是一个进程(例如谷歌浏览器);
8.然后for循环遍历intptr_childs,进入UIA使用;
9.首先根据GetMinimized(intptr_childs[i])判断窗口是否为最小化状态,若是,则需要ShowWindow(intptr_childs[i], 3)显示出来,为了不影响主界面,使用SetWindowPos(intptr_childs[i], new IntPtr(1), 0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, SWP_NOMOVE);将此窗口放置在桌面最下层(当然,若使用多个显示器,此法应该只会在窗口所在显示器上进行操作);
10.然后给root和condition赋值,condition中的ControlType.TabItem即代表选项卡项目;
11.然后tabs=root.FindAll(TreeScope.Descendants, condition),即表示把此窗口的所有选项卡都放入tabs中;
12.然后遍历tabs,获取其的Current.Name,并存入tempTabs中,同时也将intptr_childs[b]存入tempTabsHWND中;
13.然后写两个for循环,第一个是循环listBrowserTabs,若tempTabs中不包含,则代表有web界面被关闭,在listBrowserTabs中移除,并在listBrowserTabsHWND中移除,第二个是循环tempTabs,若listBrowserTabs中不包含,则代表有新增web界面,存入listBrowserTabs中,并存入listBrowserTabsHWND中;
14.在方法结束前,要去清空intptr_childs、string_childs、tempTabs和tempTabsHWND,以防下次进入此方法时出现重复的情况。

public static void BrowserTabs()
        {
            Console.WriteLine("进入BrowserTabs " + DateTime.Now.ToString(@"HH:mm:ss.ff"));
            try
            {
                Thread.Sleep(500);//防止web界面开启缓慢
                for (int a = 0; a < Browsers.Length; a++)
                {
                    browser = Process.GetProcessesByName(Browsers[a]);
                    Console.WriteLine(Browsers[a] + ":" + browser.Length);
                    if (browser.Length > 0)
                    {
                        ptr = GetDesktopWindow();
                        ptr = GetWindow(ptr, GetWindow_Cmd.GW_CHILD);
                        while (ptr != IntPtr.Zero)
                        {
                            ptr = GetWindow(ptr, GetWindow_Cmd.GW_HWNDNEXT);
                            length = GetWindowTextLength(ptr);
                            stringBuilder = new StringBuilder(length + 1);
                            GetWindowText(ptr, stringBuilder, stringBuilder.Capacity);
                            if (!intptr_childs.Contains(ptr))
                            {
                                if (stringBuilder.ToString().Contains(BrowsersFullName[a]))
                                {
                                    intptr_childs.Add(ptr);
                                    string_childs.Add(stringBuilder.ToString());
                                }
                            }
                            else { break; }
                        }
                        //Console.WriteLine("intptr_childs:" + intptr_childs.Count);
                        for (int b = 0; b < intptr_childs.Count; b++)
                        {
                            if (GetMinimized(intptr_childs[b]))
                            {
                                ShowWindow(intptr_childs[b], 3);
                                SetWindowPos(intptr_childs[b], new IntPtr(1), 0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, SWP_NOMOVE);
                            }
                            root = AutomationElement.FromHandle(intptr_childs[b]);
                            condition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
                            tabs = root.FindAll(TreeScope.Descendants, condition);
                            foreach (AutomationElement ae in tabs)
                            {
                                tempTabs.Add(ae.Current.Name);
                                tempTabsHWND.Add(intptr_childs[b]);
                            }
                        }
                    }
                }
                //Console.WriteLine("listBrowserTabs:" + listBrowserTabs.Count);
                //foreach (string s in listBrowserTabs) { Console.WriteLine(s); }
                //Console.WriteLine("tempTabs:" + tempTabs.Count);
                //foreach (string s in tempTabs) { Console.WriteLine(s); }
                for (int a = listBrowserTabs.Count - 1; a >= 0; a--)
                {
                    if (!tempTabs.Contains(listBrowserTabs[a]))
                    {
                        Console.WriteLine("移除:" + listBrowserTabs[a]);
                        listBrowserTabs.RemoveAt(a); listBrowserTabsHWND.RemoveAt(a);
                    }
                }
                for (int a = 0; a < tempTabs.Count; a++)
                {
                    if (!listBrowserTabs.Contains(tempTabs[a]))
                    {
                        Console.WriteLine("添加:" + tempTabs[a]);
                        listBrowserTabs.Add(tempTabs[a]); listBrowserTabsHWND.Add(tempTabsHWND[a]);
                    }
                }
            }
            catch
            {
                Console.WriteLine("进入catch " + DateTime.Now.ToString(@"HH:mm:ss.ff"));
                BrowserTabs();
            }
            //Console.WriteLine("BrowserTabs方法 " + listBrowserTabs.Count + " " + DateTime.Now.ToString(@"HH:mm:ss.ff"));
            //foreach (string s in listBrowserTabs) { Console.WriteLine(s); }
            intptr_childs.Clear(); string_childs.Clear();
            tempTabs.Clear(); tempTabsHWND.Clear();
            Console.WriteLine("BrowserTabs结束 " + DateTime.Now.ToString(@"HH:mm:ss.ff"));
        }

方法运行完成一次后,便将现有窗口存入listBrowserTabs中。

新建CloseTargetTab()方法,关闭目标网页

原理:
判断目标网页所在窗口,判断目标网页是否是窗口主界面,若不是,则发送Ctrl+Tab切换界面,若是,则Ctrl+W关闭界面。

private const byte W = 0x57;
        private const byte Tab = 0x9;
        //public static bool IsInCloseTargetTab = false;
        public static void CloseTargetTab_Disused2(int system_num)
        {
            IsInCloseTargetTab = true;
            Console.WriteLine("System_num=" + system_num + " " + DateTime.Now.ToString(@"HH:mm:ss"));
            foreach (string s in listBrowserTabs) { Console.WriteLine(s); }
            foreach (IntPtr i in listBrowserTabsHWND) { Console.WriteLine(i); }
            times[system_num] = -1; NowTab[system_num] = -1; TargetTab[system_num] = -1;
            List<string> tempTabs = new List<string>();//记录目标网页所在浏览器的所有网页标题
            IntPtr tempNeedCloseTab = IntPtr.Zero;
            for (int a = 0; a < listBrowserTabs.Count; a++)
            {
                if (listBrowserTabs[a] == System_Name[system_num])
                {
                    tempNeedCloseTab = listBrowserTabsHWND[a];
                    for (int b = 0; b < listBrowserTabsHWND.Count; b++)
                    {
                        if (listBrowserTabsHWND[b] == listBrowserTabsHWND[a]) { tempTabs.Add(listBrowserTabs[b]); }
                    }
                    int tempLength = GetWindowTextLength(listBrowserTabsHWND[a]);
                    StringBuilder tempStringBuilder = new StringBuilder(tempLength + 1);
                    GetWindowText(listBrowserTabsHWND[a], tempStringBuilder, tempStringBuilder.Capacity);
                    for (int b = 0; b < tempTabs.Count; b++)
                    {
                        if (tempTabs[b] == System_Name[system_num]) { TargetTab[system_num] = b; }
                        if (tempStringBuilder.ToString().Contains(tempTabs[b])) { NowTab[system_num] = b; }
                    }
                    break;
                }
            }
            if (NowTab[system_num] == TargetTab[system_num]) { times[system_num] = 0; }
            else if (NowTab[system_num] < TargetTab[system_num]) { times[system_num] = TargetTab[system_num] - NowTab[system_num]; }
            else { times[system_num] = tempTabs.Count - (NowTab[system_num] + 1) + (TargetTab[system_num] + 1); }
            ShowWindow(tempNeedCloseTab, 8);
            for (int j = 0; j < times[system_num]; j++)
            {
                SetForegroundWindow(tempNeedCloseTab);
                Send(Tab, true, false, false, false);
                Thread.Sleep(500);
                IntPtr ip = GetForegroundWindow();
                length = GetWindowTextLength(ip);
                stringBuilder = new StringBuilder(length + 1);
                GetWindowText(tempNeedCloseTab, stringBuilder, stringBuilder.Capacity);
                Console.WriteLine("ForegroundWindow=" + stringBuilder);
            }
            SetForegroundWindow(tempNeedCloseTab);
            Send(W, true, false, false, false);
        }
        private static void Send(byte KeyCode, bool Ctrl, bool Alt, bool Shift, bool Win)
        {
            byte Keycode = (byte)KeyCode;

            uint KEYEVENTF_KEYUP = 2;
            byte VK_CONTROL = 0x11;
            byte VK_MENU = 0x12;
            byte VK_LSHIFT = 0xA0;
            byte VK_LWIN = 0x5B;

            if (Ctrl)
                keybd_event(VK_CONTROL, 0, 0, 0);
            if (Alt)
                keybd_event(VK_MENU, 0, 0, 0);
            if (Shift)
                keybd_event(VK_LSHIFT, 0, 0, 0);
            if (Win)
                keybd_event(VK_LWIN, 0, 0, 0);

            keybd_event(Keycode, 0, 0, 0); //down
            keybd_event(Keycode, 0, KEYEVENTF_KEYUP, 0); //up

            if (Ctrl)
                keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
            if (Alt)
                keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
            if (Shift)
                keybd_event(VK_LSHIFT, 0, KEYEVENTF_KEYUP, 0);
            if (Win)
                keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
        }
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值