Przeczytaj w języku angielskim

Udostępnij za pośrednictwem


Tworzenie niestandardowych pasków eksploratora, pasków narzędzi i pasków biurkowych

Pasek eksploratora został wprowadzony w programie Microsoft Internet Explorer 4.0 w celu zapewnienia obszaru wyświetlania sąsiadującego z okienkiem przeglądarki. Jest to w zasadzie okno podrzędne w oknie programu Windows Internet Explorer i może służyć do wyświetlania informacji i interakcji z użytkownikiem w taki sam sposób. Paski eksploratora są najczęściej wyświetlane jako pionowe okienko po lewej stronie okienka przeglądarki. Jednak pasek Eksploratora może być również wyświetlany poziomo pod okienkiem przeglądarki.

Zrzut ekranu przedstawiający pionowe i poziome paski Eksploratora.

Istnieje szeroki zakres możliwych zastosowań paska Eksploratora. Użytkownicy mogą wybrać, która opcja ma być widoczna na kilka różnych sposobów, w tym wybranie jej z Paska Eksploratora podmenu menu Widok lub kliknięcie przycisku paska narzędzi. Program Internet Explorer udostępnia kilka standardowych pasków eksploratora, w tym ulubione i wyszukiwanie.

Jednym ze sposobów dostosowywania programu Internet Explorer jest dodanie niestandardowego paska eksploratora. Po wdrożeniu i zarejestrowaniu zostanie on dodany do podmenu paska eksploratora w menu Widok . Po wybraniu przez użytkownika obszaru wyświetlania paska eksploratora można następnie użyć do wyświetlania informacji i wprowadzania danych przez użytkownika w taki sam sposób jak w normalnym oknie.

zrzut ekranu pasków eksploratora

Aby utworzyć niestandardowy pasek Eksploratora, należy zaimplementować i zarejestrować obiekt pasm . Obiekty pasmowe zostały wprowadzone w wersji 4.71 Shell i zapewniają funkcje podobne do normalnych okien. Jednak ponieważ są to obiekty modelu obiektów składowych (COM) i zawarte w programie Internet Explorer lub powłoce, są one implementowane nieco inaczej. Proste obiekty pasmowe zostały użyte do utworzenia przykładowych pasków Eksploratora wyświetlanych na pierwszej grafice. Implementacja przykładu pionowego paska eksploratora zostanie szczegółowo omówiona w dalszej sekcji.

Opaski narzędziowe

pasek narzędziowy jest obiektem pasmowym wprowadzonym w programie Microsoft Internet Explorer 5 w celu obsługi funkcji radiowego paska narzędzi systemu Windows. Pasek narzędzi programu Internet Explorer jest w rzeczywistości kontrolką paska zawierającą kilka kontrolek paska narzędzi . Tworząc pasek narzędzi, można dodać pasek do tej kontrolki rebar. Jednak podobnie jak paski Eksploratora, pasek narzędzi jest oknem ogólnego przeznaczenia.

zrzut ekranu pasków narzędzi

Użytkownicy wyświetlają pasek narzędzi, wybierając go z podmenu Paski narzędzi w menu Widok lub z menu kontekstowego wyświetlanego po kliknięciu prawym przyciskiem myszy obszaru paska narzędzi.

Opaski biurkowe

Obiekty pasmowe mogą również służyć do tworzenia pasków biurkowych . Chociaż ich podstawowa implementacja jest podobna do pasków eksploratora, paski narzędziowe nie są powiązane z programem Internet Explorer. Pasek narzędziowy to w zasadzie sposób na utworzenie okna wbudowanego w pulpit. Użytkownik wybiera go, klikając prawym przyciskiem myszy pasek zadań i wybierając go z paski narzędzi podmenu.

Zrzut ekranu przedstawiający przykładowy pasek narzędziowy.

Początkowo paski biurkowe są zadokowane na pasku zadań.

Zrzut ekranu przedstawiający paski narzędzi zakotwiczone na pasku zadań.

Użytkownik może następnie przeciągnąć pasek biurkowy na pulpit i będzie wyświetlany jako normalne okno.

zrzut ekranu pasków narzędzi na pulpicie

Implementowanie obiektów pasmowych

Omówiono następujące tematy.

Podstawy obiektów pasmowych

Chociaż mogą być używane podobnie jak zwykłe okna, obiekty pasmowe są obiektami COM, które istnieją w kontenerze. Paski eksploratora znajdują się w programie Internet Explorer, a paski zadań znajdują się w powłoce. Chociaż pełnią one różne funkcje, ich podstawowa implementacja jest bardzo podobna. Podstawową różnicą jest sposób rejestrowania obiektu pasma, który z kolei kontroluje typ obiektu i jego kontenera. W tej sekcji omówiono te aspekty implementacji, które są wspólne dla wszystkich obiektów pasmowych. Zobacz prosty przykład niestandardowego paska eksploratora, aby uzyskać dodatkowe szczegóły dotyczące implementacji.

Oprócz IUnknown i IClassFactorywszystkie obiekty pasmowe muszą implementować następujące interfejsy.

Oprócz zarejestrowania identyfikatora klasy (CLSID) obiekty Paska Eksploratora i paska narzędziowego muszą być również zarejestrowane dla odpowiedniej kategorii komponentów. Zarejestrowanie kategorii składników określa typ obiektu i jego kontener. Pasma narzędzi używają innej procedury rejestracji i nie mają identyfikatora kategorii (CATID). Identyfikatory CATID dla trzech obiektów pasmowych, które ich wymagają, są następujące:

Typ przedziału Kategoria składnika
Pasek eksploratora pionowego CATID_InfoBand
Pasek poziomej eksploracji CATID_CommBand
Opaska biurkowa CATID_DeskBand

 

Aby uzyskać więcej informacji na temat rejestrowania obiektów pasmowych, zobacz rejestracji obiektów pasmowych.

Jeśli obiekt 'band' ma zaakceptować dane wejściowe użytkownika, musi również zaimplementować IInputObject. Aby dodać elementy do menu skrótów dla paska Eksploratora lub pasków narzędzi biurka, obiekt pasma musi wyeksportować IContextMenu. Paski narzędzi nie obsługują menu skrótów.

Ponieważ obiekty pasmowe implementują okno podrzędne, muszą również zaimplementować procedurę okna do obsługi komunikatów systemu Windows.

Obiekty pasmowe mogą wysyłać polecenia do swojego kontenera za pośrednictwem interfejsu IOleCommandTarget . Aby uzyskać wskaźnik interfejsu, wywołaj metodę IInputObjectSite::QueryInterface kontenera i zażądaj IID_IOleCommandTarget. Następnie wysyłasz polecenia do kontenera za pomocą polecenia IOleCommandTarget::Exec. Grupa poleceń jest CGID_DeskBand. Gdy wywoływana jest metodaobiektu zespołuIDeskBand::GetBandInfo, kontener używa parametru dwBandID, aby przypisać obiektowi identyfikator używany w trzech poleceniach. Cztery identyfikatory poleceń IOleCommandTarget::Exec są obsługiwane.

  • DBID_BANDINFOCHANGED

    Informacje o zespole uległy zmianie. Ustaw parametr pvaIn na identyfikator zespołu, który został odebrany w ostatnim wywołaniu do IDeskBand::GetBandInfo. Kontener wywoła metodę IDeskBand::GetBandInfo obiektu pasma, aby zażądać zaktualizowanych informacji.

  • DBID_MAXIMIZEBAND

    Maksymalizuj zespół. Ustaw parametr pvaIn na identyfikator pasma, który został odebrany w ostatnim wywołaniu funkcji IDeskBand::GetBandInfo.

  • DBID_SHOWONLY

    Włączanie lub wyłączanie innych pasm w kontenerze. Ustaw parametr pvaIn na typ VT_UNKNOWN z jedną z następujących wartości:

    Wartość Opis
    pUnk Wskaźnik do interfejsu IUnknown obiektu pasma. Wszystkie inne opaski biurkowe będą ukryte.
    0 Ukryj wszystkie paski biurkowe.
    1 Pokaż wszystkie paski narzędziowe pulpitu.

     

  • DBID_PUSHCHEVRON

    w wersji 5. Wyświetl menu z symbolem strzałki. Kontener wysyła komunikat RB_PUSHCHEVRON, a obiekt paska odbiera powiadomienie RBN_CHEVRONPUSHED, co powoduje wyświetlenie menu guzika strzałki. Ustaw parametr IOleCommandTarget::Exec metody nCmdExecOpt na identyfikator grupy odebrany w ostatnim wywołaniu IDeskBand::GetBandInfo. Ustaw parametr IOleCommandTarget::Exec metody pvaIn na typ VT_I4 z wartością zdefiniowaną przez aplikację. Przekazuje z powrotem do obiektu pasma jako wartość lAppValue dla powiadomienia RBN_CHEVRONPUSHED.

Rejestracja zespołu

Obiekt pasma musi być zarejestrowany jako serwer przetwarzania OLE, który obsługuje wątkowanie apartamentów. Wartość domyślna serwera to ciąg tekstowy menu. W obszarze Paski eksploratora zostanie on wyświetlony w podmenu paska eksploratora Programu Internet Explorer View menu. W przypadku pasków narzędzi pojawi się on w menu Paski narzędzi podmenu programu Internet Explorer View. W przypadku pasków narzędzi pojawi się ono w podmenu Paski narzędzi menu skrótów paska zadań. Podobnie jak w przypadku zasobów menu, umieszczenie znaku i (&) przed literą spowoduje podkreślenie i włączenie skrótów klawiaturowych. Na przykład ciąg menu pionowego paska Eksploratora pokazany na pierwszej grafice to "Sample &Vertical Explorer Bar".

Początkowo program Internet Explorer pobiera wyliczenie zarejestrowanych obiektów paska eksploratora z rejestru przy użyciu kategorii składników. Aby zwiększyć wydajność, buforuje to wyliczenie, co powoduje, że paski eksploratora dodane później są pomijane. Aby wymusić, by program Windows Internet Explorer odtworzył pamięć podręczną i rozpoznał nowy pasek eksploratora, usuń następujące klucze rejestru podczas rejestracji nowego paska eksploratora.

pl-PL: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Odrzucone\\Kategorie Składników\{00021493-0000-0000-C000-000000000046}\Enum

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\niezachowane\PostSetup\Kategorie komponentów\{00021494-0000-0000-C000-000000000046}\Enum

Uwaga

Ponieważ pamięć podręczna paska eksploratora jest tworzona dla każdego użytkownika, aplikacja instalacyjna może wymagać wyliczenia wszystkich gałęzi rejestru użytkowników lub dodania elementu startowego dla poszczególnych użytkowników, który uruchomi się podczas pierwszego logowania się użytkownika.

 

Ogólnie rzecz biorąc, podstawowy wpis rejestru dla obiektu pasma będzie wyświetlany w następujący sposób.

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

Paski narzędzi muszą również mieć identyfikator CLSID obiektu zarejestrowany w programie Internet Explorer. W tym celu przypisz wartość w obszarze HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Toolbar nazwaną identyfikatorem GUID obiektu paska narzędzi CLSID, jak pokazano tutaj. Jego wartość danych jest ignorowana, więc typ wartości jest nieważny.

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

Istnieje kilka opcjonalnych wartości, które można również dodać do rejestru. Na przykład poniższa wartość jest niezbędna, jeśli chcesz użyć paska eksploratora do wyświetlenia kodu HTML Wyświetlana wartość nie jest przykładem, ale rzeczywista wartość, która powinna być używana.

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

Używana w połączeniu z wartością pokazaną powyżej, następująca opcjonalna wartość jest również niezbędna, jeśli chcesz użyć paska eksploratora do wyświetlenia kodu HTML. Ta wartość powinna być ustawiona na lokalizację pliku zawierającego zawartość HTML paska eksploratora.

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

Inna opcjonalna wartość definiuje domyślną szerokość lub wysokość paska Eksploratora, w zależności od tego, czy jest odpowiednio pionowa, czy pozioma.

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

Wartość BarSize powinna być ustawiona na szerokość lub wysokość słupka. Wartość wymaga ośmiu bajtów i jest umieszczana w rejestrze jako wartość binarna. Pierwsze cztery bajty określają rozmiar w pikselach w formacie szesnastkowym, zaczynając od lewego bajtu. Ostatnie cztery bajty są zarezerwowane i powinny być ustawione na zero.

Na przykład pełne wpisy rejestru dla paska eksploratora obsługującego kod HTML o domyślnej szerokości 291 (0x123) pikseli są wyświetlane tutaj.

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

Rejestrację identyfikatora CATID obiektu zespołu można obsługiwać programowo. Utwórz obiekt menedżera kategorii składników (CLSID_StdComponentCategoriesMgr) i zażądaj wskaźnika do interfejsu ICatRegister. Przekaż identyfikator CLSID i CATID obiektu pasma do ICatRegister::RegisterClassImplCategories.

Prosty przykład paska eksploratora niestandardowego

W tym przykładzie przedstawiono implementację przykładowego pionowego paska eksploratora pokazanego we wprowadzeniu.

Podstawowa procedura tworzenia niestandardowego paska eksploratora jest następująca.

  1. Zaimplementuj funkcje wymagane przez bibliotekę DLL.
  2. Zaimplementuj wymagane interfejsy COM.
  3. Zaimplementuj dowolne opcjonalne interfejsy COM.
  4. Zarejestruj identyfikator CLSID obiektu i, jeśli jest to wymagane, kategoria składników.
  5. Utwórz okno podrzędne programu Internet Explorer o rozmiarze odpowiadającym regionie wyświetlania paska programu Explorer.
  6. Użyj okna podrzędnego do wyświetlania informacji i interakcji z użytkownikiem.

Bardzo prostą implementację używaną w przykładzie Paska Eksploratora można rzeczywiście używać dla dowolnego typu paska eksploratora lub paska narzędzi, po prostu rejestrując go w odpowiedniej kategorii składników. Bardziej zaawansowane implementacje należy dostosować dla regionu wyświetlania i kontenera każdego typu obiektu. Jednak wiele z tych dostosowań można osiągnąć przez pobranie przykładowego kodu i rozszerzenie go przez zastosowanie znanych technik programowania systemu Windows do okna podrzędnego. Na przykład można dodawać kontrolki interakcji z użytkownikiem lub grafikę dla bogatszego wyświetlania.

Funkcje DLL

Wszystkie trzy obiekty są pakowane w pojedynczej biblioteki DLL, która uwidacznia następujące funkcje.

Pierwsze trzy funkcje to standardowe implementacje i nie zostaną tu omówione. Implementacja fabryki klas jest również standardowa.

Implementacje wymaganego interfejsu

Przykład pionowego paska eksploratora implementuje cztery wymagane interfejsy: IUnknown, IObjectWithSite, IPersistStreamoraz IDeskBand w ramach klasy CExplorerBar. Konstruktor, destruktor i implementacje IUnknown są proste i nie zostaną omówione tutaj. Aby uzyskać szczegółowe informacje, zobacz przykładowy kod.

Poniższe interfejsy zostały szczegółowo omówione.

IObjectWithSite

Gdy użytkownik wybierze pasek Eksploratora, kontener wywołuje IObjectWithSite::SetSite obiektu pasmowego. Parametr punkSite zostanie ustawiony na wskaźnik IUnknown witryny.

Ogólnie rzecz biorąc, implementacja SetSite powinna wykonać następujące czynności:

  1. Zwolnij dowolny wskaźnik witryny, który jest obecnie przechowywany.
  2. Jeśli wskaźnik przekazany do SetSite jest ustawiony na wartość null, zespół jest usuwany. SetSite może zwrócić S_OK.
  3. Jeśli wskaźnik przekazany do SetSite jest inny niżNULL, jest ustawiana nowa lokalizacja. setSite należy wykonać następujące czynności:
    1. Wywołaj QueryInterface w witrynie dla interfejsu IOleWindow.
    2. Wywołaj IOleWindow::GetWindow, aby uzyskać uchwyt okna nadrzędnego. Zapisz uchwyt do późniejszego użycia. Zwolnij IOleWindow, jeśli nie jest już potrzebne.
    3. Utwórz okno obiektu pasma jako element podrzędny okna uzyskanego w poprzednim kroku. Nie twórz go jako widocznego okna.
    4. Jeśli obiekt pasma implementuje IInputObject, wywołaj QueryInterface na stronie dla interfejsu IInputObjectSite. Zapisz wskaźnik do tego interfejsu do późniejszego użycia.
    5. Jeśli wszystkie kroki zakończyły się pomyślnie, zwróć S_OK. Jeśli nie, zwróć kod błędu zdefiniowany przez OLE określający, co poszło nie tak.

Przykład paska eksploratora implementuje SetSite w następujący sposób. W poniższym kodzie m_pSite jest prywatną zmienną składową, która zawiera wskaźnik IInputObjectSite i m_hwndParent przechowuje uchwyt okna nadrzędnego. W tym przykładzie jest również obsługiwane tworzenie okien. Jeśli okno nie istnieje, ta metoda tworzy okno paska Eksploratora jako podrzędne okno odpowiedniego rozmiaru w ramach okna nadrzędnego uzyskanego przez SetSite. Uchwyt okna podrzędnego jest przechowywany w 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;
}

Implementacja GetSite przykładu po prostu opakowuje wywołanie metody QueryInterface witryny, używając wskaźnika witryny zapisanego przez 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

Program Internet Explorer wywoła interfejs IPersistStream paska eksploratora, aby umożliwić ładowanie lub zapisywanie trwałych danych przez pasek eksploratora. Jeśli nie ma danych trwałych, metody muszą nadal zwracać kod powodzenia. Interfejs IPersistStream dziedziczy z IPersist, więc należy zaimplementować pięć metod.

Przykład paska eksploratora nie używa żadnych trwałych danych i ma tylko minimalną implementację IPersistStream. IPersist::GetClassID zwraca identyfikator CLSID obiektu (CLSID_SampleExplorerBar), a reszta zwróci S_OK, S_FALSE lub E_NOTIMPL.

IDeskBand

Interfejs IDeskBand jest specyficzny dla obiektów pasmowych. Oprócz swojej jednej metody dziedziczy ona z IDockingWindow, która z kolei dziedziczy z IOleWindow.

Istnieją dwie metody IOleWindow: GetWindow i IOleWindow::ContextSensitiveHelp. Przykładowa implementacja paska eksploratora GetWindow zwraca uchwyt okna podrzędnego dla tego paska, m_hwnd. Pomoc kontekstowa nie jest zaimplementowana, dlatego ContextSensitiveHelp zwraca E_NOTIMPL.

Interfejs IDockingWindow ma trzy metody.

Metoda ResizeBorderDW nie jest używana z żadnym typem obiektu pasmowego i zawsze powinna zwracać E_NOTIMPL. Metoda ShowDW pokazuje lub ukrywa okno paska Eksploratora, w zależności od wartości jego parametru.

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

    return S_OK;
}

Metoda CloseDW niszczy okno paska eksploratora.

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

    return S_OK;
}

Pozostała metoda, GetBandInfo, jest specyficzna dla IDeskBand. Program Internet Explorer używa go do określania identyfikatora paska programu Explorer i trybu wyświetlania. Program Internet Explorer może również zażądać jednego lub więcej elementów informacji z paska eksploratora, wypełniając dwMask składową struktury DESKBANDINFO, która jest przekazywana jako trzeci parametr. GetBandInfo powinny przechowywać identyfikator i tryb wyświetlania oraz wypełnić strukturę DESKBANDINFO żądanymi danymi. Przykład paska eksploratora implementuje GetBandInfo, jak pokazano w poniższym przykładzie kodu.

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

Implementacje interfejsu opcjonalnego

Istnieją dwa interfejsy, które nie są wymagane, ale może to być przydatne do zaimplementowania: IInputObject i IContextMenu. Przykład paska eksploratora implementuje IInputObject. Zapoznaj się z dokumentacją, aby uzyskać informacje na temat implementowania IContextMenu.

IInputObject

Interfejs IInputObject należy zaimplementować, jeśli obiekt przedziału akceptuje dane wejściowe użytkownika. Program Internet Explorer implementuje IInputObjectSite i używa IInputObject w celu utrzymania prawidłowego fokusu na danych wejściowych użytkownika, gdy ma więcej niż jedno zawarte okno. Istnieją trzy metody, które należy zaimplementować za pomocą paska eksploratora.

Program Internet Explorer wywołuje UIActivateIO, aby poinformować pasek eksploratora o jego aktywacji lub dezaktywacji. Po aktywacji przycisk paska eksploratora wywołuje SetFocus, aby ustawić skupienie na swoim oknie.

Program Internet Explorer wywołuje HasFocusIO podczas próby określenia, które okno ma fokus. Jeśli okno paska eksploratora lub jeden z jego elementów potomnych ma fokus, HasFocusIO powinien zwrócić S_OK. Jeśli nie, powinien zwrócić S_FALSE.

TranslateAcceleratorIO umożliwia obiektowi przetwarzanie akceleratorów klawiatury. Przykład paska eksploratora nie implementuje tej metody, dlatego zwraca S_FALSE.

Implementacja przykładowego paska IInputObjectSite jest następująca.

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

Rejestracja CLSID

Podobnie jak we wszystkich obiektach COM, identyfikator CLSID paska eksploratora musi być zarejestrowany. Aby obiekt działał prawidłowo w programie Internet Explorer, musi być również zarejestrowany dla odpowiedniej kategorii składników (CATID_InfoBand). Odpowiednia sekcja kodu paska Eksploratora jest pokazana w poniższym przykładzie kodu.

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

Rejestracja obiektów pasmowych w przykładzie używa normalnych procedur COM.

Oprócz CLSID serwer obiektów pasma musi być również zarejestrowany w co najmniej jednej kategorii składników. Jest to faktycznie główna różnica w implementacji między przykładami pionowymi i poziomymi paska eksploratora. Ten proces jest obsługiwany przez utworzenie obiektu menedżera kategorii składników (CLSID_StdComponentCategoriesMgr) i użycie metody ICatRegister::RegisterClassImplCategories do rejestrowania serwera obiektu pasma. W tym przykładzie rejestracja kategorii komponentów jest obsługiwana przez przekazanie identyfikatorów CLSID i CATID przykładu paska narzędzi Eksploratora do funkcji prywatnej —RegisterComCat— jak pokazano w poniższym przykładzie kodu.

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

Procedura okna

Ponieważ obiekt paska używa okna podrzędnego do swojego wyświetlania, musi zaimplementować procedurę okna do obsługi komunikatów systemu Windows. Próbka pasma ma minimalną funkcjonalność, więc procedura okna obsługuje tylko pięć komunikatów.

Procedurę można łatwo rozszerzyć, aby obsłużyć dodatkowe komunikaty w celu obsługi większej liczby funkcji.

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

Procedura obsługi WM_COMMAND po prostu zwraca zero. Procedura obsługi WM_PAINT tworzy prosty tekst wyświetlany w przykładzie paska eksploratora we wprowadzeniu.

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

Programy obsługi WM_SETFOCUS i WM_KILLFOCUS informują witrynę o zmianie fokusu, wywołując metodę IInputObjectSite::OnFocusChangeIS.

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

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

Obiekty pasmowe zapewniają elastyczny i zaawansowany sposób rozszerzania możliwości programu Internet Explorer przez tworzenie niestandardowych pasków programu Explorer. Wdrożenie paska narzędzi umożliwia rozszerzenie możliwości typowych okien. Mimo że niektóre programowanie COM jest wymagane, ostatecznie służy do zapewnienia okienka podrzędnego dla interfejsu użytkownika. Z tego miejsca większość implementacji może używać znanych technik programowania systemu Windows. Chociaż omówiony tutaj przykład ma tylko ograniczone funkcje, ilustruje wszystkie niezbędne funkcje obiektu pasma i można go łatwo rozszerzyć w celu utworzenia unikatowego i zaawansowanego interfejsu użytkownika.