2015-12-18 4 views
0

Я хочу иметь инструмент, который предоставляет функцию 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

Различные (верхние) окна ap Обычно использование одного и того же класса окон. Вызовите [GetClassName] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms633582.aspx) в обратном вызове 'EnumWindowProc' для фильтрации имени класса. – IInspectable

+0

Только вы можете принять решение по вашим критериям. Кто они такие? Как только вы решите, используйте EnumWindows для получения окон верхнего уровня. –

ответ

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

Поиск процессов может быть сделано с помощью метода 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, которые могут оказаться полезными.

UPDATE (Per вашего комментария вопросов):
Все не равен другая вкладка Chrome процесса Chrome. Вместо этого каждый процесс Chrome представляет собой отдельный веб-приложение, подключаемый модуль или механизм обработки вкладок.
Google отделяет каждое веб-приложение, плагин и фоновый процесс вкладки в свой собственный процесс Windows, чтобы защитить основной процесс в случае сбоя подключаемого модуля. Это предотвращает поврежденный подключаемый модуль от основного приложения Chrome или любых других вкладок.
Также он имеет преимущество, позволяющее ОС управлять параллельной многозадачностью.
Вы можете увидеть их каждый в диспетчере задач Chrome, нажав «Shift-ESC» в Chrome. Вы можете узнать больше об этом: http://blog.chromium.org/2008/09/multi-process-architecture.html

Хром управляет каждым окном вкладки в его родительском процессе как отдельные окна верхнего уровня. Вместо того, чтобы просматривать все 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); 
     } 
    } 
} 

UPDATE:
Если вы работаете с Chrome или только хотите более прямой путь, то вы можете использовать Chrome от Google API, чтобы непосредственно управлять вкладками:
http://code.google.com/chrome/extensions/windows.html#method-getAll http://code.google.com/chrome/extensions/tabs.html#method-getAllInWindow

+2

Процесс может иметь несколько окон верхнего уровня. –

+0

Спасибо, этого может быть достаточно для моего случая. – FlySoFast

+0

Отлично, надеюсь. Получив действительный дескриптор окна, если вы хотите получить верхнее родительское окно в этом процессе, повторите цепочку родительских окон, пока не получите верхнюю. Дайте мне знать, если вам нужна помощь. – Don

Смежные вопросы