在程序的窗口之间切换

本文关键字:之间 窗口 程序 | 更新日期: 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;
}