在程序的窗口之间切换
本文关键字:之间 窗口 程序 | 更新日期: 2023-09-27 18:27:12
我想有一个工具来提供类似Alt + Tab
的功能,但我不想在所有打开的窗口之间切换,而是想将它们缩小到只有一个特定的程序(例如firefox.exe)。
我所能想到的就是使用GetWindowText
来获得标题中包含"Mozilla Firefox"的窗口列表,然后使用ShowWindowAsync
来显示它们,但如果其他一些打开的窗口的标题中也包含"Mozilla Firefox"这句话,这似乎就不太好用了。
有更好的解决方案吗?这是代码:
/// <summary>Contains functionality to get all the open windows.</summary>
public static class OpenWindowGetter
{
/// <summary>Returns a dictionary that contains the handle and title of all the open windows.</summary>
/// <returns>A dictionary that contains the handle and title of all the open windows.</returns>
public static IDictionary<HWND, string> GetOpenWindows()
{
HWND shellWindow = GetShellWindow();
Dictionary<HWND, string> windows = new Dictionary<HWND, string>();
EnumWindows(delegate(HWND hWnd, int lParam)
{
if (hWnd == shellWindow) return true;
if (!IsWindowVisible(hWnd)) return true;
int length = GetWindowTextLength(hWnd);
if (length == 0) return true;
StringBuilder builder = new StringBuilder(length);
GetWindowText(hWnd, builder, length + 1);
windows[hWnd] = builder.ToString();
return true;
}, 0);
return windows;
}
private delegate bool EnumWindowsProc(HWND hWnd, int lParam);
[DllImport("USER32.DLL")]
private static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam);
[DllImport("USER32.DLL")]
private static extern int GetWindowText(HWND hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("USER32.DLL")]
private static extern int GetWindowTextLength(HWND hWnd);
[DllImport("USER32.DLL")]
private static extern bool IsWindowVisible(HWND hWnd);
[DllImport("USER32.DLL")]
private static extern IntPtr GetShellWindow();
}
这就是我使用它的方式:
/// <summary>
/// Get a window handle by a title
/// </summary>
/// <param name="windowTitle"></param>
/// <param name="wildCard">match if window title contains input windowTitle</param>
/// <returns></returns>
public static int GetWindowHandle(string windowTitle, bool wildCard = false)
{
var processList = OpenWindowGetter.GetOpenWindows();
foreach (var process in processList)
{
if ((wildCard && process.Value.ToLower().Contains(windowTitle.ToLower())) //Find window by wildcard
|| !wildCard && process.Value.Equals(windowTitle)) //Find window with exact name
{
int a = (int)process.Key;
return a;
}
}
return 0;
}
可以使用System.Diagnostics.Process.GetProcessesByName()
方法搜索进程。您可以在此处获得有关该功能的更多详细信息:https://msdn.microsoft.com/en-us/library/z3w4xdc9(v=vs.110).aspx
下面的函数接受一个进程的名称,如"firefox.exe",并返回第一个匹配进程的主窗口的窗口句柄,该进程有一个窗口
(进程可以在没有主窗口的情况下运行,如服务或控制台应用程序等。)
public static IntPtr GetMainWindowHandle(string ProcessName)
{
Process[] ProcessList = Process.GetProcessesByName(ProcessName);
foreach (Process ThisProcess in ProcessList)
{
if (ThisProcess.MainWindowHandle != IntPtr.Zero)
{
return ThisProcess.MainWindowHandle;
}
}
return IntPtr.Zero;
}
同一进程可能有多个实例已打开,因此您可能希望更直接地使用生成的ProcessList。此外,Process类中内置了许多函数,您可能会发现这些函数很有用。
更新(根据您的评论问题):
所有的Chrome进程并不等于一个不同的Chrome选项卡。相反,每个Chrome进程实际上都是一个单独的web应用程序、插件或Tab处理引擎
谷歌将每个web应用程序、插件和选项卡后台进程分离到各自的Windows进程中,以在插件崩溃时保护主进程。这样可以防止崩溃的插件影响主Chrome应用程序或任何其他选项卡
此外,让操作系统管理并行多任务处理也有好处
在Chrome中点击"Shift ESC",您可以在Chrome任务管理器中看到每一个。您可以在此处阅读更多信息:http://blog.chromium.org/2008/09/multi-process-architecture.html
Chrome将其父进程中的每个选项卡窗口作为单独的顶级窗口进行管理。与其浏览所有的PROCESS,不如浏览所有的WINDOWS。在下面的例子中,通过调用SwitchToAllChromeWinows(),它遍历所有窗口并切换到任何具有文本"Google Chrome"的窗口但是,可能还有其他窗口的标题中包含该文本。此外,这会切换到所有这些,并使它们一次一个地成为焦点。如果你正在寻找一个特定的,你可以限制你的搜索字符串更具体。
public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.dll")]
protected static extern bool EnumWindows(Win32Callback enumProc, IntPtr lParam);
private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
List<IntPtr> pointers = GCHandle.FromIntPtr(pointer).Target as List<IntPtr>;
pointers.Add(handle);
return true;
}
private static List<IntPtr> GetAllWindows()
{
Win32Callback enumCallback = new Win32Callback(EnumWindow);
List<IntPtr> AllWindowPtrs = new List<IntPtr>();
GCHandle listHandle = GCHandle.Alloc(AllWindowPtrs);
try
{
EnumWindows(enumCallback, GCHandle.ToIntPtr(listHandle));
}
finally
{
if (listHandle.IsAllocated)
listHandle.Free();
}
return AllWindowPtrs;
}
[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 string GetTitle(IntPtr handle)
{
int length = GetWindowTextLength(handle);
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(handle, sb, sb.Capacity);
return sb.ToString();
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
private static void SwitchToAllChromeWinows()
{
List<IntPtr> AllWindowsPtrs = GetAllWindows();
foreach (IntPtr ThisWindowPtr in AllWindowsPtrs)
{
if (GetTitle(ThisWindowPtr).Contains("Google Chrome") == true)
{
SwitchToThisWindow(ThisWindowPtr, true);
}
}
}
更新:
如果您只使用Chrome或想要更直接的方式,那么您可以使用Google的Chrome API来直接管理选项卡:
http://code.google.com/chrome/extensions/windows.html#method-获取全部http://code.google.com/chrome/extensions/tabs.html#method-getAllInWindow
这就是为我做的:
[DllImport("user32.dll")]
static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
[DllImport("user32.dll")]
private static extern bool IsWindowVisible(int hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetWindowText(int hWnd, StringBuilder title, int size);
delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
public List<IntPtr> GetMainWindowHandle()
{
var list = Process.GetProcessesByName(ProcessName);
List<IntPtr> windowList = new List<IntPtr>();
foreach (Process process in list)
{
if (process.MainWindowHandle != IntPtr.Zero)
//windowList.Add(ThisProcess.MainWindowHandle);
{
foreach (ProcessThread processThread in process.Threads)
{
EnumThreadWindows(processThread.Id,
(hWnd, lParam) =>
{
//Check if Window is Visible or not.
if (!IsWindowVisible((int)hWnd))
return true;
//Get the Window's Title.
StringBuilder title = new StringBuilder(256);
GetWindowText((int)hWnd, title, 256);
//Check if Window has Title.
if (title.Length == 0)
return true;
windowList.Add(hWnd);
return true;
}, IntPtr.Zero);
}
}
}
return windowList;
}