Windows 7 タスク バー関連の開発 - ジャンプ リストの活用 (その 3)

みなさん、こんにちは。Windows 開発統括部の古内です。猛暑に続いて大型台風通過と厳しい天候が続いていますが、くれぐれもご自愛ください。

さて、今日は Windows 7 タスク バーのジャンプ リストに関する 3 部作の最終回、2009 年 7 月 2 日に Developing for Windows Blog に投稿された 「Developing for the Windows 7 Taskbar – Jump into Jump Lists – Part 3」 の翻訳をお届けします。
来週も Windows 7 のタスク バーについての翻訳記事を掲載予定です。どうぞお楽しみに!


Windows 7 タスク バー関連の開発 - ジャンプ リストの活用 (その 3)

これまでの投稿で、アプリケーションのジャンプ リストを作成し、Windows 7 タスク バーのジャンプ リスト エクスペリエンスをカスタマイズする方法 (前回投稿した 「Windows 7 タスク バー関連の開発 - ジャンプ リストの活用 (その 2)」 を参照のこと) を説明してきました。 また、Windows 7 がデフォルトでサポートする [最近使用した] または [よく使用する] 移動先リストが作成されるしくみと、独自のカスタム カテゴリの作成方法についても紹介しました。 今回は、ジャンプ リストの機能をさらに詳しく検証し、アプリケーションのジャンプ リストにタスクを簡単に追加できる方法について説明します。

ユーザー タスクとは、独自のタスク カテゴリを設定してカスタマイズしたタスクです。 開発者のみなさんは、表示されるタスクのタイトルと左側のアイコンを設定できるほか、さらに重要な点として、タスクのアクティブ化によって起動される "アプリケーション" を指定することができます。 ユーザー タスクは、アプリケーションで提供可能な機能へのショートカットだと考えることができます。 以前お伝えしましたが、ユーザー タスクは 「動詞」 にあたります。たとえば Windows Media Player には [前回の再生リストを再開] タスクがあり、付箋には [新しい付箋] タスクがあります。

ユーザー タスクは通常 IShellLink オブジェクトであり、指定した任意のアプリケーション (自社アプリケーション、または選択した他社のアプリケーション) を、特定のコマンド ライン パラメーターを付加して起動します。 タスクを分類することはできませんが、特別なセパレーター オブジェクトを使用して区切ることは可能です。 次の例のジャンプ リストでは、セパレーターを使用して、3 つのタスクを 2 つからなるグループと 1 つからなるグループに分けています。

イメージ

では、ジャンプ リストにタスクを追加するには、何が必要となるでしょうか。 実は、特に必要なものはありません。 基本的には、既にお馴染みとなった ICustomDestinationList (ICustomDestinationList::AddUserTasks(IObjectArray) メソッド) インターフェイスで AddUserTasks 関数を 1 回呼び出すだけです。 対象のコードを見てみると、hr = pcdl->AddUserTasks(poa); の 1 行しかありません。ただし、いつものように、この poa (IObjectArray) とパラメーターを作成し、構築して、関連する情報を入力する必要があります。 以降では、そのプロセスを紹介します。

まず、IShellLink のコレクションを作成します。 このコレクションは後ほど、必要な IObjectArray パラメーターに変換されます。 次に、このプロセスの冒頭のコードを示します。

 IObjectCollection *poc;
HRESULT hr = CoCreateInstance(
D_EnumerableObjectCollection, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&poc));
if (SUCCEEDED(hr))
{
    IShellLink * psl;
    hr = _CreateShellLink(L"/Task1", L"Task 1", &psl);
    if (SUCCEEDED(hr))
    {
        hr = poc->AddObject(psl);
        psl->Release();
    }
}

ご覧のように、(今回も) COM と、CoCreate および IObjectCollection (poc) を使用しています。 次に、CreateShellLink というヘルパー関数を呼び出し、3 つのパラメーターを受け取ります。

  • 1 つ目のパラメーターは、タスクに対するコマンド ライン引数です。
  • 2 つ目のパラメーターは、表示されるタイトルです。
  • 最後のパラメーターは、IShellLink へのポインターです。

関連する情報に基づいたオブジェクトが保存されます。

最後に、最近作成された IShellLink をオブジェクト コレクションに追加します。 起動予定の実行可能ファイルへのパスを提供するパラメーターが、どこにあるのか疑問に思われた方もいるかもしれません。 これはもっともな疑問です。 簡略化するために、ここではその情報を次のコード スニペットで示すようにハードコーディングしました。

 if (SUCCEEDED(hr))
{
    hr = _CreateShellLink2(
            L"C:\\Users\\<my user>\\Documents\\new text file.txt", 
            L"NotePad", 
            &psl);

    if (SUCCEEDED(hr))
    {
        hr = poc->AddObject(psl);
        psl->Release();
    }
}

上のコードでは、ハードコーディングした _CreateShellLink2 関数を呼び出しています。 この関数は、パラメーターの 1 つとしてテキスト ファイルへのパスを受け取り、メモ帳 (Notepad) を起動しています。

次に、CreateShellLink2 関数のコードを示します。

 HRESULT _CreateShellLink2(
            PCWSTR pszArguments, PCWSTR pszTitle, 
            IShellLink **ppsl)
{
    IShellLink *psl;
    HRESULT hr = CoCreateInstance(
                    CLSID_ShellLink, 
                    NULL, 
                    CLSCTX_INPROC_SERVER, 
                    IID_PPV_ARGS(&psl));
    if (SUCCEEDED(hr))
    {
        hr = psl->SetPath(c_szNotePadExecPath);
            if (SUCCEEDED(hr))
            {
                hr = psl->SetArguments(pszArguments);
                if (SUCCEEDED(hr))
                {
                    // IShellLink インスタンスとして提供されたジャンプ リスト項目には 
                    // タイトル プロパティが必要です。 この値は、ジャンプ リストでの 
                    // 表示名として使用されます。
                    IPropertyStore *pps;
                    hr = psl->QueryInterface(IID_PPV_ARGS(&pps));
                    if (SUCCEEDED(hr))
                    {
                        PROPVARIANT propvar;
                        hr = InitPropVariantFromString(pszTitle, &propvar);
                        if (SUCCEEDED(hr))
                        {
                            hr = pps->SetValue(PKEY_Title, propvar);
                            if (SUCCEEDED(hr))
                            {
                                hr = pps->Commit();
                                if (SUCCEEDED(hr))
                                {
                                    hr = psl->QueryInterface
                                            (IID_PPV_ARGS(ppsl));
                                }
                            }
                            PropVariantClear(&propvar);
                        }
                        pps->Release();
                    }
                }
            }
        else
        {
            hr = HRESULT_FROM_WIN32(GetLastError());
        }
        psl->Release();
    }
    return hr;
}

ここでも最初に、COM および CoCreate を使用して IShellLink COM オブジェクトを作成する必要があります。 SDK を簡単に見ただけでも、IShellLink オブジェクトには多くの関数があることがわかります。 このコードでは、次の関数のみを使用します。

  • GetPath: 実行可能ファイルへのパスとして、シェル リンク オブジェクトのパスとファイル名を取得
  • GetShowCmd: 実行可能ファイルの名前として、シェル リンク オブジェクトの show コマンドの結果を取得
  • SetArguments: シェル リンク オブジェクトのコマンド ライン引数を設定
  • SetDescription: シェル リンク オブジェクトの説明を設定。説明には、任意のアプリケーション定義文字列を使用可能
  • SetIconLocation: シェル リンク オブジェクトのアイコンの場所 (パスとインデックス) を設定 SetPath: シェル リンク オブジェクトのパスとファイル名を設定
  • SetWorkingDirectory: シェル リンク オブジェクトの作業ディレクトリの名前を設定

ご覧のように、各パラメーターについて、適切なメソッドの値の取得と設定が必要になります。 その他のパラメーターについて詳しく確認したい場合は、SDK (IShellLink) を参照してください。

上記の例では、メモ帳へのパス (Windows 7 の既定のインストールでは、c:\windows\notepad.exe) を設定しています。 さらに、私の個人用ドキュメント フォルダー (C:\Users\<my user>\Documents\new text file.txt) 内にあるテキスト ファイルを参照する、ハードコーディングされた (あまりお勧めしません) コマンド ライン引数を渡しています。残りは、ジャンプ リスト項目に必要となるタイトル プロパティを設定するコードです。

先ほどの画面キャプチャで示した 3 つのショートカットすべてを追加するために、さらに数回 CreateShellLink2CreateShellLink を呼び出します。

では、セパレーターを追加しましょう。

タスク リストにセパレーターを追加するには、次のコード スニペットで示すように、IShellLink を作成し、COM のバリアント型プロパティを使用するように PKEY_AppUserModel_IsDestListSeparator プロパティを設定する必要があります。

 // ジャンプ リストのタスク カテゴリはセパレーター項目をサポートしています。 
// セパレーターは、IShellLink インスタンスの PKEY_AppUserModel_IsDestListSeparator 
// プロパティを TRUE に設定するだけで追加できます。 
// このプロパティを設定すると、その他の値はすべて無視されます。
HRESULT _CreateSeparatorLink(IShellLink **ppsl)
{
    IPropertyStore *pps;
    HRESULT hr = CoCreateInstance(
                    CLSID_ShellLink, 
                    NULL, 
                    CLSCTX_INPROC_SERVER, 
                    IID_PPV_ARGS(&pps));
    if (SUCCEEDED(hr))
    {
        PROPVARIANT propvar;
        hr = InitPropVariantFromBoolean(TRUE, &propvar);
        if (SUCCEEDED(hr))
        {
            hr = pps->SetValue(PKEY_AppUserModel_IsDestListSeparator, propvar);
            if (SUCCEEDED(hr))
            {
                hr = pps->Commit();
                if (SUCCEEDED(hr))
                {
                    hr = pps->QueryInterface(IID_PPV_ARGS(ppsl));
                }
            }
            PropVariantClear(&propvar);
        }
        pps->Release();
    }
    return hr;
}

上記では、CoCreate を使用して IShellLink オブジェクトを作成しています。 続いて、PROPVARIANT (propvar) を TRUE に設定し、IShellLink オブジェクトの PKEY_AppUserModel_IsDestListSeparator プロパティを TRUE に設定します。 これにより、OS に対して、このオブジェクトが通常の IShellLink ではなく、セパレーターとして表示すべき IShellLink であることが伝達されます。

上記は長いコードでしたが、 次は .NET を使用した短いバージョンをご紹介します。 これには、Windows API Code Pack for Microsoft .NET Framework を使用します。

.NET の特長により、必要な "COM コード ビハインド" のほとんどは抽象化できます。 Microsoft.WindowsAPICodePack.Shell.Taskbar 名前空間には JumpListLink オブジェクトが含まれ、ShellLink オブジェクトの拡張と IJumpListTasks の実装が行われます。

次のコード スニペットで示すとおり、JumpList クラスは IJumpListTasksUserTasks コレクションを含み、新しい JumpListLink オブジェクトを簡単に追加できます。

 // Windows システム フォルダーへのパス
string systemFolder = 
        Environment.GetFolderPath(Environment.SpecialFolder.System);

jumpList.UserTasks.Add(new JumpListLink
{
    Title = "Open Notepad",
    Path = Path.Combine(systemFolder, "notepad.exe"),
    IconReference = new IconReference(
(systemFolder, "notepad.exe"), 0)
});

C# 3.0 構文を使用して新しい JumpListLink オブジェクトを初期化し、それを UserTasks コレクションに追加します。 ご覧のように、マネージ コードの JumpListLink のプロパティは、(当然のことながら) ネイティブ コードの場合ときわめて似通っています。 上のコードではさらに、メモ帳へのショートカットのアイコンを追加していますが、コマンド ライン パラメーターは指定していません。

セパレーターも追加してみましょう。 この作業はとても簡単です。UserTasks コレクションに JumpListSeperator オブジェクトを追加するだけです。

 jumpList.UserTasks.Add(new JumpListSeparator());

前の投稿で説明しましたが、Windows Code Pack API のタスク バーを調整する場合も、通常どおり、変更を確定するために "リフレッシュ" 関数を呼び出す必要があります。

 Taskbar.JumpList.RefreshTaskbarList();

最新の情報に更新すると、ジャンプ リストは次のようになります。

イメージ

Windows 7 SDK からネイティブ コードの例をコンパイルしました。 ご興味のある方は、こちらからダウンロードしてください。

Windows API Code Pack をダウンロードすれば、ここで使用したサンプルのマネージ コードもご覧いただけます。

今回でジャンプ リストに関する説明は終わりです。 次回は、タスク バーのアイコンのオーバーレイについて紹介します。