Поделиться через


Создание настраиваемых Обозреватель баров, полос инструментов и наборов рабочих столов

Панель Обозреватель появилась в Microsoft Internet Обозреватель 4.0, чтобы предоставить область отображения, расположенную рядом с панелью браузера. Это в основном дочернее окно в окне Windows Internet Обозреватель, и его можно использовать для отображения информации и взаимодействия с пользователем таким же образом. Обозреватель полосы чаще всего отображаются как вертикальная панель в левой части панели браузера. Однако панель Обозреватель также может отображаться горизонтально под панелью браузера.

Screenshot that shows the vertical and horizontal Explorer Bars.

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

Одним из способов настройки интернет-Обозреватель является добавление настраиваемой панели Обозреватель. При реализации и регистрации она будет добавлена в подменю Обозреватель панели меню "Вид". При выборе пользователя область отображения Обозреватель панели может использоваться для отображения сведений и ввода данных пользователей так же, как и в обычном окне.

screen shot of the explorer bars

Чтобы создать пользовательскую панель Обозреватель, необходимо реализовать и зарегистрировать объект группы. Объекты группы были представлены в оболочке версии 4.71 и предоставляют возможности, аналогичные обычным окнам. Тем не менее, поскольку они являются объектами объектной модели компонентов (COM) и содержатся в Интернете Обозреватель или оболочке, они реализуются несколько иначе. Простые объекты полосы использовались для создания примера Обозреватель полос, отображаемых на первом рисунке. Реализация примера вертикальной Обозреватель линейчатой панели подробно рассматривается в следующем разделе.

Полосы инструментов

Группа инструментов — это объект группы, который был представлен в Microsoft Internet Обозреватель 5 для поддержки функции радиосвязи Windows. Панель инструментов Обозреватель в Интернете — это элемент управления перебары, содержащий несколько элементов управления панелью инструментов. Создав группу инструментов, вы можете добавить полосу в этот элемент управления перекладиной. Однако, как и Обозреватель полосы инструментов, это окно общего назначения.

screen shot of tool bands

Пользователи отображают панель инструментов, выбрав ее в подменю "Панели инструментов" в меню "Вид" или в контекстном меню, которое отображается, щелкнув правой кнопкой мыши область панели инструментов.

Группы рабочих столов

Объекты группы также можно использовать для создания групп рабочих столов. Хотя их базовая реализация аналогична Обозреватель Баров, группы на столе не связаны с Интернетом Обозреватель. Панель стола в основном является способом создания закрепления окна на рабочем столе. Пользователь выбирает его, щелкнув правой кнопкой мыши панель задач и выбрав ее в подменю панели инструментов .

Screenshot that shows a sample desk band.

Изначально группы рабочих столов закреплены на панели задач.

Screenshot that shows desk bands docked on the task bar.

Затем пользователь может перетащить группу стола на рабочий стол, и она будет отображаться как обычное окно.

screen shot of desk bands

Реализация объектов группы

Рассматриваются следующие разделы.

Основные сведения об объектах группы

Хотя их можно использовать так же, как обычные окна, объекты полосы являются COM-объектами, существующими в контейнере. Обозреватель Бары содержатся в Интернете Обозреватель, а группы столов содержатся оболочкой. Хотя они служат различным функциям, их базовая реализация очень похожа. Основное различие заключается в том, как регистрируется объект группы, который, в свою очередь, управляет типом объекта и его контейнера. В этом разделе рассматриваются те аспекты реализации, которые являются общими для всех объектов группы. Дополнительные сведения о реализации см. в простом примере пользовательской панели Обозреватель.

Помимо IUnknown и IClassFactory, все объекты группы должны реализовать следующие интерфейсы.

Помимо регистрации идентификатора класса (CLSID), объекты Обозреватель панели и группы рабочих столов также должны быть зарегистрированы для соответствующей категории компонентов. Регистрация категории компонента определяет тип объекта и его контейнер. Полосы инструментов используют другую процедуру регистрации и не имеют идентификатора категории (CATID). Идентификаторы CATID для трех объектов группы, которые требуют их:

Тип полосы Категории компонентов
Вертикальная Обозреватель линейчатая панель CATID_InfoBand
Горизонтальная Обозреватель линейчатая панель CATID_CommBand
Группа рабочих столов CATID_DeskBand

 

Дополнительные сведения о регистрации объектов группы см. в разделе "Регистрация группы".

Если объект группы должен принимать входные данные пользователя, он также должен реализовать IInputObject. Чтобы добавить элементы в контекстное меню для Обозреватель панели или группы рабочих столов, объект группы должен экспортировать IContextMenu. Полосы инструментов не поддерживают контекстные меню.

Так как объекты группы реализуют дочернее окно, они также должны реализовать процедуру окна для обработки сообщений Windows.

Объекты группы могут отправлять команды в контейнер через интерфейс IOleCommandTarget контейнера. Чтобы получить указатель интерфейса, вызовите метод IInputObjectSite::QueryInterface и попросите IID_IOleCommandTarget. Затем вы отправляете команды в контейнер с помощью IOleCommandTarget::Exec. Группа команд CGID_DeskBand. При вызове метода IDeskBand::GetBandInfo контейнер использует параметр dwBandID для назначения объекта группы идентификатора, используемого для трех команд. Поддерживаются четыре идентификатора команд IOleCommandTarget::Exec .

  • DBID_BANDINFOCHANGED

    Информация группы изменилась. Задайте для параметра pvaIn идентификатор группы, полученный в последнем вызове IDeskBand::GetBandInfo. Контейнер вызовет метод IDeskBand объекта группы::GetBandInfo для запроса обновленных сведений.

  • DBID_MAXIMIZEBAND

    Максимальное увеличение диапазона. Задайте для параметра pvaIn идентификатор группы, полученный в последнем вызове IDeskBand::GetBandInfo.

  • DBID_SHOWONLY

    Включите или отключите другие полосы в контейнере. Задайте для параметра pvaIn тип VT_UNKNOWN одним из следующих значений:

    значение Описание
    Панк Указатель на интерфейс IUnknown объекта группы. Все остальные группы столовых будут скрыты.
    0 Скрыть все полосы стола.
    1 Показать все группы стола.

     

  • DBID_PUSHCHEVRON

    Версия 5. Отображение меню шеврона. Контейнер отправляет сообщение RB_PUSHCHEVRON, а объект группы получает уведомление RBN_CHEVRONPUSHED, которое предложит ему отобразить меню шеврона. Задайте для параметра метода IOleCommandTarget::Exec nCmdExecOpt идентификатор группы, полученный в последнем вызове IDeskBand::GetBandInfo. Задайте параметр pvaIn метода IOleCommandTarget::Exec для типа VT_I4 с заданным приложением значением. Он передает объекту группы в качестве значения lAppValue уведомления RBN_CHEVRONPUSHED.

Регистрация полосы

Объект группы должен быть зарегистрирован как сервер в процессе OLE, поддерживающий потоки квартир. Значением по умолчанию для сервера является текстовая строка меню. Для Обозреватель баров он появится в подменю Обозреватель панели в меню "Вид Обозреватель Интернета". Для полос инструментов она появится в подменю "Панели инструментов" в меню "Вид" в Интернете Обозреватель. Для групп рабочих столов он появится в подменю панели инструментов контекстного меню панели задач. Как и в случае с ресурсами меню, размещение амперсанда (&) перед буквой приведет к подчеркиваниям и включению сочетаний клавиш. Например, строка меню для вертикальной панели Обозреватель, показанной на первом рисунке, — "Пример и вертикальная строка Обозреватель".

Изначально интернет-Обозреватель извлекает перечисление зарегистрированных объектов Обозреватель линейчатой строки из реестра с помощью категорий компонентов. Чтобы повысить производительность, она кэширует это перечисление, что приводит к тому, что впоследствии добавленные Обозреватель панели будут пропущены. Чтобы принудить Windows Internet Обозреватель перестроить кэш и распознать новую панель Обозреватель, удалите следующие разделы реестра во время регистрации новой панели Обозреватель:

HKEY_CURRENT_USER программного обеспечения\Microsoft\Windows\CurrentVersion\ Обозреватель\ Dis карта доступные\категории\ компонентов PostSetup\{00021493-0000-0000-C000000000000046}\Enum\

HKEY_CURRENT_USER Программное обеспечение\Microsoft\Windows\CurrentVersion\ Обозреватель\ Dis карта able\PostSetup\Component Categories\{00021494-0000-0000-C000-000000000000046}\Enum\

Примечание.

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

 

Как правило, базовая запись реестра для объекта группы будет отображаться следующим образом.

HKEY_CLASSES_ROOT
   CLSID
      {Your Band Object's CLSID GUID}
         (Default) = Menu Text String
         InProcServer32
            (Default) = DLL Path Name
            ThreadingModel = Apartment

Полосы инструментов также должны иметь clSID объекта, зарегистрированного в Обозреватель Интернета. Для этого назначьте значение в разделе HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Обозреватель\ Toolbar с идентификатором CLSID объекта средства, как показано здесь. Его значение данных игнорируется, поэтому тип значения не имеет значения.

HKEY_LOCAL_MACHINE
   Software
      Microsoft
         Internet Explorer
            Toolbar
               {Your Band Object's CLSID GUID}

В реестр также можно добавить несколько необязательных значений. Например, необходимо следующее значение, если вы хотите использовать панель Обозреватель для отображения HTML, отображаемое значение не является примером, но фактическим значением, которое следует использовать.

HKEY_CLASSES_ROOT
   CLSID
      {Your Band Object's CLSID GUID}
         Instance
            CLSID
               (Default) = {4D5C8C2A-D075-11D0-B416-00C04FB90376}

Используется в сочетании со значением, показанным выше, следующее необязательное значение также необходимо, если вы хотите использовать панель Обозреватель для отображения HTML. Это значение должно быть задано в расположении файла, содержащего HTML-содержимое для панели Обозреватель.

HKEY_CLASSES_ROOT
   CLSID
      {Your Band Object's CLSID GUID}
         Instance
            InitPropertyBag
               Url

Другое необязательное значение определяет ширину или высоту панели Обозреватель по умолчанию в зависимости от того, является ли она вертикальной или горизонтальной, соответственно.

HKEY_CURRENT_USER
   Software
      Microsoft
         Internet Explorer
            Explorer Bars
               {Your Band Object's CLSID GUID}
                  BarSize

Значение BarSize должно быть задано на ширину или высоту панели. Значение требует восьми байтов и помещается в реестр как двоичное значение. Первые четыре байта указывают размер в пикселях в шестнадцатеричном формате, начиная с самого левого байта. Последние четыре байта зарезервированы и должны иметь значение нулю.

В качестве примера отображаются полные записи реестра для строки с поддержкой HTML Обозреватель с шириной по умолчанию 291 (0x123) пикселей.

HKEY_CLASSES_ROOT
   CLSID
      {Your Band Object's CLSID GUID}
         (Default) = Menu Text String
         InProcServer32
            (Default) = DLL Path Name
            ThreadingModel = Apartment
         Instance
            CLSID
               (Default) = {4D5C8C2A-D075-11D0-B416-00C04FB90376}
            InitPropertyBag
               Url = Your HTML File
HKEY_CURRENT_USER
   Software
      Microsoft
         Internet Explorer
            Explorer Bars
               {Your Band Object's CLSID GUID}
                  BarSize = 23 01 00 00 00 00 00 00

Вы можете обрабатывать регистрацию CATID объекта группы программным способом. Создайте объект диспетчера категорий компонентов (CLSID_StdComponentCategoriesMgr) и запросите указатель на его интерфейс ICatRegister. Передайте CLSID и CATID объекта группы в ICatRegister::RegisterClassImplCategories.

Простой пример пользовательской панели Обозреватель

В этом примере выполняется реализация примера вертикальной Обозреватель линейчатой панели, показанной в вводном представлении.

Базовая процедура создания пользовательской панели Обозреватель выглядит следующим образом.

  1. Реализуйте функции, необходимые библиотеке DLL.
  2. Реализуйте необходимые COM-интерфейсы.
  3. Реализуйте все необходимые необязательные com-интерфейсы.
  4. Зарегистрируйте CLSID объекта и, при необходимости, категорию компонентов.
  5. Создайте дочернее окно Обозреватель Интернета, размер в котором соответствует области отображения Обозреватель панели.
  6. Используйте дочернее окно для отображения сведений и взаимодействия с пользователем.

Очень простая реализация, используемая в примере панели Обозреватель, может быть использована для любого типа Обозреватель бар или панели стола, просто зарегистрируя его для соответствующей категории компонентов. Более сложные реализации необходимо настроить для каждого региона отображения и контейнера каждого типа объекта. Однако большую часть этой настройки можно выполнить, принимая пример кода и расширяя его, применяя знакомые методы программирования Windows к дочернему окну. Например, можно добавить элементы управления для взаимодействия с пользователем или графику для более полного отображения.

Функции DLL

Все три объекта упаковываются в одну библиотеку DLL, которая предоставляет следующие функции.

Первые три функции являются стандартными реализациями и не будут обсуждаться здесь. Реализация фабрики классов также является стандартной.

Обязательные реализации интерфейса

Пример вертикальной Обозреватель bar реализует четыре необходимых интерфейса: IUnknown, IObjectWithSite, IPersistStream и IDeskBand в рамках класса C Обозреватель Bar. Конструктор, деструктор и реализации IUnknown просты и здесь не будут обсуждаться. Подробности см. в примере кода.

Подробно рассматриваются следующие интерфейсы.

IObjectWithSite

Когда пользователь выбирает панель Обозреватель, контейнер вызывает соответствующий метод объекта группы IObjectWithSite::SetSite. Параметр punkSite будет иметь указатель IUnknown сайта.

Как правило, реализация SetSite должна выполнять следующие действия:

  1. Выпустите любой указатель сайта, который в настоящее время проводится.
  2. Если указатель, переданный в SetSite , имеет значение NULL, то полоса удаляется. SetSite может возвращать S_OK.
  3. Если указатель, переданный в SetSite , не имеет значения NULL, устанавливается новый сайт. SetSite должен выполнять следующие действия:
    1. Вызов QueryInterface на сайте для своего интерфейса IOleWindow.
    2. Вызовите IOleWindow::GetWindow , чтобы получить дескриптор родительского окна. Сохраните дескриптор для последующего использования. Выпуск IOleWindow , если он больше не нужен.
    3. Создайте окно объекта группы в качестве дочернего элемента окна, полученного на предыдущем шаге. Не создавайте его как видимое окно.
    4. Если объект группы реализует IInputObject, вызовите QueryInterface на сайте для своего интерфейса IInputObjectSite. Сохраните указатель на этот интерфейс для последующего использования.
    5. Если все шаги выполнены успешно, вернитесь S_OK. В противном случае верните код ошибки, определенный OLE, указывающий, что произошло сбоем.

Пример панели Обозреватель реализует SetSite следующим образом. В следующем коде m_pSite — это частная переменная члена, содержащая указатель IInputObjectSite, а m_hwndParent содержит дескриптор родительского окна. В этом примере также обрабатывается создание окна. Если окно не существует, этот метод создает окно панели Обозреватель в качестве дочернего элемента родительского окна, полученного SetSite. Дескриптор дочернего окна хранится в m_hwnd.

STDMETHODIMP CDeskBand::SetSite(IUnknown *pUnkSite)
{
    HRESULT hr = S_OK;

    m_hwndParent = NULL;

    if (m_pSite)
    {
        m_pSite->Release();
    }

    if (pUnkSite)
    {
        IOleWindow *pow;
        hr = pUnkSite->QueryInterface(IID_IOleWindow, reinterpret_cast<void **>(&pow));
        if (SUCCEEDED(hr))
        {
            hr = pow->GetWindow(&m_hwndParent);
            if (SUCCEEDED(hr))
            {
                WNDCLASSW wc = { 0 };
                wc.style         = CS_HREDRAW | CS_VREDRAW;
                wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
                wc.hInstance     = g_hInst;
                wc.lpfnWndProc   = WndProc;
                wc.lpszClassName = g_szDeskBandSampleClass;
                wc.hbrBackground = CreateSolidBrush(RGB(255, 255, 0));

                RegisterClassW(&wc);

                CreateWindowExW(0,
                                g_szDeskBandSampleClass,
                                NULL,
                                WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
                                0,
                                0,
                                0,
                                0,
                                m_hwndParent,
                                NULL,
                                g_hInst,
                                this);

                if (!m_hwnd)
                {
                    hr = E_FAIL;
                }
            }

            pow->Release();
        }

        hr = pUnkSite->QueryInterface(IID_IInputObjectSite, reinterpret_cast<void **>(&m_pSite));
    }

    return hr;
}

Реализация GetSite примера просто упаковывает вызов метода QueryInterface сайта с помощью указателя сайта, сохраненного SetSite.

STDMETHODIMP CDeskBand::GetSite(REFIID riid, void **ppv)
{
    HRESULT hr = E_FAIL;

    if (m_pSite)
    {
        hr =  m_pSite->QueryInterface(riid, ppv);
    }
    else
    {
        *ppv = NULL;
    }

    return hr;
}

IPersistStream

Интернет-Обозреватель вызовет интерфейс IPersistStream Обозреватель bar, чтобы разрешить Обозреватель линейчатой строке загружать или сохранять постоянные данные. Если постоянных данных нет, методы по-прежнему должны возвращать код успешного выполнения. Интерфейс IPersistStream наследует от IPersist, поэтому необходимо реализовать пять методов.

Пример панели Обозреватель не использует постоянные данные и имеет только минимальную реализацию IPersistStream. IPersist::GetClassID возвращает CLSID объекта (CLSID_SampleОбозреватель Bar), а остальные возвращаются либо S_OK, S_FALSE, либо E_NOTIMPL.

IDeskBand

Интерфейс IDeskBand зависит от объектов группы. Помимо одного метода, он наследует от IDockingWindow, который, в свою очередь, наследует от IOleWindow.

Существует два метода IOleWindow: GetWindow и IOleWindow::ContextSensitiveHelp. Реализация примера Обозреватель панели GetWindow возвращает дескриптор дочернего окна панели Обозреватель, m_hwnd. Справка с учетом контекста не реализована, поэтому ContextSensitiveHelp возвращает E_NOTIMPL.

Интерфейс IDockingWindow имеет три метода.

Метод ResizeBorderDW не используется с любым типом объекта группы и всегда должен возвращать E_NOTIMPL. Метод ShowDW отображает или скрывает окно панели Обозреватель в зависимости от значения параметра.

STDMETHODIMP CDeskBand::ShowDW(BOOL fShow)
{
    if (m_hwnd)
    {
        ShowWindow(m_hwnd, fShow ? SW_SHOW : SW_HIDE);
    }

    return S_OK;
}

Метод CloseDW уничтожает окно Обозреватель панели.

STDMETHODIMP CDeskBand::CloseDW(DWORD)
{
    if (m_hwnd)
    {
        ShowWindow(m_hwnd, SW_HIDE);
        DestroyWindow(m_hwnd);
        m_hwnd = NULL;
    }

    return S_OK;
}

Оставшийся метод GetBandInfo зависит от IDeskBand. Интернет Обозреватель использует его для указания идентификатора Обозреватель панели и режима просмотра. Интернет-Обозреватель также может запрашивать одну или несколько частей информации из панели Обозреватель, заполнив элемент dwMask структуры DES КБ ANDINFO, передаваемой в качестве третьего параметра. GetBandInfo должен хранить идентификатор и режим просмотра и заполнять структуру DES КБ ANDINFO запрошенными данными. Пример панели Обозреватель реализует GetBandInfo, как показано в следующем примере кода.

STDMETHODIMP CDeskBand::GetBandInfo(DWORD dwBandID, DWORD, DESKBANDINFO *pdbi)
{
    HRESULT hr = E_INVALIDARG;

    if (pdbi)
    {
        m_dwBandID = dwBandID;

        if (pdbi->dwMask & DBIM_MINSIZE)
        {
            pdbi->ptMinSize.x = 200;
            pdbi->ptMinSize.y = 30;
        }

        if (pdbi->dwMask & DBIM_MAXSIZE)
        {
            pdbi->ptMaxSize.y = -1;
        }

        if (pdbi->dwMask & DBIM_INTEGRAL)
        {
            pdbi->ptIntegral.y = 1;
        }

        if (pdbi->dwMask & DBIM_ACTUAL)
        {
            pdbi->ptActual.x = 200;
            pdbi->ptActual.y = 30;
        }

        if (pdbi->dwMask & DBIM_TITLE)
        {
            // Don't show title by removing this flag.
            pdbi->dwMask &= ~DBIM_TITLE;
        }

        if (pdbi->dwMask & DBIM_MODEFLAGS)
        {
            pdbi->dwModeFlags = DBIMF_NORMAL | DBIMF_VARIABLEHEIGHT;
        }

        if (pdbi->dwMask & DBIM_BKCOLOR)
        {
            // Use the default background color by removing this flag.
            pdbi->dwMask &= ~DBIM_BKCOLOR;
        }

        hr = S_OK;
    }

    return hr;
}

Необязательные реализации интерфейса

Существует два интерфейса, которые не требуются, но это может быть полезно для реализации: IInputObject и IContextMenu. Пример панели Обозреватель реализует IInputObject. Дополнительные сведения о реализации IContextMenu см. в документации.

IInputObject

Интерфейс IInputObject должен быть реализован, если объект группы принимает входные данные пользователя. Интернет Обозреватель реализует IInputObjectSite и использует IInputObject для поддержания правильного фокуса ввода пользователей при использовании нескольких содержащихся в нем окон. Существует три метода, которые необходимо реализовать с помощью панели Обозреватель.

Интернет Обозреватель вызывает UIActivateIO, чтобы сообщить Обозреватель панели о том, что она активируется или деактивируется. При активации пример Обозреватель панели вызывает SetFocus, чтобы задать фокус в окне.

Интернет Обозреватель вызывает HasFocusIO при попытке определить, какое окно имеет фокус. Если окно Обозреватель бар или один из потомков имеет фокус, HasFocusIO должен вернуться S_OK. В противном случае он должен возвращать S_FALSE.

TranslateAcceleratorIO позволяет объекту обрабатывать ускорители клавиатуры. Пример панели Обозреватель не реализует этот метод, поэтому возвращает S_FALSE.

Реализация IInputObjectSite в примере строки выглядит следующим образом.

STDMETHODIMP CDeskBand::UIActivateIO(BOOL fActivate, MSG *)
{
    if (fActivate)
    {
        SetFocus(m_hwnd);
    }

    return S_OK;
}

STDMETHODIMP CDeskBand::HasFocusIO()
{
    return m_fHasFocus ? S_OK : S_FALSE;
}

STDMETHODIMP CDeskBand::TranslateAcceleratorIO(MSG *)
{
    return S_FALSE;
};

Регистрация CLSID

Как и во всех COM-объектах, необходимо зарегистрировать CLSID Обозреватель bar. Для правильной работы объекта с Обозреватель в Интернете она также должна быть зарегистрирована для соответствующей категории компонентов (CATID_InfoBand). В следующем примере кода показан соответствующий раздел кода для панели Обозреватель.

HRESULT RegisterServer()
{
    WCHAR szCLSID[MAX_PATH];
    StringFromGUID2(CLSID_DeskBandSample, szCLSID, ARRAYSIZE(szCLSID));

    WCHAR szSubkey[MAX_PATH];
    HKEY hKey;

    HRESULT hr = StringCchPrintfW(szSubkey, ARRAYSIZE(szSubkey), L"CLSID\\%s", szCLSID);
    if (SUCCEEDED(hr))
    {
        hr = E_FAIL;
        if (ERROR_SUCCESS == RegCreateKeyExW(HKEY_CLASSES_ROOT,
                                             szSubkey,
                                             0,
                                             NULL,
                                             REG_OPTION_NON_VOLATILE,
                                             KEY_WRITE,
                                             NULL,
                                             &hKey,
                                             NULL))
        {
            WCHAR const szName[] = L"DeskBand Sample";
            if (ERROR_SUCCESS == RegSetValueExW(hKey,
                                                NULL,
                                                0,
                                                REG_SZ,
                                                (LPBYTE) szName,
                                                sizeof(szName)))
            {
                hr = S_OK;
            }

            RegCloseKey(hKey);
        }
    }

    if (SUCCEEDED(hr))
    {
        hr = StringCchPrintfW(szSubkey, ARRAYSIZE(szSubkey), L"CLSID\\%s\\InprocServer32", szCLSID);
        if (SUCCEEDED(hr))
        {
            hr = HRESULT_FROM_WIN32(RegCreateKeyExW(HKEY_CLASSES_ROOT, szSubkey,
                 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL));
            if (SUCCEEDED(hr))
            {
                WCHAR szModule[MAX_PATH];
                if (GetModuleFileNameW(g_hInst, szModule, ARRAYSIZE(szModule)))
                {
                    DWORD cch = lstrlen(szModule);
                    hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, NULL, 0, REG_SZ, (LPBYTE) szModule, cch * sizeof(szModule[0])));
                }

                if (SUCCEEDED(hr))
                {
                    WCHAR const szModel[] = L"Apartment";
                    hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, L"ThreadingModel", 0,  REG_SZ, (LPBYTE) szModel, sizeof(szModel)));
                }

                RegCloseKey(hKey);
            }
        }
    }

    return hr;
}

Регистрация объектов полосы в примере использует обычные com-процедуры.

Помимо CLSID, сервер объектов группы также должен быть зарегистрирован для одной или нескольких категорий компонентов. На самом деле это основное различие в реализации между вертикальными и горизонтальными Обозреватель линейчатой панели. Этот процесс обрабатывается путем создания объекта диспетчера категорий компонентов (CLSID_StdComponentCategoriesMgr) и использования метода ICatRegister::RegisterClassImplCategories для регистрации сервера объектов группы. В этом примере регистрация категорий компонентов обрабатывается путем передачи clSID и CATID примера Обозреватель в частную функцию RegisterComCat, как показано в следующем примере кода.

HRESULT RegisterComCat()
{
    ICatRegister *pcr;
    HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pcr));
    if (SUCCEEDED(hr))
    {
        CATID catid = CATID_DeskBand;
        hr = pcr->RegisterClassImplCategories(CLSID_DeskBandSample, 1, &catid);
        pcr->Release();
    }
    return hr;
}

Процедура окна

Так как объект группы использует дочернее окно для отображения, он должен реализовать процедуру окна для обработки сообщений Windows. Пример группы имеет минимальные функциональные возможности, поэтому процедура окна обрабатывает только пять сообщений:

Процедура может быть легко расширена, чтобы разместить дополнительные сообщения для поддержки дополнительных функций.

LRESULT CALLBACK CDeskBand::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    LRESULT lResult = 0;

    CDeskBand *pDeskBand = reinterpret_cast<CDeskBand *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));

    switch (uMsg)
    {
    case WM_CREATE:
        pDeskBand = reinterpret_cast<CDeskBand *>(reinterpret_cast<CREATESTRUCT *>(lParam)->lpCreateParams);
        pDeskBand->m_hwnd = hwnd;
        SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pDeskBand));
        break;

    case WM_SETFOCUS:
        pDeskBand->OnFocus(TRUE);
        break;

    case WM_KILLFOCUS:
        pDeskBand->OnFocus(FALSE);
        break;

    case WM_PAINT:
        pDeskBand->OnPaint(NULL);
        break;

    case WM_PRINTCLIENT:
        pDeskBand->OnPaint(reinterpret_cast<HDC>(wParam));
        break;

    case WM_ERASEBKGND:
        if (pDeskBand->m_fCompositionEnabled)
        {
            lResult = 1;
        }
        break;
    }

    if (uMsg != WM_ERASEBKGND)
    {
        lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

    return lResult;
}

Обработчик WM_COMMAND просто возвращает ноль. Обработчик WM_PAINT создает простой текстовый дисплей, показанный в примере строки Обозреватель в вводной статье.

void CDeskBand::OnPaint(const HDC hdcIn)
{
    HDC hdc = hdcIn;
    PAINTSTRUCT ps;
    static WCHAR szContent[] = L"DeskBand Sample";
    static WCHAR szContentGlass[] = L"DeskBand Sample (Glass)";

    if (!hdc)
    {
        hdc = BeginPaint(m_hwnd, &ps);
    }

    if (hdc)
    {
        RECT rc;
        GetClientRect(m_hwnd, &rc);

        SIZE size;

        if (m_fCompositionEnabled)
        {
            HTHEME hTheme = OpenThemeData(NULL, L"BUTTON");
            if (hTheme)
            {
                HDC hdcPaint = NULL;
                HPAINTBUFFER hBufferedPaint = BeginBufferedPaint(hdc, &rc, BPBF_TOPDOWNDIB, NULL, &hdcPaint);

                DrawThemeParentBackground(m_hwnd, hdcPaint, &rc);

                GetTextExtentPointW(hdc, szContentGlass, ARRAYSIZE(szContentGlass), &size);
                RECT rcText;
                rcText.left   = (RECTWIDTH(rc) - size.cx) / 2;
                rcText.top    = (RECTHEIGHT(rc) - size.cy) / 2;
                rcText.right  = rcText.left + size.cx;
                rcText.bottom = rcText.top + size.cy;

                DTTOPTS dttOpts = {sizeof(dttOpts)};
                dttOpts.dwFlags = DTT_COMPOSITED | DTT_TEXTCOLOR | DTT_GLOWSIZE;
                dttOpts.crText = RGB(255, 255, 0);
                dttOpts.iGlowSize = 10;
                DrawThemeTextEx(hTheme, hdcPaint, 0, 0, szContentGlass, -1, 0, &rcText, &dttOpts);

                EndBufferedPaint(hBufferedPaint, TRUE);

                CloseThemeData(hTheme);
            }
        }
        else
        {
            SetBkColor(hdc, RGB(255, 255, 0));
            GetTextExtentPointW(hdc, szContent, ARRAYSIZE(szContent), &size);
            TextOutW(hdc,
                     (RECTWIDTH(rc) - size.cx) / 2,
                     (RECTHEIGHT(rc) - size.cy) / 2,
                     szContent,
                     ARRAYSIZE(szContent));
        }
    }

    if (!hdcIn)
    {
        EndPaint(m_hwnd, &ps);
    }
}

Обработчики WM_SETFOCUS и WM_KILLFOCUS сообщают сайту изменения фокуса путем вызова метода IInputObjectSite::OnFocusChangeIS.

void CDeskBand::OnFocus(const BOOL fFocus)
{
    m_fHasFocus = fFocus;

    if (m_pSite)
    {
        m_pSite->OnFocusChangeIS(static_cast<IOleWindow*>(this), m_fHasFocus);
    }
}

Объекты полосы обеспечивают гибкий и мощный способ расширения возможностей Интернет-Обозреватель путем создания настраиваемых Обозреватель баров. Реализация полосы стола позволяет расширить возможности обычных окон. Хотя для некоторых программ COM требуется, он в конечном итоге служит для предоставления дочернего окна пользовательского интерфейса. Оттуда основная часть реализации может использовать знакомые методы программирования Windows. Хотя в примере, описанном здесь, есть только ограниченные функциональные возможности, он иллюстрирует все необходимые функции объекта группы, и его можно легко расширить для создания уникального и мощного пользовательского интерфейса.