Share via


Crear barras de Explorador personalizadas, bandas de herramientas y bandas de escritorio

La barra del Explorador se introdujo con Microsoft Internet Explorer 4.0 para proporcionar un área de visualización adyacente al panel del explorador. Básicamente es una ventana secundaria dentro de la ventana de Windows Internet Explorer y se puede usar para mostrar información e interactuar con el usuario de la misma manera. Las barras del explorador se muestran normalmente como un panel vertical en el lado izquierdo del panel del explorador. Sin embargo, también se puede mostrar una barra del explorador horizontalmente, debajo del panel del explorador.

Captura de pantalla que muestra las barras verticales y horizontales del Explorador.

Hay una amplia gama de usos posibles para la barra del explorador. Los usuarios pueden seleccionar la opción que quieren ver de varias maneras diferentes, incluida la selección en el submenú Barra del explorador del menú Ver o hacer clic en un botón de barra de herramientas. Internet Explorer proporciona varias barras estándar del Explorador, como Favoritos y Búsqueda.

Una de las formas en que puedes personalizar Internet Explorer es agregando una barra de Explorador personalizada. Cuando se implementa y se registra, se agregará al submenú Barra del explorador del menú Ver . Cuando lo selecciona el usuario, el área de visualización de la barra del explorador se puede usar para mostrar información y tomar la entrada del usuario de la misma manera que una ventana normal.

captura de pantalla de las barras del explorador

Para crear una barra de explorador personalizada, debe implementar y registrar un objeto de banda. Los objetos band se introdujeron con la versión 4.71 del Shell y proporcionan funcionalidades similares a las de las ventanas normales. Sin embargo, dado que son objetos del Modelo de objetos componentes (COM) y contenidos en Internet Explorer o shell, se implementan de forma ligeramente diferente. Los objetos de banda simples se usaron para crear las barras del Explorador de ejemplo mostradas en el primer gráfico. La implementación del ejemplo de barra del Explorador vertical se describirá en detalle en una sección posterior.

Bandas de herramientas

Una banda de herramientas es un objeto de banda que se introdujo con Microsoft Internet Explorer 5 para admitir la característica de la barra de herramientas de radio de Windows. La barra de herramientas de Internet Explorer es realmente un control de barra de herramientas que contiene varios controles de barra de herramientas. Al crear una banda de herramientas, puede agregar una banda a ese control de barra. Sin embargo, al igual que las barras del explorador, una banda de herramientas es una ventana de uso general.

captura de pantalla de las bandas de herramientas

Los usuarios muestran una barra de herramientas seleccionándola en el submenú Barras de herramientas del menú Ver o en el menú contextual que se muestra haciendo clic con el botón derecho en el área de la barra de herramientas.

Bandas de escritorio

Los objetos band también se pueden usar para crear bandas de escritorio. Aunque su implementación básica es similar a las barras de Explorer, las bandas de escritorio no están relacionadas con Internet Explorer. Una banda de escritorio es básicamente una manera de crear una ventana acoplable en el escritorio. El usuario lo selecciona haciendo clic con el botón derecho en la barra de tareas y seleccionándolo en el submenú Barras de herramientas .

Captura de pantalla que muestra una banda de escritorio de ejemplo.

Inicialmente, las bandas de escritorio se acoplan en la barra de tareas.

Captura de pantalla que muestra las bandas de escritorio acopladas en la barra de tareas.

A continuación, el usuario puede arrastrar la banda de escritorio al escritorio y aparecerá como una ventana normal.

captura de pantalla de bandas de escritorio

Implementación de objetos band

Se tratan los temas siguientes.

Conceptos básicos de objetos band

Aunque se pueden usar de forma muy similar a las ventanas normales, los objetos band son objetos COM que existen dentro de un contenedor. Las barras del Explorador están contenidas en Internet Explorer y las bandas de escritorio están contenidas en shell. Aunque sirven diferentes funciones, su implementación básica es muy similar. La principal diferencia es la forma en que se registra el objeto de banda, que a su vez controla el tipo de objeto y su contenedor. En esta sección se describen los aspectos de la implementación que son comunes a todos los objetos de banda. Consulte Un ejemplo sencillo de una barra del Explorador personalizado para obtener más detalles de implementación.

Además de IUnknown e IClassFactory, todos los objetos de banda deben implementar las siguientes interfaces.

Además de registrar su identificador de clase (CLSID), los objetos de banda de escritorio y barra del explorador también deben registrarse para la categoría de componente adecuada. El registro de la categoría de componente determina el tipo de objeto y su contenedor. Las bandas de herramientas usan un procedimiento de registro diferente y no tienen un identificador de categoría (CATID). Los CATID de los tres objetos de banda que los requieren son:

Tipo de banda Categoría de componentes
Barra del Explorador vertical CATID_InfoBand
Barra del Explorador horizontal CATID_CommBand
Banda de escritorio CATID_DeskBand

 

Consulte Registro de banda para obtener más información sobre cómo registrar objetos de banda.

Si el objeto band es aceptar la entrada del usuario, también debe implementar IInputObject. Para agregar elementos al menú contextual de la barra del Explorador o bandas de escritorio, el objeto band debe exportar IContextMenu. Las bandas de herramientas no admiten menús contextuales.

Dado que los objetos de banda implementan una ventana secundaria, también deben implementar un procedimiento de ventana para controlar la mensajería de Windows.

Los objetos band pueden enviar comandos a su contenedor a través de la interfaz IOleCommandTarget del contenedor. Para obtener el puntero de interfaz, llame al método IInputObjectSite::QueryInterface del contenedor y solicite IID_IOleCommandTarget. A continuación, envíe comandos al contenedor con IOleCommandTarget::Exec. El grupo de comandos es CGID_DeskBand. Cuando se llama al método IDeskBand::GetBandInfo de un objeto de banda, el contenedor usa el parámetro dwBandID para asignar al objeto de banda un identificador que se usa para tres de los comandos. Se admiten cuatro identificadores de comando IOleCommandTarget::Exec .

  • DBID_BANDINFOCHANGED

    La información de la banda ha cambiado. Establezca el parámetro pvaIn en el identificador de banda que se recibió en la llamada más reciente a IDeskBand::GetBandInfo. El contenedor llamará al método IDeskBand::GetBandInfo del objeto de banda para solicitar la información actualizada.

  • DBID_MAXIMIZEBAND

    Maximice la banda. Establezca el parámetro pvaIn en el identificador de banda que se recibió en la llamada más reciente a IDeskBand::GetBandInfo.

  • DBID_SHOWONLY

    Active o desactive otras bandas del contenedor. Establezca el parámetro pvaIn en el tipo VT_UNKNOWN con uno de los valores siguientes:

    Valor Descripción
    Punk Puntero a la interfaz IUnknown del objeto de banda. Todas las demás bandas de escritorio estarán ocultas.
    0 Oculta todas las bandas de escritorio.
    1 Mostrar todas las bandas de escritorio.

     

  • DBID_PUSHCHEVRON

    Versión 5. Muestra un menú de contenido adicional. El contenedor envía un mensaje de RB_PUSHCHEVRON y el objeto band recibe una notificación de RBN_CHEVRONPUSHED que le pide que muestre el menú de contenido adicional. Establezca el parámetro nCmdExecOpt del método IOleCommandTarget::Exec en el identificador de banda recibido en la llamada más reciente a IDeskBand::GetBandInfo. Establezca el parámetro pvaIn del método IOleCommandTarget::Exec en el tipo VT_I4 con un valor definido por la aplicación. Vuelve al objeto band como el valor lAppValue de la notificación de RBN_CHEVRONPUSHED.

Registro de banda

Un objeto de banda debe registrarse como un servidor OLE en proceso que admita subprocesos de apartamento. El valor predeterminado para el servidor es una cadena de texto de menú. En Barras del Explorador, aparecerá en el submenú Barra del Explorador del menú Vista de Internet Explorer. En el caso de las bandas de herramientas, aparecerá en el submenú Barras de herramientas del menú Vista de Internet Explorer. En el caso de las bandas de escritorio, aparecerá en el submenú Barras de herramientas del menú contextual de la barra de tareas. Al igual que con los recursos de menú, colocar una y comercial (&) delante de una letra hará que se subrayado y habilite los métodos abreviados de teclado. Por ejemplo, la cadena de menú de la barra vertical del Explorador que se muestra en el primer gráfico es "Barra de explorador vertical de &ejemplo".

Inicialmente, Internet Explorer recupera una enumeración de los objetos Bar del Explorador registrados del Registro mediante las categorías de componentes. Para aumentar el rendimiento, luego almacena en caché esta enumeración, lo que hace que se pasen por alto las barras del Explorador agregadas posteriormente. Para forzar que Windows Internet Explorer recompile la memoria caché y reconozca una nueva barra del Explorador, elimine las siguientes claves del Registro durante el registro de la nueva barra del Explorador:

HKEY_CURRENT_USER\Software\Microsoft\Windows\Currentversion\Explorador\Descartable\PostSetup\Categorías de componentes\{00021493-0000-0000-C000-000000000046}\Enum

HKEY_CURRENT_USER\Software\Microsoft\Windows\Currentversion\Explorador\Descartable\PostSetup\Categorías de componentes\{00021494-0000-0000-C000-000000000046}\Enum

Nota

Dado que se crea una caché de barras del explorador para cada usuario, es posible que la aplicación de instalación tenga que enumerar todos los subárboles del registro de usuario o agregar un código auxiliar por usuario para que se ejecute cuando el usuario inicie sesión por primera vez.

 

En general, la entrada básica del Registro para un objeto de banda aparecerá de la siguiente manera.

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

Las bandas de herramientas también deben tener el CLSID de su objeto registrado con Internet Explorer. Para ello, asigne un valor en HKEY_LOCAL_MACHINE\ Barra de herramientas deMicrosoft\Internet Explorer\de software\denominada con el GUID CLSID del objeto de banda de herramientas, como se muestra aquí. Se omite su valor de datos, por lo que el tipo de valor no es importante.

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

Hay varios valores opcionales que también se pueden agregar al Registro. Por ejemplo, el siguiente valor es necesario si desea usar la barra del explorador para mostrar HTML El valor mostrado no es un ejemplo, pero el valor real que se debe usar.

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

Se usa junto con el valor mostrado anteriormente, el siguiente valor opcional también es necesario si desea usar la barra del explorador para mostrar HTML. Este valor debe establecerse en la ubicación del archivo que contiene el contenido HTML de la barra del explorador.

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

Otro valor opcional define el ancho o alto predeterminados de la barra del Explorador, en función de si es vertical u horizontal, respectivamente.

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

El valor BarSize debe establecerse en el ancho o alto de la barra. El valor requiere ocho bytes y se coloca en el Registro como un valor binario. Los cuatro primeros bytes especifican el tamaño en píxeles, en formato hexadecimal, empezando por el byte situado más a la izquierda. Los cuatro últimos bytes están reservados y deben establecerse en cero.

Por ejemplo, aquí se muestran las entradas completas del Registro para una barra del Explorador compatible con HTML con un ancho predeterminado de 291 píxeles (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

Puede controlar el registro del CATID de un objeto de banda mediante programación. Cree un objeto de administrador de categorías de componentes (CLSID_StdComponentCategoriesMgr) y solicite un puntero a su interfaz ICatRegister . Pase el CLSID y CATID del objeto de banda a ICatRegister::RegisterClassImplCategories.

Un ejemplo sencillo de una barra del Explorador personalizado

En este ejemplo se recorre la implementación de la barra de explorador vertical de ejemplo que se muestra en la introducción.

El procedimiento básico para crear una barra de Explorador personalizada es el siguiente.

  1. Implemente las funciones necesarias para el archivo DLL.
  2. Implemente las interfaces COM necesarias.
  3. Implemente las interfaces COM opcionales deseadas.
  4. Registre el CLSID del objeto y, si es necesario, la categoría de componente.
  5. Cree una ventana secundaria de Internet Explorer con el tamaño para ajustarse a la región de presentación de la barra del Explorador.
  6. Use la ventana secundaria para mostrar información e interactuar con el usuario.

La implementación muy sencilla que se usa en el ejemplo de barra del explorador podría usarse realmente para cualquier tipo de barra del Explorador o una banda de escritorio, simplemente registrándolo para la categoría de componente adecuada. Las implementaciones más sofisticadas deberán personalizarse para la región de visualización y el contenedor de cada tipo de objeto. Sin embargo, gran parte de esta personalización se puede lograr tomando el código de ejemplo y extendiéndolo aplicando técnicas de programación de Windows conocidas a la ventana secundaria. Por ejemplo, puede agregar controles para la interacción del usuario o gráficos para una visualización más completa.

Funciones DLL

Los tres objetos se empaquetan en un único archivo DLL, que expone las siguientes funciones.

Las tres primeras funciones son implementaciones estándar y no se analizarán aquí. La implementación de Class Factory también es estándar.

Implementaciones de interfaz necesarias

El ejemplo de barra de explorador vertical implementa las cuatro interfaces necesarias: IUnknown, IObjectWithSite, IPersistStream e IDeskBand como parte de la clase CExplorerBar. El constructor, el destructor y las implementaciones de IUnknown son sencillas y no se analizarán aquí. Vea el código de ejemplo para obtener más detalles.

Las siguientes interfaces se describen en detalle.

IObjectWithSite

Cuando el usuario selecciona una barra del explorador, el contenedor llama al método IObjectWithSite::SetSite del objeto de banda correspondiente. El parámetro punkSite se establecerá en el puntero IUnknown del sitio.

En general, una implementación de SetSite debe realizar los pasos siguientes:

  1. Libere cualquier puntero de sitio que se esté conservando actualmente.
  2. Si el puntero pasado a SetSite se establece en NULL, se quita la banda. SetSite puede devolver S_OK.
  3. Si el puntero pasado a SetSite no es NULL, se establece un nuevo sitio. SetSite debe hacer lo siguiente:
    1. Llame a QueryInterface en el sitio para su interfaz IOleWindow .
    2. Llame a IOleWindow::GetWindow para obtener el identificador de la ventana primaria. Guarde el identificador para su uso posterior. Libere IOleWindow si ya no es necesario.
    3. Cree la ventana del objeto de banda como elemento secundario de la ventana obtenida en el paso anterior. No lo cree como una ventana visible.
    4. Si el objeto band implementa IInputObject, llame a QueryInterface en el sitio para su interfaz IInputObjectSite . Almacene el puntero a esta interfaz para usarlo más adelante.
    5. Si todos los pasos se realizan correctamente, devuelva S_OK. Si no es así, devuelve el código de error definido por OLE que indica lo que ha fallado.

El ejemplo de barra del explorador implementa SetSite de la siguiente manera. En el código siguiente m_pSite es una variable de miembro privado que contiene el puntero IInputObjectSite y m_hwndParent contiene el identificador de la ventana primaria. En este ejemplo, también se controla la creación de ventanas. Si la ventana no existe, este método crea la ventana de la barra del explorador como un elemento secundario de tamaño adecuado de la ventana primaria obtenida por SetSite. El identificador de la ventana secundaria se almacena en 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;
}

La implementación getSite del ejemplo simplemente ajusta una llamada al método QueryInterface del sitio mediante el puntero de sitio guardado por 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

Internet Explorer llamará a la interfaz IPersistStream de la barra del Explorador para permitir que la barra del Explorador cargue o guarde datos persistentes. Si no hay datos persistentes, los métodos deben devolver un código correcto. La interfaz IPersistStream hereda de IPersist, por lo que se deben implementar cinco métodos.

El ejemplo de barra del explorador no usa ningún dato persistente y solo tiene una implementación mínima de IPersistStream. IPersist::GetClassID devuelve el CLSID del objeto (CLSID_SampleExplorerBar) y el resto devuelve S_OK, S_FALSE o E_NOTIMPL.

IDeskBand

La interfaz IDeskBand es específica de los objetos de banda. Además de su único método, hereda de IDockingWindow, que a su vez hereda de IOleWindow.

Hay dos métodos IOleWindow : GetWindow e IOleWindow::ContextSensitiveHelp. La implementación del ejemplo de barra del explorador de GetWindow devuelve el identificador de ventana secundario de la barra del explorador, m_hwnd. No se implementa la Ayuda contextual, por lo que ContextSensitiveHelp devuelve E_NOTIMPL.

La interfaz IDockingWindow tiene tres métodos.

El método ResizeBorderDW no se usa con ningún tipo de objeto de banda y siempre debe devolver E_NOTIMPL. El método ShowDW muestra u oculta la ventana de la barra del explorador, en función del valor de su parámetro.

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

    return S_OK;
}

El método CloseDW destruye la ventana de la barra del explorador.

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

    return S_OK;
}

El método restante, GetBandInfo, es específico de IDeskBand. Internet Explorer lo usa para especificar el identificador y el modo de visualización de la barra del Explorador. Internet Explorer también puede solicitar una o varias partes de información de la barra del Explorador rellenando el miembro dwMask de la estructura DESKBANDINFO que se pasa como tercer parámetro. GetBandInfo debe almacenar el identificador y el modo de visualización y rellenar la estructura DESKBANDINFO con los datos solicitados. El ejemplo de barra del explorador implementa GetBandInfo como se muestra en el ejemplo de código siguiente.

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

Implementaciones de interfaz opcionales

Hay dos interfaces que no son necesarias, pero que pueden ser útiles para implementar: IInputObject e IContextMenu. El ejemplo de barra del explorador implementa IInputObject. Consulte la documentación para obtener información sobre cómo implementar IContextMenu.

IInputObject

La interfaz IInputObject debe implementarse si un objeto de banda acepta la entrada del usuario. Internet Explorer implementa IInputObjectSite y usa IInputObject para mantener el foco de entrada de usuario adecuado cuando tiene más de una ventana independiente. Hay tres métodos que deben implementarse mediante una barra del Explorador.

Internet Explorer llama a UIActivateIO para informar a la barra del Explorador de que se está activando o desactivando. Cuando se activa, el ejemplo barra del explorador llama a SetFocus para establecer el foco en su ventana.

Internet Explorer llama a HasFocusIO cuando intenta determinar qué ventana tiene el foco. Si la ventana de la barra del explorador o uno de sus descendientes tiene el foco, HasFocusIO debe devolver S_OK. Si no es así, debe devolver S_FALSE.

TranslateAcceleratorIO permite que el objeto procese aceleradores de teclado. El ejemplo de barra del explorador no implementa este método, por lo que devuelve S_FALSE.

La implementación de la barra de ejemplo de IInputObjectSite es la siguiente.

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

Registro clSID

Al igual que con todos los objetos COM, el CLSID de la barra del explorador debe estar registrado. Para que el objeto funcione correctamente con Internet Explorer, también debe registrarse para la categoría de componente adecuada (CATID_InfoBand). La sección de código pertinente para la barra del explorador se muestra en el ejemplo de código siguiente.

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

El registro de objetos de banda en el ejemplo usa procedimientos COM normales.

Además del CLSID, el servidor de objetos de banda también debe estar registrado para una o varias categorías de componentes. En realidad, esta es la principal diferencia en la implementación entre los ejemplos de barra de explorador vertical y horizontal. Este proceso se controla mediante la creación de un objeto de administrador de categorías de componentes (CLSID_StdComponentCategoriesMgr) y el uso del método ICatRegister::RegisterClassImplCategories para registrar el servidor de objetos de banda. En este ejemplo, el registro de categorías de componentes se controla pasando el CLSID y EL CATID del ejemplo de barra del explorador a una función privada (RegisterComCat), como se muestra en el ejemplo de código siguiente.

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

Procedimiento window

Dado que un objeto de banda usa una ventana secundaria para su presentación, debe implementar un procedimiento de ventana para controlar la mensajería de Windows. El ejemplo de banda tiene una funcionalidad mínima, por lo que su procedimiento de ventana solo controla cinco mensajes:

El procedimiento se puede expandir fácilmente para dar cabida a mensajes adicionales para admitir más características.

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

El controlador WM_COMMAND simplemente devuelve cero. El controlador de WM_PAINT crea la presentación de texto simple que se muestra en el ejemplo de barra del explorador en la introducción.

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

Los controladores WM_SETFOCUS y WM_KILLFOCUS informan al sitio de un cambio de foco llamando al método IInputObjectSite::OnFocusChangeIS del sitio.

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

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

Los objetos band proporcionan una manera flexible y eficaz de ampliar las funcionalidades de Internet Explorer mediante la creación de barras de Explorador personalizadas. La implementación de una banda de escritorio le permite ampliar las funcionalidades de las ventanas normales. Aunque se requiere cierta programación COM, en última instancia sirve para proporcionar una ventana secundaria para la interfaz de usuario. Desde allí, la mayor parte de la implementación puede usar técnicas de programación de Windows conocidas. Aunque el ejemplo que se describe aquí solo tiene una funcionalidad limitada, ilustra todas las características necesarias de un objeto de banda y se puede ampliar fácilmente para crear una interfaz de usuario única y eficaz.