Как отображать открытые вкладки IE в виде эскизов DWM?

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

Windows 7 показывает открытые вкладки IE

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

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

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


person Robert S.    schedule 10.02.2012    source источник
comment
Вы посмотрели на эту ссылку, она может вам помочь в том, в каком направлении двигаться с вашей идеей msdn.microsoft.com/en-us/library/bb776426%28VS.85%29.aspx   -  person MethodMan    schedule 11.02.2012
comment
Эта ссылка также может помочь, если вы использовали проводник Windows с codeproject.com/Articles/14570/   -  person MethodMan    schedule 11.02.2012
comment
Спасибо за ссылки, но я ищу что-то более конкретное.   -  person Robert S.    schedule 11.02.2012


Ответы (3)


Этот код перечисляет дескрипторы окон, соответствующие эскизам 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);
person Simon Mourier    schedule 13.02.2012
comment
+1, TabThumbnailWindow была ключевой частью, которую мне не хватало в моих попытках. - person Robert S.; 14.02.2012
comment
Обратите внимание, что это имя класса недокументировано. Нет никакой гарантии, что будущие версии IE будут вести себя так же. Убедитесь, что ваши клиенты понимают, что вы намеренно берете на себя зависимость от недокументированного поведения. - person Raymond Chen; 15.02.2012
comment
@RaymondChen - есть ли какой-нибудь задокументированный способ? К сожалению, нет интерфейса TaskBar, способного вывести список того, что было зарегистрировано с помощью ITaskList3:RegisterTab, если я правильно понимаю. - person Simon Mourier; 15.02.2012
comment
Я не знаю документированного интерфейса для этого. - person Raymond Chen; 15.02.2012
comment
Это элегантное решение, но я беспокоюсь о совместимости в будущем. - person Robert S.; 17.02.2012
comment
@ Роберт С. - ну, похоже, у вас нет выбора :-) Если вам нужна эта функция, нет документированного способа сделать это. - person Simon Mourier; 17.02.2012
comment
@SimonMourier, никогда не говори никогда! Я обнаружил, что можно использовать EnumWindows, а затем найти конкретное окно по его заголовку. - person Robert S.; 17.02.2012
comment
@ Роберт С. Ах да, конечно, но факт существования этих окон TabThumbnailWindow или любых окон с подходящим заголовком сам по себе не документирован. Если Рэймонд Чен сказал, что документированного способа не существует, то он прав — он всегда прав насчет Windows :-) - person Simon Mourier; 18.02.2012

Обновлять

Хотя это действительно было указано в вопросе, я на самом деле не просматривал файл DWM Thumbnail API и требованиям функция DwmRegisterThumbnail, в частности:

hwndSource

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

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


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

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

  • IEFrame
    • [...]
    • Frame Tab
      • [...]
    • Frame Tab
      • [...]
      • TabWindowClass
        • Shell DocObject View
          • Internet Explorer_Server

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

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

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

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

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

Удачи!

person Steffen Opel    schedule 13.02.2012
comment
@Steffen Opel - Хотя это кажется хорошей идеей, это не работает. Иерархия есть, но нет подходящего окна для создания эскизов. Все окна под IEFrame сообщают об ошибке при попытке вызвать в нем DwmRegisterThumbnail. - person Simon Mourier; 15.02.2012
comment
@SimonMourier: Спасибо за фактическое тестирование этого, я действительно только что ответил, основываясь на явно небрежном понимании варианта использования и возникшей проблемы;) Соответственно, я обновил свой ответ, чтобы объяснить возникшую ошибку и вместо этого продвигать ваше решение ( +1). - person Steffen Opel; 15.02.2012

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

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

person Robert S.    schedule 18.02.2012