カスタム エクスプローラー バー、ツール バンド、デスク バンドの作成

エクスプローラー バーは、ブラウザー ウィンドウに隣接する表示領域を提供するために、Microsoft Internet エクスプローラー 4.0 で導入されました。 これは基本的に Windows インターネット エクスプローラー ウィンドウ内の子ウィンドウであり、情報の表示とユーザーとの対話に使用できます。 エクスプローラーバーは、ブラウザー ウィンドウの左側に垂直ウィンドウとして最も一般的に表示されます。 ただし、エクスプローラー バーは、ブラウザー ウィンドウの下に水平方向に表示することもできます。

縦横のエクスプローラーバーを示すスクリーンショット。

エクスプローラーバーには幅広い用途があります。 ユーザーは、[表示] メニューの [エクスプローラー バー] サブメニューから選択したり、ツール バー ボタンをクリックしたりするなど、さまざまな方法で表示するオプションを選択できます。 インターネット エクスプローラーには、お気に入りや検索など、いくつかの標準的なエクスプローラー バーが用意されています。

インターネット エクスプローラーをカスタマイズする方法の 1 つは、カスタム エクスプローラー バーを追加することです。 実装して登録すると、[表示] メニューの [エクスプローラー バー] サブメニューに追加されます。 ユーザーが選択すると、エクスプローラー バーの表示領域を使用して、通常のウィンドウとほぼ同じ方法で情報を表示し、ユーザー入力を取得できます。

エクスプローラー バーのスクリーン ショット

カスタム エクスプローラー Bar を作成するには、バンド オブジェクトを実装して登録する必要があります。 バンド オブジェクトは、シェルのバージョン 4.71 で導入され、通常のウィンドウと同様の機能を提供します。 ただし、これらはコンポーネント オブジェクト モデル (COM) オブジェクトであり、インターネット エクスプローラーまたはシェルに含まれているため、実装方法が多少異なります。 単純なバンド オブジェクトを使用して、最初の図に表示されるサンプル エクスプローラー バーを作成しました。 垂直エクスプローラー Bar サンプルの実装については、後のセクションで詳しく説明します。

ツール バンド

ツール バンドは、Windows ラジオ ツール バー機能をサポートするために Microsoft Internet エクスプローラー 5 で導入されたバンド オブジェクトです。 インターネット エクスプローラー ツールバーは、実際には複数のツールバー コントロールを含む Rebar コントロールです。 ツール バンドを作成すると、その Rebar コントロールにバンドを追加できます。 ただし、エクスプローラーバーと同様に、ツール バンドは汎用ウィンドウです。

ツール バンドのスクリーン ショット

ユーザーは、[表示] メニューの [ツール バー] サブメニューから選択するか、ツール バー領域を右クリックして表示されるショートカット メニューからツール バーを表示します。

デスク バンド

バンド オブジェクトを使用して 、デスク バンドを作成することもできます。 基本的な実装はエクスプローラーバーに似ていますが、デスクバンドはインターネットエクスプローラーとは無関係です。 デスク バンドは、基本的にデスクトップにドッキング可能なウィンドウを作成する方法です。 ユーザーがタスク バーを右クリックし、[ ツール バー ] サブメニューからタスク バーを選択して選択します。

サンプルのデスク バンドを示すスクリーンショット。

最初は、デスク バンドがタスク バーにドッキングされます。

タスク バーにドッキングされているデスク バンドを示すスクリーンショット。

その後、デスクトップにデスク バンドをドラッグすると、通常のウィンドウとして表示されます。

デスク バンドのスクリーン ショット

Band オブジェクトの実装

次のトピックについて説明します。

Band オブジェクトの基本

通常のウィンドウと同様に使用できますが、バンド オブジェクトはコンテナー内に存在する COM オブジェクトです。 エクスプローラーバーはインターネットエクスプローラーに含まれており、デスクバンドはシェルに含まれています。 これらはさまざまな関数を提供しますが、基本的な実装は非常に似ています。 主な違いは、バンド オブジェクトの登録方法です。これにより、オブジェクトとそのコンテナーの種類が制御されます。 このセクションでは、すべてのバンド オブジェクトに共通する実装のこれらの側面について説明します。 実装の詳細については、「カスタム エクスプローラー バーの簡単な例」を参照してください。

IUnknownIClassFactory に加えて、すべてのバンド オブジェクトで次のインターフェイスを実装する必要があります。

クラス識別子 (CLSID) の登録に加えて、エクスプローラー Bar オブジェクトとデスク バンド オブジェクトも適切なコンポーネント カテゴリに登録する必要があります。 コンポーネント カテゴリを登録すると、オブジェクトの種類とそのコンテナーが決まります。 ツール バンドは別の登録手順を使用し、カテゴリ識別子 (CATID) を持っていません。 必要な 3 つのバンド オブジェクトの CATID は次のとおりです。

バンドの種類 コンポーネント カテゴリ
垂直エクスプローラーバー CATID_InfoBand
横エクスプローラーバー CATID_CommBand
デスク バンド CATID_DeskBand

 

バンド オブジェクトを 登録 する方法の詳細については、「バンド登録」を参照してください。

バンド オブジェクトがユーザー入力を受け入れる場合は、 IInputObject も実装する必要があります。 エクスプローラーバーまたはデスク バンドのショートカット メニューに項目を追加するには、バンド オブジェクトが IContextMenu をエクスポートする必要があります。 ツール バンドでは、ショートカット メニューはサポートされていません。

バンド オブジェクトは子ウィンドウを実装するため、Windows メッセージングを処理するウィンドウ プロシージャも実装する必要があります。

Band オブジェクトは、コンテナーの IOleCommandTarget インターフェイスを使用して、コンテナーにコマンドを送信できます。 インターフェイス ポインターを取得するには、コンテナーの IInputObjectSite::QueryInterface メソッドを呼び出し、IID_IOleCommandTargetを要求します。 次に、 IOleCommandTarget::Exec を使用してコンテナーにコマンドを送信します。 コマンド グループがCGID_DeskBand。 バンド オブジェクトの IDeskBand::GetBandInfo メソッドが呼び出されると、コンテナーは dwBandID パラメーターを使用して、バンド オブジェクトに 3 つのコマンドに使用される識別子を割り当てます。 4 つの IOleCommandTarget::Exec コマンド ID がサポートされています。

  • DBID_BANDINFOCHANGED

    バンドの情報が変更されました。 pvaIn パラメーターを、IDeskBand::GetBandInfo の最新の呼び出しで受信したバンド識別子に設定します。 コンテナーは、バンド オブジェクトの IDeskBand::GetBandInfo メソッドを呼び出して、更新された情報を要求します。

  • DBID_MAXIMIZEBAND

    バンドを最大化します。 pvaIn パラメーターを、IDeskBand::GetBandInfo の最新の呼び出しで受信したバンド識別子に設定します。

  • DBID_SHOWONLY

    コンテナー内の他のバンドをオンまたはオフにします。 次のいずれかの値を使用して、 pvaIn パラメーターを VT_UNKNOWN 型に設定します。

    [説明]
    パンク バンド オブジェクトの IUnknown インターフェイスへのポインター。 その他のデスク バンドはすべて非表示になります。
    0 すべてのデスク バンドを非表示にします。
    1 すべてのデスク バンドを表示します。

     

  • DBID_PUSHCHEVRON

    バージョン 5。 シェブロン メニューを表示します。 コンテナーは RB_PUSHCHEVRON メッセージを送信し、バンド オブジェクトはシェブロン メニューの表示を求める RBN_CHEVRONPUSHED 通知を受け取ります。 IOleCommandTarget::Exec メソッドの nCmdExecOpt パラメーターを、IDeskBand::GetBandInfo の最新の呼び出しで受信したバンド識別子に設定します。 IOleCommandTarget::Exec メソッドのpvaInパラメーターを、アプリケーション定義値を持つVT_I4型に設定します。 RBN_CHEVRONPUSHED通知の lAppValue 値としてバンド オブジェクトに戻ります。

バンド登録

バンド オブジェクトは、アパートメント スレッド処理をサポートする OLE インプロセス サーバーとして登録する必要があります。 サーバーの既定値はメニュー テキスト文字列です。 エクスプローラー バーの場合は、[インターネット エクスプローラー 表示] メニューの [エクスプローラー バー] サブメニューに表示されます。 ツール バンドの場合は、[インターネット] エクスプローラー [表示] メニューの [ツール バー] サブメニューに表示されます。 デスク バンドの場合は、タスク バーのショートカット メニューの [ツール バー] サブメニューに表示されます。 メニュー リソースと同様に、アンパサンド (&) を文字の前に配置すると、下線が引き、キーボード ショートカットが有効になります。 たとえば、最初の図に示されている垂直エクスプローラーバーのメニュー文字列は、"Sample &Vertical エクスプローラー Bar" です。

最初に、インターネット エクスプローラーは、コンポーネント カテゴリを使用してレジストリから登録済みのエクスプローラー Bar オブジェクトの列挙体を取得します。 パフォーマンスを向上させるために、この列挙をキャッシュし、その後追加されたエクスプローラーバーを見落とします。 Windows インターネット エクスプローラーでキャッシュを再構築し、新しい エクスプローラー バーを認識するように強制するには、新しい エクスプローラー バーの登録中に次のレジストリ キーを削除します。

Hkey_current_user\ソフトウェア\マイクロソフト\Windows\CurrentVersion\\エクスプローラー Discardable\PostSetup\コンポーネント カテゴリ\{00021493-0000-0000-C000-000000000046}\Enum

Hkey_current_user\ソフトウェア\マイクロソフト\Windows\CurrentVersion\\エクスプローラー Discardable\PostSetup\コンポーネント カテゴリ\{00021494-0000-0000-C000-000000000046}\Enum

Note

エクスプローラー バー キャッシュはユーザーごとに作成されるため、セットアップ アプリケーションでは、すべてのユーザー レジストリ ハイブを列挙するか、ユーザーが最初にログオンしたときに実行するユーザーごとのスタブを追加する必要があります。

 

一般に、バンド オブジェクトの基本的なレジストリ エントリは次のように表示されます。

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

ツール バンドには、オブジェクトの CLSID もインターネット エクスプローラーに登録されている必要があります。 これを行うには、次に示すように、ツール バンド オブジェクトHKEY_LOCAL_MACHINE\ CLSID GUID を使用して、HKEY_LOCAL_MACHINESoftware\Microsoft\Internet エクスプローラー\Toolbar という名前の値を割り当てます。 そのデータ値は無視されるため、値の型は重要ではありません。

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

レジストリに追加できる省略可能な値がいくつかあります。 たとえば、エクスプローラー バーを使用して HTML を表示する場合は、次の値が必要です。表示される値は例ではなく、実際に使用する必要がある値です。

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

上記の値と組み合わせて使用します。エクスプローラー バーを使用して HTML を表示する場合は、次の省略可能な値も必要です。 この値は、エクスプローラー バーの HTML コンテンツを含むファイルの場所に設定する必要があります。

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

もう 1 つの省略可能な値は、エクスプローラーバーの既定の幅または高さを定義します。これは、それぞれ垂直か横かによって異なります。

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

BarSize 値は、バーの幅または高さに設定する必要があります。 値には 8 バイトが必要であり、レジストリにバイナリ値として配置されます。 最初の 4 バイトは、左端のバイトから始まるピクセル単位のサイズを 16 進数形式で指定します。 最後の 4 バイトは予約済みであり、0 に設定する必要があります。

たとえば、既定の幅が 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. エクスプローラー バーの表示領域に合わせてサイズ設定された、インターネット エクスプローラーの子ウィンドウを作成します。
  6. 子ウィンドウを使用して情報を表示し、ユーザーと対話します。

エクスプローラー Bar サンプルで使用される非常に単純な実装は、適切なコンポーネント カテゴリに登録するだけで、実際には エクスプローラー Bar の種類またはデスク バンドに使用できます。 より高度な実装は、オブジェクトの種類の表示領域とコンテナーごとにカスタマイズする必要があります。 ただし、このカスタマイズの多くは、サンプル コードを取得し、使い慣れた Windows プログラミング手法を子ウィンドウに適用して拡張することで実現できます。 たとえば、ユーザー操作用のコントロールや、よりリッチなディスプレイ用のグラフィックスを追加できます。

DLL 関数

3 つのオブジェクトはすべて 1 つの DLL にパッケージ化され、次の関数が公開されます。

最初の 3 つの関数は標準実装であり、ここでは説明しません。 Class Factory の実装も標準です。

必要なインターフェイスの実装

垂直エクスプローラー Bar サンプルでは、CExplorerBar クラスの一部として、IUnknownIObjectWithSiteIPersistStreamIDeskBand の 4 つの必須インターフェイスを実装しています。 コンストラクター、デストラクター、および IUnknown の実装は簡単であり、ここでは説明しません。 詳細については、サンプル コードを参照してください。

次のインターフェイスについて詳しく説明します。

IObjectWithSite

ユーザーが エクスプローラー バーを選択すると、コンテナーは対応するバンド オブジェクトの IObjectWithSite::SetSite メソッドを呼び出します。 punkSite パラメーターは、サイトの IUnknown ポインターに設定されます。

一般に、 SetSite 実装では次の手順を実行する必要があります。

  1. 現在保持されているサイト ポインターを解放します。
  2. SetSite に渡されたポインターが NULL に設定されている場合、バンドは削除されます。 SetSite はS_OKを返すことができます。
  3. SetSite に渡されるポインターが NULL 以外の場合は、新しいサイトが設定されます。 SetSite では、次の操作を行う必要があります。
    1. サイトで QueryInterface を呼び出して、 その IOleWindow インターフェイスを取得します。
    2. IOleWindow::GetWindow を呼び出して、親ウィンドウのハンドルを取得します。 後で使用するためにハンドルを保存します。 不要になった場合は、 IOleWindow をリリースします。
    3. 前の手順で取得したウィンドウの子として、バンド オブジェクトのウィンドウを作成します。 表示されるウィンドウとして作成しないでください。
    4. バンド オブジェクトが IInputObject を実装する場合は、その IInputObjectSite インターフェイスのサイトで QueryInterface を呼び出します。 後で使用するために、このインターフェイスへのポインターを格納します。
    5. すべての手順が成功した場合は、S_OKを返します。 そうでない場合は、失敗した内容を示す OLE 定義のエラー コードを返します。

エクスプローラー バーのサンプルでは、次の方法で SetSite を実装します。 次のコード m_pSite は、 IInputObjectSite ポインターを保持し、親ウィンドウのハンドル を保持m_hwndParent プライベート メンバー変数です。 このサンプルでは、ウィンドウの作成も処理されます。 ウィンドウが存在しない場合、このメソッドは SetSite によって取得された親ウィンドウの適切なサイズの子として、エクスプローラー バーのウィンドウを作成します。 子ウィンドウのハンドルは 、m_hwndに格納されます。

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

    m_hwndParent = NULL;

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

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

                RegisterClassW(&wc);

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

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

            pow->Release();
        }

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

    return hr;
}

サンプルの GetSite 実装は、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

インターネット エクスプローラーは、エクスプローラー バーの IPersistStream インターフェイスを呼び出して、エクスプローラー バーが永続的なデータを読み込んだり保存したりできるようにします。 永続的なデータがない場合でも、メソッドは成功コードを返す必要があります。 IPersistStream インターフェイスは IPersist から継承されるため、5 つのメソッドを実装する必要があります。

エクスプローラー バーのサンプルでは、永続的なデータは使用されず、IPersistStream の実装は最小限です。 IPersist::GetClassID はオブジェクトの CLSID (CLSID_SampleExplorerBar) を返し、剰余は S_OK、S_FALSE、またはE_NOTIMPLを返します。

IDeskBand

IDeskBand インターフェイスはバンド オブジェクトに固有です。 その 1 つのメソッドに加えて、 IDockingWindow から継承され、 IOleWindow から継承されます。

IOleWindow メソッドには、GetWindowIOleWindow::ContextSensitiveHelp の 2 つがあります。 エクスプローラー Bar サンプルの GetWindow の実装では、エクスプローラー バーの子ウィンドウ ハンドル m_hwndが返されます。 状況依存ヘルプは実装されていないため、 ContextSensitiveHelpE_NOTIMPLを返します。

IDockingWindow インターフェイスには、3 つのメソッドがあります。

ResizeBorderDW メソッドは、どの種類のバンド オブジェクトでも使用されず、常にE_NOTIMPLを返す必要があります。 ShowDW メソッドは、パラメーターの値に応じて、エクスプローラー バーのウィンドウを表示または非表示にします。

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

    return S_OK;
}

CloseDW メソッドは、エクスプローラー バーのウィンドウを破棄します。

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

    return S_OK;
}

残りのメソッド GetBandInfo は、 IDeskBand に固有です。 インターネット エクスプローラーでは、エクスプローラー バーの識別子と表示モードを指定するために使用されます。 インターネット エクスプローラーは、3 番目のパラメーターとして渡される DESKBANDINFO 構造体の dwMask メンバーを入力することによって、エクスプローラー バーに 1 つ以上の情報を要求することもできます。 GetBandInfo は識別子と表示モードを格納し、 DESKBANDINFO 構造体に要求されたデータを入力する必要があります。 エクスプローラー バーのサンプルでは、次のコード例に示すように 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;
}

省略可能なインターフェイスの実装

必須ではないインターフェイスが 2 つありますが、 IInputObjectIContextMenu を実装すると便利な場合があります。 エクスプローラー バーのサンプルでは、IInputObject が実装されていますIContextMenu を実装する方法については、ドキュメントを参照してください。

IInputObject

バンド オブジェクトがユーザー入力を受け入れる場合は、 IInputObject インターフェイスを実装する必要があります。 インターネット エクスプローラーは IInputObjectSite を実装し、IInputObject を使用して、複数のウィンドウが含まれている場合に適切なユーザー入力フォーカスを維持します。 エクスプローラー バーで実装する必要がある 3 つのメソッドがあります。

インターネット エクスプローラーは UIActivateIO を呼び出して、アクティブ化または非アクティブ化されていることをエクスプローラー バーに通知します。 アクティブ化すると、エクスプローラー Bar サンプルは SetFocus を呼び出して、フォーカスをウィンドウに設定します。

インターネット エクスプローラーは、フォーカスがあるウィンドウを特定しようとしたときに HasFocusIO を呼び出します。 エクスプローラー バーのウィンドウまたはその子孫の 1 つにフォーカスがある場合、HasFocusIO はS_OKを返す必要があります。 そうでない場合は、S_FALSEを返す必要があります。

TranslateAcceleratorIO を使用すると、オブジェクトでキーボード アクセラレータを処理できます。 エクスプローラー 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 を登録する必要があります。 オブジェクトがインターネット エクスプローラーで正しく機能するには、適切なコンポーネント カテゴリ (CATID_InfoBand) にも登録する必要があります。 エクスプローラー バーの関連するコード セクションを次のコード例に示します。

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

    WCHAR szSubkey[MAX_PATH];
    HKEY hKey;

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

            RegCloseKey(hKey);
        }
    }

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

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

                RegCloseKey(hKey);
            }
        }
    }

    return hr;
}

サンプル内のバンド オブジェクトの登録では、通常の COM プロシージャを使用します。

CLSID に加えて、バンド オブジェクト サーバーも 1 つ以上のコンポーネント カテゴリに登録する必要があります。 これは、実際には、垂直と水平方向のエクスプローラー Bar サンプルの実装におけるメインの違いです。 このプロセスは、コンポーネント カテゴリ マネージャー オブジェクト (CLSID_StdComponentCategoriesMgr) を作成し、 ICatRegister::RegisterClassImplCategories メソッドを使用してバンド オブジェクト サーバーを登録することによって処理されます。 この例では、次のコード例に示すように、コンポーネント カテゴリの登録は、エクスプローラー Bar サンプルの CLSID と CATID をプライベート関数 RegisterComCat に渡すことによって処理されます。

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

ウィンドウ プロシージャ

バンド オブジェクトは、その表示に子ウィンドウを使用するため、Windows メッセージングを処理するウィンドウ プロシージャを実装する必要があります。 バンド サンプルには最小限の機能があるため、ウィンドウ プロシージャは 5 つのメッセージのみを処理します。

この手順は、追加のメッセージに対応するように簡単に拡張して、より多くの機能をサポートできます。

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 ハンドラーは、単に 0 を返します。 WM_PAINT ハンドラーは、概要のエクスプローラー バーの例に示されている単純なテキスト表示を作成します。

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

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

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

        SIZE size;

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

                DrawThemeParentBackground(m_hwnd, hdcPaint, &rc);

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

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

                EndBufferedPaint(hBufferedPaint, TRUE);

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

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

WM_SETFOCUSハンドラーとWM_KILLFOCUS ハンドラーは、サイトの IInputObjectSite::OnFocusChangeIS メソッドを呼び出すことによって、フォーカスの変更をサイトに通知します。

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

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

バンド オブジェクトは、カスタム エクスプローラー バーを作成することで、インターネット エクスプローラーの機能を拡張する柔軟で強力な方法を提供します。 デスク バンドを実装すると、通常のウィンドウの機能を拡張できます。 一部の COM プログラミングは必要ですが、最終的にはユーザー インターフェイスの子ウィンドウを提供するのに役立ちます。 そこから、実装の大部分で使い慣れた Windows プログラミング手法を使用できます。 ここで説明する例は機能が限られていますが、バンド オブジェクトに必要なすべての機能を示しており、一意で強力なユーザー インターフェイスを作成するために簡単に拡張できます。