共用方式為


建立自定義總管列、工具帶和桌面頻帶

Explorer 列是 Microsoft Internet Explorer 4.0 引進的,可提供與瀏覽器窗格相鄰的顯示區域。 它基本上是 Windows Internet Explorer 視窗中的子視窗,它可以用來顯示資訊,並以完全相同的方式與用戶互動。 總管列最常顯示為瀏覽器窗格左側的垂直窗格。 不過,瀏覽器窗格下方也可以水平顯示總管列。

Screenshot that shows the vertical and horizontal Explorer Bars.

總管列有各種不同的可能用途。 使用者可以以數種不同的方式選取想要查看的選項,包括從 [檢視] 功能表的 [總管列] 子功能表選取它,或單擊工具列按鈕。 Internet Explorer 提供數個標準總管列,包括 [我的最愛] 和 [搜尋]。

您可以自定義 Internet Explorer 的其中一種方式是新增自定義 Explorer 列。 實作並註冊時,它會新增至 [檢視] 功能表的 [總管列] 子功能表。 當使用者選取時,瀏覽器列的顯示區域接著可以用來顯示資訊,並以與一般視窗相同的方式接受用戶輸入。

screen shot of the explorer bars

若要建立自定義總管列,您必須實作並註冊 帶狀物件。 頻帶物件是使用Shell 4.71版引進的,並提供與一般窗口類似的功能。 不過,因為它們是元件物件模型 (COM) 物件,而且是由 Internet Explorer 或 Shell 所包含,所以它們會以稍微不同的方式實作。 簡單帶狀物件可用來建立第一個圖形中顯示的範例總管列。 後續章節將詳細討論垂直總管列範例的實作。

工具帶

工具帶是 Microsoft Internet Explorer 5 引進的頻帶物件,可支援 Windows 無線電工具列功能。 Internet Explorer 工具列實際上是包含數個工具欄控件的 Rebar 控件 藉由建立工具帶,您可以將帶狀新增至該 Rebar 控件。 不過,就像總管列一樣,工具列是一般用途視窗。

screen shot of tool bands

使用者從 [檢視] 功能表的 [工具列] 子功能選取工具列,或從以滑鼠右鍵按兩下工具列區域所顯示的快捷方式功能表來顯示工具列。

辦公桌帶

頻帶物件也可以用來建立 桌面頻帶。 雖然其基本實作類似於 Explorer 列,但桌面樂隊與 Internet Explorer 無關。 桌面樂隊基本上是一種在桌面上建立可停駐視窗的方式。 使用者以滑鼠右鍵按兩下任務列,然後從 [工具列 ] 子功能選取它來選取它。

Screenshot that shows a sample desk band.

一開始,桌面樂隊停駐在任務欄上。

Screenshot that shows desk bands docked on the task bar.

然後,用戶可以將桌面帶拖曳至桌面,並顯示為一般視窗。

screen shot of desk bands

實作頻帶物件

下列主題會討論。

Band 物件基本概念

雖然它們可以像一般視窗一樣使用,但帶狀物件是存在於容器內的 COM 物件。 Explorer 列是由 Internet Explorer 所包含,桌面樂隊則由 Shell 所包含。 雖然它們提供不同的功能,但他們的基本實作非常類似。 主要差異在於註冊頻帶物件的方式,進而控制物件及其容器的類型。 本節討論所有頻帶物件通用的實作層面。 如需其他實作詳細數據,請參閱 自定義總管列 的簡單範例。

除了 IUnknownIClassFactory 之外,所有頻帶對象都必須實作下列介面。

除了註冊其類別標識碼 (CLSID),Explorer Bar 和 desk band 對象也必須註冊適當的元件類別目錄。 註冊元件類別會決定物件類型和其容器。 工具帶使用不同的註冊程式,而且沒有類別標識碼(CATID)。 這三個需要它們的頻帶物件的 CATID 為:

頻帶類型 元件類別
垂直總管列 CATID_InfoBand
水平總管列 CATID_CommBand
桌面帶 CATID_DeskBand

 

如需如何註冊頻帶對象的進一步討論,請參閱 頻帶註冊

如果頻帶物件是接受使用者輸入,它也必須實作 IInputObject 若要將專案新增至 Explorer Bar 或桌面頻帶的快捷方式功能表,樂隊對象必須匯出 IContextMenu 工具區不支援快捷功能表。

因為帶狀物件會實作子視窗,所以它們也必須實作視窗程序來處理 Windows 傳訊。

Band 物件可以透過容器的 IOleCommandTarget 介面,將命令傳送至其容器。 若要取得介面指標,請呼叫容器的 IInputObjectSite::QueryInterface 方法,並要求IID_IOleCommandTarget。 接著,您會使用 IOleCommandTarget::Exec 將命令傳送至容器。 命令群組CGID_DeskBand。 呼叫頻帶物件的 IDeskBand::GetBandInfo 方法時,容器會使用 dwBandID 參數將帶物件指派為用於其中三個命令的標識符。 支援四個 IOleCommandTarget::Exec 命令標識碼。

  • DBID_BANDINFOCHANGED

    樂隊的資訊已經改變。 將 pvaIn 參數設定為最近呼叫 IDeskBand::GetBandInfo 中所收到的頻帶標識碼。 容器會呼叫頻帶物件的 IDeskBand::GetBandInfo 方法,以要求更新的資訊。

  • DBID_MAXIMIZEBAND

    最大化帶狀。 將 pvaIn 參數設定為最近呼叫 IDeskBand::GetBandInfo 中所收到的頻帶標識碼。

  • DBID_SHOWONLY

    開啟或關閉容器中的其他頻帶。 使用下列其中一個值,將 pvaIn 參數設定為VT_UNKNOWN類型:

    Description
    朋 克 頻帶物件的 IUnknown 介面指標。 所有其他辦公桌帶都會隱藏起來。
    0 隱藏所有辦公桌帶。
    1 顯示所有辦公桌帶。

     

  • DBID_PUSHCHEVRON

    第 5 版。 顯示>形箭號功能表。 容器會傳送 RB_PUSHCHEVRON 訊息,而 band 物件會收到 RBN_CHEVRONPUSHED 通知,提示它顯示>形箭號功能表。 將 IOleCommandTarget::Exec 方法的 nCmdExecOpt 參數設定為最近呼叫 IDeskBand::GetBandInfo 中所收到的頻帶標識碼。 使用應用程式定義的值,將 IOleCommandTarget::Exec 方法的 pvaIn 參數設定為VT_I4類型。 它會以RBN_CHEVRONPUSHED通知的 lAppValue 值傳回給頻帶物件

頻帶註冊

帶狀對象必須註冊為支援 Apartment 線程的 OLE 同進程伺服器。 伺服器的預設值是功能表文字字串。 針對總管列,它會出現在 Internet Explorer 檢視功能表的 [總管列] 子功能表中。 針對工具區,它會出現在 Internet Explorer 檢視功能表的 [工具欄] 子功能表中。 對於桌面樂隊,它會出現在 任務欄快捷方式功能表的工具列 子功能表中。 如同功能表資源,將連字元和 (&) 放在字母前面會導致它加上底線並啟用鍵盤快捷方式。 例如,第一個圖形中顯示的垂直總管列功能表字串是「範例與垂直總管列」。

一開始,Internet Explorer 會使用元件類別從登錄擷取已註冊的 Explorer Bar 物件列舉。 為了提升效能,它會快取此列舉,導致後續新增的 Explorer Bars 會被忽略。 若要強制 Windows Internet Explorer 重建快取並辨識新的 Explorer 列,請在新 Explorer 列的註冊期間刪除下列登錄機碼:

\HKEY_CURRENT_USER軟體\Microsoft\Windows\CurrentVersion\Explorer\可捨棄\PostSetup\元件類別\{00021493-0000-0000-C000-00000000000046}列舉\

\HKEY_CURRENT_USER軟體\Microsoft\Windows\CurrentVersion\Explorer\可捨棄的\PostSetup\元件類別\{00021494-0000-0000-C000-000000000046}列舉\

注意

因為系統會為每個使用者建立檔案總管列快取,因此您的設定應用程式可能需要列舉所有用戶登錄區,或新增每個使用者存根,以在使用者第一次登入時執行。

 

一般而言,頻帶物件的基本登錄項目會顯示如下。

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

工具區也必須在其物件的 CLSID 向 Internet Explorer 註冊。 若要這樣做,請使用工具區物件的CLSID GUID,在 HKEY_LOCAL_MACHINE [\軟體][Microsoft\\Internet Explorer\工具列] 底下指派值,如下所示。 會忽略其數據值,因此實值類型不重要。

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

有數個選擇性值也可以新增至登錄。 例如,如果您想要使用總管列來顯示 HTML,則下列值是必要的。所顯示的值不是範例,而是應該使用的實際值。

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

與上述值搭配使用,如果您想要使用總管列來顯示 HTML,也需要下列選擇性值。 此值應該設定為檔案的位置,其中包含 Explorer Bar 的 HTML 內容。

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

另一個選擇性值會根據瀏覽器列的默認寬度或高度,分別根據它是垂直還是水準。

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

BarSize 值應該設定為橫條的寬度或高度。 此值需要八個字節,且會放在登錄中做為二進位值。 前四個字節會以像素為單位,以十六進位格式指定從最左邊位元組開始的大小。 最後四個字節是保留的,而且應該設定為零。

例如,這裡會顯示預設寬度為 291 (0x123) 圖元之 HTML 功能總管列的完整登錄專案。

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

您可以透過程式設計方式處理頻帶物件的 CATID 註冊。 建立元件類別管理員物件 (CLSID_StdComponentCategoriesMgr),並要求其 ICatRegister 介面的指標。 將頻帶物件的 CLSID 和 CATID 傳遞至 ICatRegister::RegisterClassImplCategories

自定義總管列的簡單範例

此範例會逐步執行簡介中所顯示範例垂直總管列的實作。

建立自定義總管列的基本程式如下。

  1. 實作 DLL 所需的函式。
  2. 實作必要的 COM 介面。
  3. 實作任何所需的選擇性 COM 介面。
  4. 註冊物件的 CLSID,並視需要註冊元件類別目錄。
  5. 建立 Internet Explorer 的子視窗,大小以符合 Explorer 列的顯示區域。
  6. 使用子視窗來顯示資訊,並與用戶互動。

Explorer Bar 範例中使用的非常簡單的實作,實際上可以藉由為適當的元件類別註冊它,來用於 Explorer Bar 類型或桌面樂隊。 需要針對每個物件類型的顯示區域和容器自定義更複雜的實作。 不過,透過將熟悉的 Windows 程式設計技術套用至子視窗,即可完成大部分的自定義。 例如,您可以新增用戶互動的控件,或更豐富的顯示圖形。

DLL 函式

這三個對象都會封裝在單一 DLL 中,這會公開下列函式。

前三個函式是標準實作,此處不會討論。 Class Factory 實作也是標準的。

必要的介面實作

垂直總管列範例會實作四個必要介面:IUnknown、IObjectWithSiteIPersistStreamIDeskBand 作為 CExplorerBar 類別的一部分。 建構函式、解構函式和 IUnknown 實作很簡單,而且不會在這裡討論。 如需詳細資訊,請參閱範例程式碼。

下列介面會詳細討論。

IObjectWithSite

當使用者選取總管列時,容器會呼叫對應的帶狀物件 IObjectWithSite::SetSite 方法。 punkSite 參數會設定為網站的 IUnknown 指標。

一般而言, SetSite 實作應該執行下列步驟:

  1. 釋放目前正在保留的任何網站指標。
  2. 如果傳遞至 SetSite 的指標設定為 NULL,則會移除帶狀。 SetSite 可以傳回S_OK。
  3. 如果傳遞至 SetSite 的指標不是 NULL,則會設定新的月臺。 SetSite 應該執行下列動作:
    1. 站臺上呼叫 QueryInterface 以取得其 IOleWindow 介面。
    2. 呼叫 IOleWindow::GetWindow 以取得父視窗的句柄。 儲存句柄以供日後使用。 如果不再需要,請發行 IOleWindow
    3. 將頻帶對象的視窗建立為上一個步驟中取得之視窗的子系。 請勿將它建立為可見的視窗。
    4. 如果 band 物件實作 IInputObject,請在站臺上呼叫 QueryInterface 以取得其 IInputObjectSite 介面。 儲存此介面的指標以供稍後使用。
    5. 如果所有步驟都成功,請傳回S_OK。 如果沒有,則傳回指出失敗的 OLE 定義錯誤碼。

Explorer Bar 範例會以下列方式實作 SetSite 在下列程式代碼中,m_pSite是保存 IInputObjectSite 指標且m_hwndParent保存父視窗句柄的私人成員變數。 在此範例中,也會處理視窗建立。 如果視窗不存在,這個方法會建立 Explorer Bar 的視窗,做為 SetSite 取得之父視窗的適當大小子系。 子視窗的句柄會儲存在 m_hwnd中。

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

    m_hwndParent = NULL;

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

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

                RegisterClassW(&wc);

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

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

            pow->Release();
        }

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

    return hr;
}

此範例的 GetSite 實作只會使用 SetSite儲存的網站指標,包裝對月臺 QueryInterface 方法的呼叫。

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 會呼叫 Explorer Bar 的 IPersistStream 介面,以允許 Explorer Bar 載入或儲存持續性數據。 如果沒有持續性數據,方法仍必須傳回成功碼。 IPersistStream 介面繼承自 IPersist,因此必須實作五種方法。

Explorer Bar 範例不會使用任何持續性數據,而且只有 IPersistStream 的最小實作 IPersist::GetClassID 會傳回物件的 CLSID (CLSID_SampleExplorerBar),其餘部分會傳回S_OK、S_FALSE或E_NOTIMPL。

IDeskBand

IDeskBand 介面專屬於頻帶物件。 除了它的其中一個方法,它繼承自 IDockingWindow,而 IDockingWindow 又繼承自 IOleWindow

有兩個 IOleWindow 方法:GetWindow 和 IOleWindow::ContextSensitiveHelp。 Explorer Bar 範例的 GetWindow作會傳回 Explorer Bar 的子視窗句柄,m_hwnd。 未實作上下文相關說明,因此 ContextSensitiveHelp傳回E_NOTIMPL

IDockingWindow 介面有三種方法。

ResizeBorderDW 方法不會與任何類型的頻帶物件搭配使用,而且應該一律傳回E_NOTIMPL。 ShowDW 方法會根據其參數的值來顯示或隱藏 Explorer Bar 的視窗。

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

    return S_OK;
}

CloseDW 方法會終結 Explorer Bar 的視窗。

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

    return S_OK;
}

其餘方法 GetBandInfo 是 IDeskBand 特有的 Internet Explorer 會使用它來指定 Explorer 列的識別碼和檢視模式。 Internet Explorer 也可以填入作為第三個參數傳遞之 DESKBANDINFO 結構的 dwMask 成員,以向 Explorer Bar 要求一或多個資訊。 GetBandInfo 應該儲存標識碼和檢視模式,並使用要求的數據填入 DESKBANDINFO 結構。 Explorer Bar 範例會實作 GetBandInfo ,如下列程式代碼範例所示。

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

    if (pdbi)
    {
        m_dwBandID = dwBandID;

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

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

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

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

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

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

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

        hr = S_OK;
    }

    return hr;
}

選擇性介面實作

不需要兩個介面,但實作可能很有用:IInputObjectIContextMenu。 Explorer Bar 範例會實作 IInputObject。 如需如何實 作 IContextMenu 的資訊,請參閱檔。

IInputObject

如果帶狀物件接受使用者輸入,則必須實作 IInputObject 介面。 Internet Explorer 會實作 IInputObjectSite,並使用 IInputObject 在有多個自主窗口時維持適當的使用者輸入焦點。 總管列需要實作三種方法。

Internet Explorer 會呼叫 UIActivateIO ,以通知 Explorer Bar 正在啟動或停用。 啟用時,Explorer Bar 範例會呼叫 SetFocus ,將焦點設定為其視窗。

Internet Explorer 嘗試判斷哪個視窗具有焦點時,會呼叫 HasFocusIO 如果 Explorer Bar 的視窗或其其中一個子系具有焦點, HasFocusIO 應該會傳回S_OK。 如果沒有,它應該會傳回S_FALSE。

TranslateAcceleratorIO 可讓對象處理鍵盤快捷方式。 Explorer Bar 範例不會實作此方法,因此會傳回S_FALSE。

範例列的 IInputObjectSite作如下所示。

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

    return S_OK;
}

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

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

CLSID 註冊

如同所有 COM 對象,必須註冊總管列的 CLSID。 若要讓物件使用 Internet Explorer 正常運作,也必須註冊適當的元件類別 (CATID_InfoBand)。 Explorer Bar 的相關程式代碼區段會顯示在下列程式代碼範例中。

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

    WCHAR szSubkey[MAX_PATH];
    HKEY hKey;

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

            RegCloseKey(hKey);
        }
    }

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

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

                RegCloseKey(hKey);
            }
        }
    }

    return hr;
}

範例中的頻帶對象註冊會使用一般 COM 程式。

除了 CLSID 之外,頻帶物件伺服器也必須註冊一或多個元件類別。 這實際上是垂直和水準總管列範例之間實作的主要差異。 建立元件類別管理員物件 (CLSID_StdComponentCategoriesMgr) 並使用 ICatRegister::RegisterClassImplCategories 方法來註冊頻帶對象伺服器,來處理此程式。 在此範例中,元件類別註冊是藉由將Explorer Bar範例的 CLSID 和 CATID 傳遞至 Private 函式 RegisterComCat 來處理,如下列程式代碼範例所示。

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

視窗程式

因為帶狀物件使用子視窗進行顯示,所以它必須實作視窗程序來處理 Windows 傳訊。 頻帶範例具有最少的功能,因此其視窗程式只會處理五則訊息:

程式可以輕鬆地擴充,以容納其他訊息以支援更多功能。

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

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

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

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

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

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

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

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

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

    return lResult;
}

WM_COMMAND處理程式只會傳回零。 WM_PAINT處理程式會建立簡介中總管列範例中顯示的簡單文字顯示。

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

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

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

        SIZE size;

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

                DrawThemeParentBackground(m_hwnd, hdcPaint, &rc);

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

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

                EndBufferedPaint(hBufferedPaint, TRUE);

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

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

WM_SETFOCUS和WM_KILLFOCUS處理程式會呼叫網站的 IInputObjectSite::OnFocusChangeIS 方法,通知網站焦點變更。

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

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

頻帶物件提供彈性且強大的方式,可藉由建立自定義 Explorer 列來擴充 Internet Explorer 的功能。 實作桌面帶可讓您擴充一般視窗的功能。 雖然有些 COM 程式設計是必要的,但最終會提供使用者介面的子視窗。 從該處,大部分的實作都可以使用熟悉的 Windows 程式設計技術。 雖然這裡所討論的範例只有有限的功能,但它說明頻帶物件的所有必要功能,而且可以輕易擴充,以建立唯一且功能強大的使用者介面。