Share via


Разработка для панели задач Windows 7 – Application ID

Это первая статья в новом цикле, посвященных панели задач Windows 7. Разработчикам стоит уделять панели задач первоочередное внимание. Мы должны понять новые возможности панели, чтобы создавать приложения, эффективно работающие с ней, чтобы расширить возможности пользователей и сделать их работу с ОС максимально удобной.

Я полагаю, что вы успели ознакомиться с базовой функциональностью и нововведениями панели задач Windows 7. Если же вы не знакомы, рекомендую вам посмотреть видео-обзор функциональных возможностей панели задач Windows 7 на Channel 9 и прочитать статьи в блоге E7. Это позволит вам лучше понять, о чем идет речь в сегодняшней в статье.

При первом запуске системы новая панель задач, пожалуй, является наиболее заметным нововведением в Windows 7. В Windows 7 панель задач представляет собой механизм для запуска приложений и переключения окон, консолидирующим возможности панелей задач из предыдущих версий Windows и, в частности, панель быстрого запуска, недавние документы, уведомления и окна запущенных приложений. В дополнение к старым возможностям панель задач Windows 7 обладает новыми: списками быстрого перехода, интерактивными миниатюрами открытых окон и т.п. Но для начала давайте заложим основу для нашей беседы и определимся с терминологией.

Основным элементом панели задач является кнопка панели задач. Кнопка представлена иконкой на панели задач. Как видите, на панели задач размещается масса кнопок, статус которых можно понять, лишь взглянув на них:

clip_image002

Возьмем, к примеру, кнопку Windows Media Player: она не обрамлена и ничем не выделяется. Это свидетельствует о том, что Windows Media Player не запущен. Однако, приложение закреплено на панели задач и будет оставаться там, если мы не уберем его. Вокруг иконки Windows Explorer можно видеть тусклую рамку: это свидетельствует о том, что приложение работает, но не активно. У Visual Studio иконка в более непрозрачной прямоугольной рамке, указывающей на то, что в данный момент пользователь работает с этим приложением. Обратите внимание, что в Word открыто много документов и они сгруппированы в одну иконку приложения. Очень важно понимать логику создания и группировки окон приложений на панели задач.

Существенное количество приложений, работающих в Windows 7 (например, Office Word 2007 и Visual Studio 2008), не были предназначены для работы с новой панелью задач Windows 7. Так каким же образом все они взаимодействуют с панелью задач и поддерживают списки переходов в Word? В основе лежит специальный Application ID, который автоматически присваивается запускаемым приложениям после их запуска. Каждое запускаемое приложение имеет свой AppID, присваиваемый либо самой Windows, либо приложением. Это не GUID, а простой строковый параметр, состоящий максимум из 128 символов. Все приложения и окна, имеющие одинаковый параметр AppID, включая списки переходов, группируются в одну кнопку на панели задач. Важно понимать, что каждый компонент (процесс, ярлык, окно, кнопка или документ) имеет ассоциированное с ним значение AppID.

Вы спросите, откуда берется этот AppID? Как уже упоминалось ранее, ОС генерирует код для приложения, используя простую и важную для понимания эвристику. Так как в Windwos 7 можно присваивать AppID отдельным окнам, ОС пытается экстраполировать AppID приложения из его окна. Приложения, как правило, имеют хотя бы одно окно, у которого система и запрашивает AppID. Однако, большинство приложений не имеют AppID, ассоциированных с каждым окном (или вообще не имеют AppID), поэтому система вынуждена обращаться к процессу, в котором выполняется окно. У каждого процесса есть несколько свойств, которые может опрашивать ОС, к примеру, исполняемый файл процесса. Но даже в этом случае, процесс не гарантирует четкого разделения. Различные ярлыки могут использовать разные параметры для запуска одного и того же исполняемого файла и запускать совершенно разные приложения (вспомните хотя бы приложения типа «launcher»), которые сгруппированы под одной кнопкой на панели задач. В таких случаях ОС может исследовать ярлык, отыскать исполняемый файл, параметры запуска и т.д. Обратите внимание, в случае зарегистрированного типа файла регистрация указывает на приложение, которое запускается двойным щелчком на файле. Это еще один способ получения AppID. Нижеприведенное изображение иллюстрирует процедуру автоматического получения AppID:

clip_image004

Если вам интересны внутренние составляющие панели задач Windows 7, рекомендую вам посмотреть несколько видео: видео Роба Джэретта (Rob Jarrett) и Бена Бетса (Ben Bets) – За кулисами панели задач windows 7 и Обзор списков переходов.

Несмотря на то, что ОС может автоматически присвоить AppID, многие разработчики хотят иметь больший контроль над AppID для своего приложения или отдельного окна. Предположим, что у вас есть приложения, запускающие другие приложения (таким образом работает отладка с помощью Visual Studio). Или у вас есть несколько различных приложений и процессов, которые вы хотите сгруппировать под одной кнопкой панели задач. В любом случае, если вы пишете новое приложение для Windows 7, мы настоятельно рекомендуем задать свой собственный идентификатор приложения, согласно приведенной инструкции.

Теперь давайте перейдем к непосредственным тестам API, который позволяет контролировать ассоциации AppID для приложений.

Если необходимо задействовать отдельную кнопку для каждого процесса (включая все окна, принадлежащие этому процессу), вы можете присвоить AppID всему процессу, в котором исполняются все окна приложения без отдельных AppID. Присвоить отдельный AppID очень просто: осуществляется это с помощью функции SetCurrentProcessExplicitAppUserModelID:

 

 SetCurrentProcessExplicitAppUserModelID(c_rgszAppID[0]);

где c_rgszAppID[0] – указатель на строку. Необходимо отметить, что в соответствии с документацией SDK этот метод должен быть применен в ходе загрузки приложения перед появлением его интерфейса или манипуляций со списками переходов.

В управляемом коде из последней версии API-библиотек вы можете использовать свойство AppID как часть объекта Taskbar, который можно найти в пространстве имен Microsoft.WindowsAPICodePack.Shell.Taskbar. Используя это свойство, можно присваивать AppID.

Присвоить AppID отдельному окну чуть сложнее. Выполняется это вызовом функции SHGetPropertyStoreForWindow и дальнейшей манипуляцией с объектом IPropertyStore для получения необходимого свойства:

 

 void SetAppID(HWND hWnd, int iAppID)
{
    IPropertyStore *pps;
    HRESULT hr = SHGetPropertyStoreForWindow(hWnd, IID_PPV_ARGS(&pps));
    if (SUCCEEDED(hr))
    {
        PROPVARIANT pv;
        if (iAppID >= 0)
        {
            hr = InitPropVariantFromString(c_rgszAppID[iAppID], &pv);
        }
        else
        {
            PropVariantInit(&pv);
        }
        if (SUCCEEDED(hr))
        {
            hr = pps->SetValue(PKEY_AppUserModel_ID, pv);
            PropVariantClear(&pv);
        }
        pps->Release();
    }
}

В приведенном фрагменте можно видеть, как извлекаются свойство окна вызовом SHGetPropertyStoreForWindow, передачей hWnd в качестве ссылки на окно. Затем инициируем с помощью InitPropVariantFromString(c_rgszAppID[iAppID], &pv) вариант свойства строкой, представляющей AppID для конкретного окна. И, наконец, устанавливаем значение нового свойства для окна.

К сожалению, нынешний Windows API Code Pack не поддерживает установку AppID для отдельных окон, хотя все, что вам нужно сделать, – это добавить следующую функцию в файл Taskbar.cs:

 

 private static void SetWindowAppId(string appId)
{
    Microsoft.WindowsAPICodePack.Shell.ShellNativeMethods.SetWindowAppId
        (OwnerHandle, "name here");
}

Поскольку в Windows API Code Pack присутствует исходный код, вы можете посмотреть на реализацию функции SetWindowAppId и увидеть собственными глазами, что она очень похожа на пример SetAppID, приведенный выше. Обратите внимание, что вовсе не обязательно использовать полное имя сборки «Microsoft.WindowsAPICodePack.Shell» – я использовал его, чтобы объяснить иерархию Windows API Code Pack.

Кстати, идентификатор окна AppID динамичен, так что вполне возможно чтобы окно отображалось как одна кнопка панели задач, а затем изменив его AppID, заставить появиться на совершенно другой кнопке. Это имеет интересный эффект. Допустим, список перехода прикреплен к кнопке на панели задач (с конкретным AppID), поэтому одно и то же окно может отображать разные списки перехода при прикреплении к другим кнопкам панели задач. Это может ввести пользователей в заблуждение, поэтому мы рекомендуем установить окну определенный AppID и придерживаться его, используя тот же процесс для определения AppID при каждом отображении окна.

Вы можете найти управляемый код объекта Taskbar в проекте Windows API Code Pack.