Erstellen von benutzerdefinierten Explorer Balken, Werkzeugbändern und Schreibtischbändern

Die Explorer Bar wurde mit Microsoft Internet Explorer 4.0 eingeführt, um einen Anzeigebereich neben dem Browserbereich bereitzustellen. Es ist im Grunde ein untergeordnetes Fenster innerhalb des Windows Internet Explorer Fensters, und es kann verwendet werden, um Informationen anzuzeigen und mit dem Benutzer auf die gleiche Weise zu interagieren. Explorer Balken werden am häufigsten als vertikaler Bereich auf der linken Seite des Browserbereichs angezeigt. Eine Explorer leiste kann jedoch auch horizontal unterhalb des Browserbereichs angezeigt werden.

Screenshot der vertikalen und horizontalen Explorer Balken

Für die Explorer Bar gibt es zahlreiche Einsatzmöglichkeiten. Benutzer können die gewünschte Option auf verschiedene Arten auswählen, z. B. im Untermenü Explorer Bar des Menüs Ansicht oder durch Klicken auf eine Symbolleistenschaltfläche. Internet Explorer bietet mehrere Standard-Explorer Balken, einschließlich Favoriten und Suche.

Sie können internet-Explorer anpassen, indem Sie eine benutzerdefinierte Explorer-Leiste hinzufügen. Nach der Implementierung und Registrierung wird sie dem Untermenü Explorer Bar des Menüs Ansicht hinzugefügt. Wenn er vom Benutzer ausgewählt wird, kann der Anzeigebereich der Explorer Leiste dann verwendet werden, um Informationen anzuzeigen und Benutzereingaben auf die gleiche Weise wie ein normales Fenster zu übernehmen.

Screenshot der Explorerleisten

Zum Erstellen eines benutzerdefinierten Explorer Bar müssen Sie ein Bandobjekt implementieren und registrieren. Bandobjekte wurden mit Version 4.71 der Shell eingeführt und bieten Funktionen, die denen normaler Fenster ähneln. Da es sich jedoch um COM-Objekte (Component Object Model) handelt, die entweder im Internet Explorer oder in der Shell enthalten sind, werden sie etwas anders implementiert. Einfache Bandobjekte wurden verwendet, um das Beispiel Explorer Balken zu erstellen, die in der ersten Grafik angezeigt werden. Die Implementierung des vertikalen Explorer Bar-Beispiels wird in einem späteren Abschnitt ausführlich erläutert.

Toolbänder

Ein Toolband ist ein Bandobjekt, das mit Microsoft Internet Explorer 5 eingeführt wurde, um das Windows-Optionssymbolleistenfeature zu unterstützen. Die Symbolleiste "Internet Explorer" ist eigentlich ein Rebar-Steuerelement, das mehrere Symbolleistensteuerelemente enthält. Wenn Sie ein Toolband erstellen, können Sie diesem Rebar-Steuerelement eine Band hinzufügen. Wie Explorer Balken ist ein Werkzeugband jedoch ein universelles Fenster.

Screenshot von Toolbändern

Benutzer zeigen eine Symbolleiste an, indem sie sie im Untermenü Symbolleisten des MenüsAnsicht oder im Kontextmenü auswählen, das durch Klicken mit der rechten Maustaste auf den Symbolleistenbereich angezeigt wird.

Schreibtischbänder

Bandobjekte können auch zum Erstellen von Schreibtischbändern verwendet werden. Während ihre grundlegende Implementierung Explorer Bars ähnelt, haben Schreibtischbänder nichts mit internet-Explorer zu tun. Ein Schreibtischband ist im Grunde eine Möglichkeit, ein andockbares Fenster auf dem Desktop zu erstellen. Der Benutzer wählt sie aus, indem er mit der rechten Maustaste auf die Taskleiste klickt und sie im Untermenü Symbolleisten auswählt.

Screenshot: Beispiel für ein Schreibtischband

Zunächst sind Schreibtischbänder an der Taskleiste angedockt.

Screenshot: An der Taskleiste angedockte Schreibtischbänder

Der Benutzer kann dann das Schreibtischband auf den Desktop ziehen, und es wird als normales Fenster angezeigt.

Screenshot von Schreibtischbändern

Implementieren von Bandobjekten

Die folgenden Themen werden erläutert.

Grundlagen des Bandobjekts

Obwohl sie ähnlich wie normale Fenster verwendet werden können, sind Bandobjekte COM-Objekte, die in einem Container vorhanden sind. Explorer Bars sind in internet Explorer enthalten, und Schreibtischbänder sind in der Shell enthalten. Obwohl sie verschiedene Funktionen erfüllen, ist ihre grundlegende Implementierung sehr ähnlich. Der Hauptunterschied besteht darin, wie das Bandobjekt registriert wird, das wiederum den Typ des Objekts und seinen Container steuert. In diesem Abschnitt werden die Aspekte der Implementierung erläutert, die allen Bandobjekten gemeinsam sind. Weitere Implementierungsdetails finden Sie unter Ein einfaches Beispiel für eine benutzerdefinierte Explorer leiste.

Zusätzlich zu IUnknown und IClassFactory müssen alle Bandobjekte die folgenden Schnittstellen implementieren.

Neben der Registrierung ihres Klassenbezeichners (CLSID) müssen die Explorer Bar- und Desk-Band-Objekte auch für die entsprechende Komponentenkategorie registriert werden. Das Registrieren der Komponentenkategorie bestimmt den Objekttyp und dessen Container. Toolbänder verwenden ein anderes Registrierungsverfahren und verfügen nicht über einen Kategoriebezeichner (CATID). Die CATIDs für die drei Bandobjekte, die diese benötigen, sind:

Bandtyp Komponentenkategorie
Vertikale Explorer-Leiste CATID_InfoBand
Horizontale Explorer leiste CATID_CommBand
Schreibtischband CATID_DeskBand

 

Weitere Informationen zum Registrieren von Bandobjekten finden Sie unter Bandregistrierung .

Wenn das Bandobjekt Benutzereingaben akzeptiert, muss es auch IInputObject implementieren. Zum Hinzufügen von Elementen zum Kontextmenü für Explorer Bar- oder Schreibtischbänder muss das Bandobjekt IContextMenu exportieren. Symbolleisten unterstützen keine Kontextmenüs.

Da Bandobjekte ein untergeordnetes Fenster implementieren, müssen sie auch eine Fensterprozedur implementieren, um Windows-Messaging zu verarbeiten.

Bandobjekte können Befehle über die IOleCommandTarget-Schnittstelle des Containers an ihren Container senden. Um den Schnittstellenzeiger abzurufen, rufen Sie die IInputObjectSite::QueryInterface-Methode des Containers auf, und fragen Sie nach IID_IOleCommandTarget. Anschließend senden Sie Befehle mit IOleCommandTarget::Exec an den Container. Die Befehlsgruppe ist CGID_DeskBand. Wenn die IDeskBand::GetBandInfo-Methode eines Bandobjekts aufgerufen wird, verwendet der Container den dwBandID-Parameter , um dem Bandobjekt einen Bezeichner zuzuweisen, der für drei der Befehle verwendet wird. Vier IOleCommandTarget:: Exec-Befehls-IDs werden unterstützt.

  • DBID_BANDINFOCHANGED

    Die Bandinformationen wurden geändert. Legen Sie den parameter pvaIn auf den Bandbezeichner fest, der beim letzten Aufruf von IDeskBand::GetBandInfo empfangen wurde. Der Container ruft die IDeskBand::GetBandInfo-Methode des Bandobjekts auf, um die aktualisierten Informationen anzufordern.

  • DBID_MAXIMIZEBAND

    Maximieren Sie das Band. Legen Sie den parameter pvaIn auf den Bandbezeichner fest, der beim letzten Aufruf von IDeskBand::GetBandInfo empfangen wurde.

  • DBID_SHOWONLY

    Aktivieren oder deaktivieren Sie andere Bänder im Container. Legen Sie den pvaIn-Parameter auf den VT_UNKNOWN-Typ mit einem der folgenden Werte fest:

    Wert BESCHREIBUNG
    Punk Ein Zeiger auf die IUnknown-Schnittstelle des Bandobjekts. Alle anderen Schreibtischbänder werden ausgeblendet.
    0 Ausblenden aller Schreibtischbänder.
    1 Alle Schreibtischbänder anzeigen.

     

  • DBID_PUSHCHEVRON

    Version 5. Anzeigen eines Chevronmenüs Der Container sendet eine RB_PUSHCHEVRON Nachricht, und das Bandobjekt empfängt eine RBN_CHEVRONPUSHED Benachrichtigung, die zum Anzeigen des Menüs "Chevron" auffordert. Legen Sie den nCmdExecOpt-Parameter der IOleCommandTarget::Exec-Methode auf den Bandbezeichner fest, der im letzten Aufruf von IDeskBand::GetBandInfo empfangen wurde. Legen Sie den pvaIn-Parameter der IOleCommandTarget::Exec-Methode auf den typ VT_I4 mit einem anwendungsdefiniertem Wert fest. Es wird an das Bandobjekt als lAppValue-Wert der RBN_CHEVRONPUSHED-Benachrichtigung zurückgegeben.

Bandregistrierung

Ein Bandobjekt muss als OLE-In-Process-Server registriert werden, der Apartmentthreading unterstützt. Der Standardwert für den Server ist eine Menütextzeichenfolge. Für Explorer Bars wird sie im Untermenü Explorer Bar des Menüs Internet Explorer Ansicht angezeigt. Für Toolbänder wird sie im Untermenü Symbolleisten des Menüs Internet Explorer Ansicht angezeigt. Für Schreibtischbänder wird sie im Untermenü Symbolleisten des Kontextmenüs der Taskleiste angezeigt. Wie bei Menüressourcen führt das Platzieren eines ampersand (&) vor einem Buchstaben dazu, dass dieser unterstrichen wird und Tastenkombinationen aktiviert werden. Beispielsweise lautet die Menüzeichenfolge für die vertikale Explorer Leiste, die in der ersten Grafik gezeigt wird, "Sample &Vertical Explorer Bar".

Zunächst ruft Internet Explorer mithilfe der Komponentenkategorien eine Enumeration der registrierten Explorer Bar-Objekte aus der Registrierung ab. Um die Leistung zu erhöhen, wird diese Enumeration zwischengespeichert, sodass anschließend Explorer Bars übersehen werden. Um zu erzwingen, dass Windows Internet Explorer den Cache neu erstellt und eine neue Explorer Bar erkennt, löschen Sie während der Registrierung der neuen Explorer Leiste die folgenden Registrierungsschlüssel:

HKEY_CURRENT_USER\Software\Microsoft\Fenster\Currentversion\\ Explorer Discardable\PostSetup\Component Categories\{00021493-0000-0000-C000-000000000046}\Enum

HKEY_CURRENT_USER\Software\Microsoft\Fenster\Currentversion\\ Explorer Discardable\PostSetup\Component Categories\{00021494-0000-0000-C000-0000000000046}\Enum

Hinweis

Da für jeden Benutzer ein Explorer Bar-Cache erstellt wird, muss Ihre Setupanwendung möglicherweise alle Benutzerregistrierungsstrukturen auflisten oder einen Stub pro Benutzer hinzufügen, der ausgeführt werden soll, wenn sich der Benutzer zum ersten Mal anmeldet.

 

Im Allgemeinen wird der grundlegende Registrierungseintrag für ein Bandobjekt wie folgt angezeigt.

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

Bei Toolbändern muss auch die CLSID ihres Objekts bei internet-Explorer registriert sein. Weisen Sie hierzu einen Wert unter HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Toolbar mit der CLSID-GUID des Toolbandobjekts zu, wie hier gezeigt. Sein Datenwert wird ignoriert, sodass der Werttyp nicht wichtig ist.

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

Es gibt mehrere optionale Werte, die auch der Registrierung hinzugefügt werden können. Für instance ist der folgende Wert erforderlich, wenn Sie den Explorer Bar verwenden möchten, um HTML anzuzeigen. Der angezeigte Wert ist kein Beispiel, sondern der tatsächliche Wert, der verwendet werden sollte.

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

In Verbindung mit dem oben gezeigten Wert ist der folgende optionale Wert auch erforderlich, wenn Sie die Explorer Leiste zum Anzeigen von HTML verwenden möchten. Dieser Wert sollte auf den Speicherort der Datei festgelegt werden, die den HTML-Inhalt für die Explorer Leiste enthält.

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

Ein weiterer optionaler Wert definiert die Standardbreite oder -höhe des Explorer Balkens, je nachdem, ob er vertikal oder horizontal ist.

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

Der BarSize-Wert sollte auf die Breite oder Höhe des Balkens festgelegt werden. Der Wert benötigt acht Bytes und wird in der Registrierung als binärer Wert platziert. Die ersten vier Bytes geben die Größe in Pixeln im Hexadezimalformat an, beginnend mit dem byte links. Die letzten vier Bytes sind reserviert und sollten auf 0 (null) festgelegt werden.

Hier werden beispielsweise die vollständigen Registrierungseinträge für einen HTML-fähigen Explorer Bar mit einer Standardbreite von 291 (0x123) Pixeln angezeigt.

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

Sie können die Registrierung der CATID eines Bandobjekts programmgesteuert verarbeiten. Erstellen Sie ein Komponentenkategorien-Manager-Objekt (CLSID_StdComponentCategoriesMgr), und fordern Sie einen Zeiger auf die zugehörige ICatRegister-Schnittstelle an. Übergeben Sie die CLSID und CATID des Bandobjekts an ICatRegister::RegisterClassImplCategories.

Ein einfaches Beispiel für eine benutzerdefinierte Explorer leiste

In diesem Beispiel wird die Implementierung des vertikalen Beispiels Explorer Balken in der Einführung beschrieben.

Das grundlegende Verfahren zum Erstellen einer benutzerdefinierten Explorer Bar lautet wie folgt.

  1. Implementieren Sie die funktionen, die von der DLL benötigt werden.
  2. Implementieren Sie die erforderlichen COM-Schnittstellen.
  3. Implementieren Sie alle gewünschten optionalen COM-Schnittstellen.
  4. Registrieren Sie die CLSID des Objekts und, falls erforderlich, die Komponentenkategorie.
  5. Erstellen Sie ein untergeordnetes Fenster von Internet Explorer, das an den Anzeigebereich der Explorer Leiste angepasst ist.
  6. Verwenden Sie das untergeordnete Fenster, um Informationen anzuzeigen und mit dem Benutzer zu interagieren.

Die sehr einfache Implementierung, die im Beispiel Explorer Bar verwendet wird, könnte tatsächlich für einen Explorer Bar-Typ oder ein Schreibtischband verwendet werden, indem sie einfach für die entsprechende Komponentenkategorie registriert wird. Komplexere Implementierungen müssen für den Anzeigebereich und container jedes Objekttyps angepasst werden. Ein Großteil dieser Anpassung kann jedoch erreicht werden, indem Der Beispielcode verwendet und erweitert wird, indem vertraute Windows-Programmiertechniken auf das untergeordnete Fenster angewendet werden. Sie können beispielsweise Steuerelemente für Benutzerinteraktionen oder Grafiken für eine umfangreichere Anzeige hinzufügen.

DLL-Funktionen

Alle drei Objekte werden in einer einzelnen DLL gepackt, die die folgenden Funktionen verfügbar macht.

Die ersten drei Funktionen sind Standardimplementierungen und werden hier nicht behandelt. Die Class Factory-Implementierung ist ebenfalls Standard.

Erforderliche Schnittstellenimplementierungen

Das Beispiel für vertikale Explorer Bar implementiert die vier erforderlichen Schnittstellen: IUnknown, IObjectWithSite, IPersistStream und IDeskBand als Teil der CExplorerBar-Klasse. Die Implementierungen Konstruktor, Destruktor und IUnknown sind einfach und werden hier nicht erläutert. Sehen Sie sich den Beispielcode an, um ausführliche Informationen zu erhalten.

Die folgenden Schnittstellen werden ausführlich erläutert.

Iobjectwithsite

Wenn der Benutzer eine Explorer Bar auswählt, ruft der Container die IObjectWithSite::SetSite-Methode des entsprechenden Bandobjekts auf. Der PunkSite-Parameter wird auf den IUnknown-Zeiger der Website festgelegt.

Im Allgemeinen sollte eine SetSite-Implementierung die folgenden Schritte ausführen:

  1. Geben Sie alle Websitezeiger frei, die derzeit gespeichert werden.
  2. Wenn der an SetSite übergebene Zeiger auf NULL festgelegt ist, wird das Band entfernt. SetSite kann S_OK zurückgeben.
  3. Wenn der an SetSite übergebene Zeiger nicht NULL ist, wird eine neue Website festgelegt. SetSite sollte die folgenden Aktionen ausführen:
    1. Rufen Sie QueryInterface auf der Website für die IOleWindow-Schnittstelle auf.
    2. Rufen Sie IOleWindow::GetWindow auf, um das Handle des übergeordneten Fensters abzurufen. Speichern Sie das Handle zur späteren Verwendung. Geben Sie IOleWindow frei, wenn es nicht mehr benötigt wird.
    3. Erstellen Sie das Fenster des Bandobjekts als untergeordnetes Element des Im vorherigen Schritt abgerufenen Fensters. Erstellen Sie es nicht als sichtbares Fenster.
    4. Wenn das Bandobjekt IInputObject implementiert, rufen Sie QueryInterface auf der Website für die IInputObjectSite-Schnittstelle auf. Speichern Sie den Zeiger auf diese Schnittstelle zur späteren Verwendung.
    5. Wenn alle Schritte erfolgreich sind, geben Sie S_OK zurück. Wenn dies nicht der Fehler ist, geben Sie den OLE-definierten Fehlercode zurück, der angibt, welcher Fehler aufgetreten ist.

Im Beispiel Explorer Bar wird SetSite wie folgt implementiert. Im folgenden Code ist m_pSite eine private Membervariable, die den IInputObjectSite-Zeiger und m_hwndParent das Handle des übergeordneten Fensters enthält. In diesem Beispiel wird auch die Fenstererstellung behandelt. Wenn das Fenster nicht vorhanden ist, erstellt diese Methode das Fenster Explorer Bar als ein entsprechend großes untergeordnetes Element des übergeordneten Fensters, das von SetSite abgerufen wurde. Das Handle des untergeordneten Fensters wird in m_hwnd gespeichert.

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

Die GetSite-Implementierung des Beispiels umschließt einfach einen Aufruf der QueryInterface-Methode der Website mithilfe des von SetSite gespeicherten Websitezeigers.

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 ruft die IPersistStream-Schnittstelle der Explorer Bar auf, damit die Explorer Bar persistente Daten laden oder speichern kann. Wenn keine persistenten Daten vorhanden sind, müssen die Methoden trotzdem einen Erfolgscode zurückgeben. Die IPersistStream-Schnittstelle erbt von IPersist, sodass fünf Methoden implementiert werden müssen.

Das Beispiel Explorer Bar verwendet keine persistenten Daten und verfügt nur über eine minimale Implementierung von IPersistStream. IPersist::GetClassID gibt die CLSID (CLSID_SampleExplorerBar) des Objekts zurück, und der Rest gibt entweder S_OK, S_FALSE oder E_NOTIMPL zurück.

IDeskBand

Die IDeskBand-Schnittstelle ist spezifisch für Bandobjekte. Zusätzlich zu seiner einen Methode erbt es von IDockingWindow, das wiederum von IOleWindow erbt.

Es gibt zwei IOleWindow-Methoden : GetWindow und IOleWindow::ContextSensitiveHelp. Die Implementierung von GetWindow im Explorer Bar-Beispiel gibt das Ziehpunkt für untergeordnete Fenster des Explorer Bar m_hwnd zurück. Die kontextbezogene Hilfe ist nicht implementiert, sodass ContextSensitiveHelpE_NOTIMPL zurückgibt.

Die IDockingWindow-Schnittstelle verfügt über drei Methoden.

Die ResizeBorderDW-Methode wird nicht mit einem Bandobjekt verwendet und sollte immer E_NOTIMPL zurückgeben. Die ShowDW-Methode blendet das Fenster des Explorer Bar abhängig vom Wert des zugehörigen Parameters ein oder aus.

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

    return S_OK;
}

Die CloseDW-Methode zerstört das Fenster der Explorer Leiste.

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

    return S_OK;
}

Die verbleibende Methode GetBandInfo ist spezifisch für IDeskBand. Internet Explorer verwendet es, um den Bezeichner und den Anzeigemodus der Explorer Leiste anzugeben. Internet Explorer können auch eine oder mehrere Informationen von der Explorer Bar anfordern, indem sie den dwMask-Member der DESKBANDINFO-Struktur füllen, der als dritter Parameter übergeben wird. GetBandInfo sollte den Bezeichner und den Anzeigemodus speichern und die DESKBANDINFO-Struktur mit den angeforderten Daten füllen. Das beispiel Explorer Bar implementiert GetBandInfo, wie im folgenden Codebeispiel gezeigt.

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

Optionale Schnittstellenimplementierungen

Es gibt zwei Schnittstellen, die nicht erforderlich sind, aber für die Implementierung kann nützlich sein: IInputObject und IContextMenu. Das beispiel Explorer Bar implementiert IInputObject. Informationen zum Implementieren von IContextMenu finden Sie in der Dokumentation.

IInputObject

Die IInputObject-Schnittstelle muss implementiert werden, wenn ein Bandobjekt Benutzereingaben akzeptiert. Internet Explorer implementiert IInputObjectSite und verwendet IInputObject, um den richtigen Benutzereingabefokus beizubehalten, wenn mehr als ein enthaltenes Fenster vorhanden ist. Es gibt drei Methoden, die von einem Explorer-Balken implementiert werden müssen.

Internet Explorer ruft UIActivateIO auf, um die Explorer Leiste darüber zu informieren, dass sie aktiviert oder deaktiviert wird. Bei Aktivierung ruft das Beispiel Explorer Bar SetFocus auf, um den Fokus auf das zugehörige Fenster festzulegen.

Internet Explorer ruft HasFocusIO auf, wenn versucht wird, zu bestimmen, welches Fenster den Fokus hat. Wenn das Fenster der Explorer Leiste oder eines seiner Nachfolger den Fokus hat, sollte HasFocusIO S_OK zurückgeben. Andernfalls sollte S_FALSE zurückgegeben werden.

TranslateAcceleratorIO ermöglicht dem -Objekt die Verarbeitung von Tastenkombinationen. Das Explorer Bar-Beispiel implementiert diese Methode nicht, sodass S_FALSE zurückgegeben wird.

Die Implementierung von IInputObjectSite in der Beispielleiste lautet wie folgt.

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-Registrierung

Wie bei allen COM-Objekten muss die CLSID des Explorer Bar registriert werden. Damit das Objekt ordnungsgemäß mit internet Explorer funktioniert, muss es auch für die entsprechende Komponentenkategorie (CATID_InfoBand) registriert werden. Der relevante Codeabschnitt für die Explorer Bar wird im folgenden Codebeispiel gezeigt.

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

Die Registrierung von Bandobjekten im Beispiel verwendet normale COM-Verfahren.

Zusätzlich zur CLSID muss der Bandobjektserver auch für eine oder mehrere Komponentenkategorien registriert werden. Dies ist tatsächlich der Standard Unterschied bei der Implementierung zwischen den vertikalen und horizontalen Explorer Bar-Beispielen. Dieser Prozess wird verarbeitet, indem ein Komponentenkategorien-Manager-Objekt (CLSID_StdComponentCategoriesMgr) erstellt und die ICatRegister::RegisterClassImplCategories-Methode zum Registrieren des Bandobjektservers verwendet wird. In diesem Beispiel wird die Komponentenkategorieregistrierung verarbeitet, indem die CLSID und CATID des Explorer Bar-Beispiels an eine private Funktion – RegisterComCat – übergeben wird, wie im folgenden Codebeispiel gezeigt.

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

Die Fensterprozedur

Da ein Bandobjekt ein untergeordnetes Fenster für seine Anzeige verwendet, muss es eine Fensterprozedur implementieren, um Windows-Messaging zu verarbeiten. Das Bandbeispiel verfügt über minimale Funktionalität, sodass seine Fensterprozedur nur fünf Nachrichten verarbeitet:

Das Verfahren kann problemlos erweitert werden, um zusätzliche Nachrichten aufzunehmen, um weitere Features zu unterstützen.

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

Der WM_COMMAND-Handler gibt einfach null zurück. Der WM_PAINT-Handler erstellt die einfache Textanzeige, die im Beispiel Explorer Bar in der Einführung gezeigt wird.

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

Die WM_SETFOCUS- und WM_KILLFOCUS-Handler informieren die Website über eine Fokusänderung, indem sie die IInputObjectSite::OnFocusChangeIS-Methode der Website aufrufen.

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

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

Bandobjekte bieten eine flexible und leistungsstarke Möglichkeit, die Funktionen von Internet Explorer zu erweitern, indem benutzerdefinierte Explorer Bars erstellt werden. Durch die Implementierung eines Schreibtischbands können Sie die Funktionen normaler Fenster erweitern. Obwohl eine gewisse COM-Programmierung erforderlich ist, dient sie letztendlich dazu, ein untergeordnetes Fenster für Ihre Benutzeroberfläche bereitzustellen. Von dort aus kann der Großteil der Implementierung vertraute Windows-Programmiertechniken verwenden. Obwohl das hier erläuterte Beispiel nur eingeschränkte Funktionalität aufweist, werden alle erforderlichen Features eines Bandobjekts veranschaulicht, und es kann leicht erweitert werden, um eine einzigartige und leistungsstarke Benutzeroberfläche zu erstellen.