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);
}