简体   繁体   English

在程序的窗口之间切换

[英]Switch between windows of a program

I want to have a tool that provide a Alt + Tab like function, but instead of switch between all of opening windows, I want to narrow them down to 1 specific program only (eg firefox.exe). 我想拥有一个提供Alt + Tab类功能的工具,但是我不想将它们都缩小到仅1个特定程序(例如firefox.exe),而不是在所有打开的窗口之间切换。

All I could think of is using GetWindowText to get a list of windows that contain "Mozilla Firefox" in their titles, and then ShowWindowAsync to show them up, but it doesn't seem to work well if some other opening windows also have this phrase "Mozilla Firefox" in their titles. 我所能想到的就是使用GetWindowText来获取在其标题中包含“ Mozilla Firefox”的窗口的列表,然后使用ShowWindowAsync来显示它们,但是,如果其他一些打开的窗口也包含此短语,则似乎效果不佳标题中的“ Mozilla Firefox”。

Is there any better solution? 有更好的解决方案吗? Here is the code: 这是代码:

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

This is how I use it: 这是我的用法:

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

Searching for processes can be done with the System.Diagnostics.Process.GetProcessesByName() method. 可以使用System.Diagnostics.Process.GetProcessesByName()方法来搜索进程。 You can get more details about that function here: https://msdn.microsoft.com/en-us/library/z3w4xdc9(v=vs.110).aspx 您可以在此处获取有关该功能的更多详细信息: https : //msdn.microsoft.com/zh-cn/library/z3w4xdc9(v=vs.110).aspx

The function below accepts the name of a process, such as "firefox.exe" and returns the Window handle of the main window of the first matching process which has a window. 下面的函数接受进程的名称,例如“ firefox.exe”,并返回具有窗口的第一个匹配进程的主窗口的Window句柄。
( A process can run without a main window, like services or console applications, etc... ) 进程可以在没有主窗口的情况下运行,例如服务或控制台应用程序等。

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

There may be multiple instances of the same process already open, so you might want to utilize the resulting ProcessList more directly. 可能已经打开了同一流程的多个实例,所以您可能想更直接地利用生成的ProcessList。 Also, there are many functions built into the Process class that you may find helpful. 另外,Process类中内置了许多功能,这些功能可能会有所帮助。

UPDATE (Per your comment questions): 更新(根据您的评论问题):
All the Chrome process's do not equal a different Chrome tab. 所有的Chrome进程均不等于其他的Chrome标签。 Instead each Chrome process is actually a separate web-app, plug-in or Tab processing engine. 相反,每个Chrome进程实际上都是一个单独的网络应用程序,插件或Tab处理引擎。
Google separates each web-app, plug-in and tab background process into their own Windows process to protect the main process in case the plug-in crashes. Google将每个Web应用程序,插件和制表符后台进程分为各自的Windows进程,以保护主进程,以防插件崩溃。 This prevents a crashed plug-in from affecting the main Chrome application or any other tabs. 这样可以防止崩溃的插件影响主Chrome应用程序或任何其他标签。
Also it has the benefit to let the OS manage parallel multitasking. 另外,让操作系统管理并行多任务也有好处。
You can see each in the Chrome Task Manager by hitting "Shift-ESC" while in Chrome. 您可以在Chrome任务管理器中点击“ Shift-ESC”来查看每个任务。 You can read more about this here: http://blog.chromium.org/2008/09/multi-process-architecture.html 您可以在此处了解更多信息: http : //blog.chromium.org/2008/09/multi-process-architecture.html

Chrome manages each tab window within it's parent process as separate Top Level windows. Chrome将其父进程中的每个选项卡窗口作为单独的顶级窗口进行管理。 Instead of looking through all the PROCESS's you original idea is the best solution, to look through all WINDOWS. 仔细研究所有WINDOWS,而不是仔细研究所有过程,您的原始想法是最好的解决方案。 By calling SwitchToAllChromeWinows() in my example below, it iterates through all windows and switches to any the have the text "Google Chrome" However, there might be other windows that have that text in their title. 通过在下面的示例中调用SwitchToAllChromeWinows(),可以迭代所有窗口并切换到任何带有文本“ Google Chrome”的窗口。但是,可能还有其他窗口的标题中带有该文本。 Also, this switches to them all and brings them all to into focus one at a time. 同样,这会切换到所有这些,并使所有这些都一次成为焦点。 If you're looking for a specific one, you can limit your search string to be more specific. 如果您要查找特定的字符串,则可以将搜索字符串限制为更特定。

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

UPDATE: 更新:
If you are working with Chrome only or want a more direct way, then you could use Google's Chrome API's to directly manage the Tabs: 如果您仅使用Chrome或希望使用更直接的方法,则可以使用Google的Chrome API直接管理“标签”:
http://code.google.com/chrome/extensions/windows.html#method-getAll http://code.google.com/chrome/extensions/tabs.html#method-getAllInWindow http://code.google.com/chrome/extensions/windows.html#method-getAll http://code.google.com/chrome/extensions/tabs.html#method-getAllInWindow

This is what did it for me: 这就是为我做的:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM