Как отображать открытые вкладки IE в виде миниатюр DWM?

Я создаю WPF-приложение на С#, и я хочу отображать миниатюры открытых вкладок IE в списке. Я по сути пытаюсь дублировать функции DWM в Windows 7.

Windows 7 showing open IE tabs

Я выяснил, как перечислять список открытых вкладок с помощью Interop.ShDocVW, но для использования вызовов API DWM мне нужно передать hwnd, а вкладки все имеют один и тот же дескриптор, что и Интернет Проводник.

Итак, я возился с EnumWindows и EnumChildWindows, но я не могу заставить что-то работать.

Любые предложения о том, как наилучшим образом подойти к этому?

Ответ 1

В решении, с которым я работал, использовались EnumWindows и GetWindowText из Win32 API. Я перечисляю через окна Internet Explorer с помощью shdocvw.dll и передаю заголовок вкладки методу, который анализирует результаты GetWindowText, чтобы найти hwnd окна с этой надписью.

Это работает для всех окон IE, а не только для вкладок.

Ответ 2

Этот код перечисляет оконные дескрипторы, соответствующие эскизам IE, и может использоваться как параметр hwndSource функции DwmRegisterThumbnail

public static IEnumerable<IntPtr> EnumerateIEDwmThumbnails()
{
    List<IntPtr> ptrs = new List<IntPtr>();
    StringBuilder cls = new StringBuilder(100);
    EnumWindows((hwnd, lparam) =>
    {
        GetClassName(hwnd, cls, cls.Capacity);
        if (cls.ToString() == "TabThumbnailWindow")
        {
            ptrs.Add(hwnd);
        }
        return true;
    }, IntPtr.Zero);
    return ptrs;
}

[DllImport("user32.dll")]
private static extern bool EnumWindows(EnumWindowsCallback lpEnumFunc, IntPtr lParam);
private delegate bool EnumWindowsCallback(IntPtr hwnd, IntPtr lParam);

[DllImport("user32.dll")]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

Ответ 3

Update

В самом деле, я действительно не рассматривал DWM Thumbnail API и требования функция DwmRegisterThumbnail:

hwndSource

Ручка к окну для использования в качестве источника эскизов. Установка дескриптора окна источника на что-либо, кроме верхнего уровня тип окна приведет к возврату E_INVALIDARG. [акцент мой]

Подчеркнутое требование отображает мой подход с дочерними окнами, полученными с помощью FindWindowEx(), приведенного ниже, недействительным, то есть только FindWindow() может использоваться для извлечения дескриптора в окно верхнего уровня вместо этого (спасибо Саймону за это указание) - Саймон answer предоставляет подходящее решение, основанное на имени класса окна IE верхнего уровня, видимо, созданного специально для этой цели.


[...], чтобы использовать вызовы API DWM, мне нужно передать hwnd, а вкладки все имеют один и тот же дескриптор, что и Internet Explorer.

Как вы проверили иерархию окон? Если я проверю окно IE 9, например. Spy ++, он предоставляет следующую иерархию классы окон (сокращенно):

  • IEFrame
    • [...]
    • Вкладка Frame
      • [...]
    • Вкладка Frame
      • [...]
      • TabWindowClass
        • Просмотр оболочки DocObject
          • Internet Explorer_Server

У дочерних окон есть отдельные дескрипторы, поэтому (с верхней части головы) вы сможете получить нужные из них с помощью соответствующих вызовов FindWindowEx функции, например:

HWND hwndIeTab = ::FindWindowEx(hwndIeFrame, NULL, "Internet Explorer_Server", NULL);

Чтобы получить все нужные вкладки, вам необходимо выполнить итерацию результатов с помощью второго параметра hwndChildAfter FindWindowEx():

Дескриптор дочернего окна. Поиск начинается со следующего ребенка окна в порядке Z. Детское окно должно быть прямым дочерним окном hwndParent, а не только окно потомков.

Итак, вам нужно будет сначала выполнить итерацию с помощью класса "Вкладка" Рамка "и получить каждое дочернее окно" Internet Explorer_Server "со вторым вызовом FindWindowEx() (хотя вам может понадобиться поэкспериментировать, прохождение ребенка выше через третий параметр lpszClass производит одинаковые или лучшие результаты).

Удачи!