2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ジャンプリストの仕組み

Last updated at Posted at 2025-09-06

まえがき

筆者は、数年前から WinUI/C# オープンソースプロジェクトである Files App の開発に参加しており、この記事は Files のジャンプリストの再設計を始めるための概念実証として開発したアプリ(後述)をもとに執筆しました。内容に不備がありましたらご容赦ください。

【注意】本記事では未公開の API や挙動を含み、将来の Windows アップデートで変更や削除される可能性があります。この記事はあくまで研究目的であり、参考にして発生した不具合や損害について筆者は一切の責任を負いません。
【対応環境】7601、9600、10240、26100.6584

導入

ジャンプリスト(英:Jump List)は、Windows 7 以降の Windows のタスクバーに実装された右クリックメニュー UI です。Microsoft は SDK にジャンプリストに関する完全な API サーフェースを公開していないため、その内部設計は複雑です。しかしながら、実装を解析することで、ある程度の全体像を捉えることができます。

アーキテクチャ

ジャンプリストの UI は、自動デスティネーション(英:Automatic Destinations)とカスタムデスティネーション(英:Custom Destinations)、タスク(英:Tasks)の 3 つの異なる種類のデータを合成して表示されています。システムが自動デスティネーションを管理し、アプリケーションの開発者がカスタムデスティネーションとタスクを管理します。

ジャンプリストの保存先

Windows 7 以降、プロセスやウィンドウを特定のアプリケーションに紐づけ、そのアプリケーションのタスクバーアイコンにグループ化するため、AppUserModelID(AUMID)1 が導入されました。ジャンプリストを管理するのにも AUMID が使われ、AUMID の CRC64 ハッシュが各アプリケーションのジャンプリストのバイナリファイルのファイル名です。

例:Microsoft.Windows.ExplorerF01B4D95CF55D32A

AUMID が明示的に設定されていない場合、

  • .exe であれば、シェル名前空間パスに正規化された .exe パス
  • MSIX でパッケージ化されていれば、(パッケージファミリー名)!(エントリーポイント名)

が暗黙的に AUMID となります。詳しくは、PowerShell で Get-StartApps を実行してみてください。

自動デスティネーション
%AppData%\Microsoft\Windows\Recent\AutomaticDestinations\<CRC64 ハッシュ>.automaticDestinations-ms

カスタムデスティネーション / タスク
%AppData%\Microsoft\Windows\Recent\CustomDestinations\<CRC64 ハッシュ>.customDestinations-ms

それぞれのバイナリフォーマットについては、Joachim Metz 氏による「Jump lists format」または「Jump lists in depth: Understand the format to better understand what your tools are (or aren't) doing2」をご覧ください。Windows には実際にこれらのバイナリをパースする内部クラス(windows.storage.dll!CAutoDestListParser) が存在します。

CRC ハッシュの算出

以下がそのハッシュに使われている非標準 CRC64 符号多項式です3

1001 0010 1100 0110 0100 0010 0110 0101 1101 0011 0010 0001 0011 1001 1010 0100

符号理論において、以下のように CRC 計算を 1 ビットずつの多項式として定義し除算しますが、これでは計算効率が悪いため、実際には 8 ビット単位の処理を行いルックアップテーブルを生成してから、ハッシュ値を求めることによって効率化するのが一般的です4

C(x)=\sum_{i=0}^{n-1} w_{i} \cdot x^i \quad (w_i \in \{0, 1\})
const ulong cp = 0x92C64265D32139A4; // 64 ビット CRC 符号多項式
static ulong table[256] = [];

static void GenerateLookupTable()
{
    for (uint i = 0U; i < 256; i++)
    {
    	ulong entry = (ulong)i;
    
    	for (uint j = 0U; j < 8U; j++)
            entry = (entry & 1) is 1 ? entry >> 1 ^ cp : entry >> 1;
    
    	table[i] = entry;
    }
}

static void GenerateCRCHash(string appID = "Microsoft.Windows.Explorer")
{
    var hash = 0xFFFFFFFFFFFFFFFF; // 初期値
    byte[] buffer = Encoding.Unicode.GetBytes(appID.ToUpper());
    
    for (uint i = 0; i < buffer.Length; i++)
    	unchecked { hash = hash >> 8 ^ table[(hash ^ buffer[i]) & 0xFF]; }

    Console.WriteLine($"hash: {hash:X}"); // hash: F01B4D95CF55D32A
}

自動デスティネーション

自動デスティネーションは、アプリケーションを通して使用したことのあるアイテムのコレクションです(以下、MRU と略します)。自動デスティネーションの API は「ピン留め」と「最近アクセスしたアイテム」、「頻繫にアクセスするアイテム」の 3 つのコレクションに解釈し、ジャンプリストの UI に提供します。

フォルダが MRU に追加される際の最も一般的なシナリオは IFileDialog 系の API を使用した場合です。FOS_DONTADDTORECENT オプションを指定しない限り、SHAddToRecentDocs 相当の API5 が内部で呼び出されます。

カスタムデスティネーション

自動デスティネーションの API から取得できるコレクションは、「ピン留め」や「最近アクセスしたアイテム」、「頻繁にアクセスするアイテム」ですが、それ以外にアプリケーションが独自に管理するアイテムコレクションを追加したい場合、カスタムデスティネーションを使用します。

タスク

タスクは、ユーザーが頻繁に行うであろうアクションを構成したい場合に使用します。例えば、Windows Terminal で コマンドプロンプトを開くコマンド wt.exe -open "cmd.exe" などです。

API アーキテクチャ

IAutomaticDestinationsList COM インターフェース

  • ピン留めをする/ピン解除を外す
  • 「ピン留め」リスト、「最近アクセスしたアイテム」リスト、「頻繫にアクセスするアイテム」リストの列挙
  • アイテムを「最近アクセスしたアイテム」に追加する
  • リストを削除する
  • アイテムを削除する

等の機能を提供します6

// {F0AE1542-F497-484B-A175-A20DB09144BA} (windows.storage.dll!CAutomaticDestinationList)
DEFINE_GUID(CLSID_AutomaticDestinationList, 0xf0ae1542,0xf497,0x484b,0xa175,0xa2,0x0d,0xb0,0x91,0x44,0xba);
// {BC10DCE3-62F2-4BC6-AF37-DB46ED7873C4}
DEFINE_GUID(IID_IAutomaticDestinationList, 0xbc10dce3,0x62f2,0x4bc6,0xaf37,0xdb,0x46,0xed,0x78,0x73,0xc4);
MIDL_INTERFACE("BC10DCE3-62F2-4BC6-AF37-DB46ED7873C4")
IAutomaticDestinationList : public IUnknown
{
public:
    virtual STDMETHOD Initialize(PCWSTR, PCWSTR, PCWSTR);
    virtual STDMETHOD HasList(BOOL*);
    virtual STDMETHOD GetList(DESTLISTTYPE, int, GETDESTLISTFLAGS, REFIID, void**);
    virtual STDMETHOD AddUsagePoint(IUnknown*);
    virtual STDMETHOD PinItem(IUnknown*, int);
    virtual STDMETHOD IsPinned(IUnknown*, int*); // NOTE: GetPinIndex is more appropriate name
    virtual STDMETHOD RemoveDestination(IUnknown*);
    virtual STDMETHOD SetUsageData(IUnknown*, float*, long*);
    virtual STDMETHOD GetUsageData(IUnknown*, float*, long*);
    virtual STDMETHOD ResolveDestination(HWND, int, IShellItem*, REFIID, void**);
    virtual STDMETHOD ClearList(int);
};

IInternalCustomDestinationList COM インターフェース

  • カスタムデスティネーションやタスクの列挙/追加/削除
  • ユーザーが「削除」したアイテムの列挙/削除

等の機能を提供します6

// {77F10CF0-3DB5-4966-B520-B7C54FD35ED6} (windows.storage.dll!CDestinationList)
DEFINE_GUID(CLSID_DestinationList, 0x77f10cf0,0x3db5,0x4966,0xb520,0xb7,0xc5,0x4f,0xd3,0x5e,0xd6);
// {507101CD-F6AD-46C8-8E20-EEB9E6BAC47F}
DEFINE_GUID(IID_IInternalCustomDestinationList, 0x507101cd,0xf6ad,0x46c8,0x8e20,0xee,0xb9,0xe6,0xba,0xc4,0x7f);
MIDL_INTERFACE("507101CD-F6AD-46C8-8E20-EEB9E6BAC47F")
IInternalCustomDestinationList : public IUnknown
{
public:
    virtual STDMETHOD SetMinItems(uint) PURE;
    virtual STDMETHOD SetApplicationID(LPCWSTR) PURE;
    virtual STDMETHOD GetSlotCount(uint*) PURE;
    virtual STDMETHOD GetCategoryCount(uint*) PURE;
    virtual STDMETHOD GetCategory(uint, GETCATFLAG, APPDESTCATEGORY*) PURE;
    virtual STDMETHOD DeleteCategory(uint, int) PURE;
    virtual STDMETHOD EnumerateCategoryDestinations(uint, REFIID, void**) PURE;
    virtual STDMETHOD RemoveDestination(IUnknown*) PURE;
    virtual STDMETHOD ResolveDestination(HWND*, ulong, IShellItem*, REFIID, void**) PURE;
    virtual STDMETHOD HasListEx(int*, int*) PURE;
    virtual STDMETHOD ClearRemovedDestinations(void) PURE;
}

その他の API サーフェース

IApplicationDestinations/IApplicationDocumentLists COM インターフェース6

これらの公開 API は、単なる IAutomaticDestinationsList API のラッパー API です。ですがアイテムの削除と、「最近アクセスしたアイテム」や「頻繫にアクセスするアイテム」リストの列挙のみ提供されており、ピン留めアイテムの列挙や、実際にピン留めすること等はできません。定義については、Microsoft Learn の IApplicationDestinationsIApplicationDocumentLists をご覧ください。

ICustomDestinationList COM インターフェース6

この API は IInternalCustomDestinationList と実装クラスを共有していますが、提供する機能は限られており、タスクの追加や、ユーザーが「削除」したアイテムの列挙、「最近アクセスしたアイテム」リストや「頻繫にアクセスするアイテム」の表示切替のみできます。定義については、Microsoft Learn 、使い方については、「Custom Jump List Sample」をご覧ください。

JumpList WPF API

WPF でのみ利用可能な API です。定義と使い方については、Microsoft Learn をご覧ください。

JumpList UAP API7

Windows 10 バージョン 1511(ビルド 10586)から利用可能な UAP API です。定義については、Microsoft Learn を、使い方については、「Jump list customization sample」をご覧ください。

よく UAP API を UWP API や WinRT API と表現されがちですが、UAP API は UWP 専用ではありません。また、WinRT API という言葉は、一般的な WinRT コンポネント全般を指し、文脈によって意味が曖昧です。したがって、UAP API という表現が最も適切です。

UI アーキテクチャ

Windows のバージョンによって以下のような違いがあります(多少のズレがあります)。

主なバイナリの場所(%SystemRoot% 描画 FW
Win 7 .\
(主な実装)explorer.exe
(リソース)explorer.exe.mui
GDI
Win 8.1 .\
(主な実装)explorer.exe
(リソース)explorer.exe.mui
DComp
Win 10 .\SystemApps\ShellExperienceHost_cw5n1h2txyewy\
(主な実装)JumpViewUI.dll
(リソース)resources.pri など
WinUI 1 XAML8
Win 11 .\
(主な実装)ShellExperiences\JumpViewUI.dll
(リソース)SystemResources\Windows.UI.ShellCommon\
resources.pri など
WinUI 2 XAML

explorer.exe に実装されていた時代は、文字列リソースが explorer.exe.mui 内にあるなど完全にクラシックな Win32 環境上で構成れていましたが、現在は内部実装も完全に C++/WinRT ベースになりました。

image.png

image.png

JumpListUI::JumpListControl ユーザーコントロール

アイテムの左クリックや右クリック、キーストローク(VK_SHIFT + VK_F10)の処理をし、コンテキストメニューやアイテムが利用できないことを知らせるポップアップの表示も処理します。JumpListListViewListView の派生コントロールで、カテゴリごとにグループ化するため CollectionViewSource をアイテムソースとして受け取ります。

<JumpListListView
    AllowDrop="True"
    CanDragItems="False"
    CanReorderItems="False"
    ItemContainerStyle="{StaticResource JumpListItemContainerStyle}"
    ItemsSource="{Binding JumpListCollectionView, Mode=OneWay}"
    ItemTemplateSelector="{StaticResource JumpListItemTemplateSelector}">
    <JumpListListView.GroupStyle>
        <GroupStyle HeaderContainerStyle="{StaticResource JumpListHeaderContainerStyle}">
            <GroupStyle.HeaderTemplate>
                <DataTemplate>
                    <JumpListCategoryHeaderControl />
                </DataTemplate>
            </GroupStyle.HeaderTemplate>
        </GroupStyle>
    </JumpListListView.GroupStyle>

    <JumpListListView.Resources>
        <ResourceDictionary>
            <JumpListItemTemplateSelector x:Key="JumpListItemTemplateSelector" Item="{StaticResource JumpListItemDataTemplate}" Separator="{StaticResource JumpListSeparatorDataTemplate}" />
            <DataTemplate x:Key="JumpListSeparatorDataTemplate">
                <Rectangle />
            </DataTemplate>
            <DataTemplate x:Key="JumpListItemDataTemplate">
                <JumpListItemControl />
            </DataTemplate>
            <CollectionViewSource x:Name="JumpListCollectionView" x:Key="JumpListCollectionView" ItemsPath="Items" IsSourceGrouped="True" />
        </ResourceDictionary>
    </JumpListListView.Resources>
</JumpListListView>

JumpListUI::JumpListItemControl ユーザーコントロール

ピン留め/ピン解除ボタンや共有の左クリック、フォーカス時の矢印キー(次のフォーカス要素にフォーカスするなど)を処理します。

<Grid ColumnDefinitions="40, *, Auto, Auto">
    <Image /> <!-- アイコン -->
    <TextBlock Column="1" /> <!-- 表示名 -->
    <Button Column="2" x:Load="False" /> <!-- 共有ボタン -->
    <Button Column="3" /> <!-- ピン留め/ピン解除ボタン -->
</Grid>

その他のクラス

  • JumpViewUI::CloseWindowSystemItem
  • JumpViewUI::EndTaskSystemItem
  • JumpViewUI::ItemNotFoundFlyoutControl
  • JumpViewUI::JumpListCategoryHeaderControl
  • JumpViewUI::JumpListCategoryViewModel
  • JumpViewUI::JumpListItemViewModel
  • JumpViewUI::JumpListViewModel

MVVM パターンを前提としてバインディングが至る所で使われており、WinUI 開発の標準的な構成に沿っています。ですが、ItemNotFoundFlyoutControl コントロールに表示されているボタン(スクリーンショット参照)が Windows 11 においても ButtonRevealStyle を使用しており、デザインに一貫性がありません。

サンプル アプリケーション—Jump List Manager

上記の API を使用して、筆者の GitHub レポジトリ上に WinUI/C# で書かれた Jump List Viewer を開発しました。Microsoft Store でインストール可能です。まだ完全には対応していませんが、CLR のランタイムマーシャラを使わずに実装したため Native AoT デプロイ上で実行するアプリケーションにも移植可能です(事前に AllowUnsafeBlocks を有効にする必要があります)。

image.png

さいごに

筆者は WPF での API が比較的優れていると感じますが、C# 専用であり、かつプロジェクトで UseWPF プロパティを有効化しなければ利用できないという制約があります。UAP での API はアンマネージド/マネージド両方で使える点からは良いと言えますが、AppContainer9上での参照を考慮していることも相まって、根本の設計思想自体が悪く、Windows App SDK で新しく API が実装されるべきだと思います。

今回はジャンプリストについて取り上げました。Windows の様々なシェルの機能について順次取り上げていくつもりですので、お楽しみにお待ち下さい!

  1. Microsoft Learn, 2023, https://learn.microsoft.com/windows/win32/shell/appids

  2. これを基に作成されたツールとして JLECmd がある。

  3. Hexacorn, 2013, https://www.hexacorn.com/blog/2013/04/30/jumplists-file-names-and-appid-calculator/

  4. 常用対数の表を事前に用意しておいて冗長な計算の手間を省き、時間の効率化を図ることと同様。Wikipedia を参照。

  5. 実際には、AddItemToRecentDocs(実装は windows.storage.dll)という名前の内部関数が呼び出される。SHAddToRecentDocs(実装は shell32.dll)もその関数を呼び出す軽量ラッパー("a thin wrapper")関数。

  6. 実装は windows.storage.dll 2 3 4

  7. 実装は twinapi.appcore.dll

  8. 内部コードネーム Jupiter として開発が始まった WinUI 1(System XAML)は、もともと Silverlight のソースコードをもとに Windows 8 において設定アプリチームによって開発され、のちに WinUI 2 (UWP XAML) が発表されるまで様々な場面で使われていた UI フレームワーク(初期の Groove Music や Maps など)。WinUI 1 をもとに WinUI 2 が開発され、WinUI 3 は WinUI 1/2 をもとに開発された。

  9. デフォルトの UWP アプリケーションの IL(LowIL と同じ)。普通の Win32 アプリケーションが MediumIL であり、これよりも低い。特別許可されない限りシステム上のほとんどのリソースにアクセスできないため、ブラウザ等のアプリケーションでも使われる。Microsoft Learn を参照。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?