在程序的窗口之间切换

时间:2015-12-18 01:55:30

标签: c# winforms winapi

我希望有一个提供类似Alt + Tab功能的工具,但我不想在所有打开的窗口之间切换,而只想将它们缩小到1个特定程序(例如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;
    }

2 个答案:

答案 0 :(得分:1)

可以使用System.Diagnostics.Process.GetProcessesByName()方法搜索进程。您可以在此处获取有关该功能的更多详细信息:https://msdn.microsoft.com/en-us/library/z3w4xdc9(v=vs.110).aspx

下面的函数接受进程的名称,例如&#34; firefox.exe&#34;并返回具有窗口的第一个匹配过程的主窗口的Window句柄 (进程可以在没有主窗口的情况下运行,如服务或控制台应用程序等......

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处理引擎 谷歌将每个网络应用程序,插件和标签后台进程分成他们自己的Windows进程,以便在插件崩溃时保护主进程。 这可以防止崩溃的插件影响主Chrome应用程序或任何其他选项卡 此外,它还可以让操作系统管理并行多任务处理 您可以通过点击&#34; Shift-ESC&#34;在Chrome任务管理器中查看每个内容。在Chrome中。 您可以在此处详细了解:http://blog.chromium.org/2008/09/multi-process-architecture.html

Chrome将其所在的父进程中的每个标签窗口作为单独的顶级窗口进行管理。 通过查看所有WINDOWS,您最初的想法是最好的解决方案,而不是查看所有过程。 通过在下面的示例中调用SwitchToAllChromeWinows(),它遍历所有窗口并切换到任何具有文本&#34; Google Chrome&#34; 但是,可能有其他窗口在其标题中包含该文本。 此外,这会切换到所有这些并将它们全部聚焦到一个一个焦点。 如果您正在寻找特定的搜索字符串,则可以将搜索字符串限制为更具体。

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-getAll http://code.google.com/chrome/extensions/tabs.html#method-getAllInWindow

答案 1 :(得分:0)

这就是为我做的事情:

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