Windowsシェル統合の今 ── 右クリックメニュー・ファイル関連付け・Windows 11の変化

· 更新日: · · Windows, シェル拡張, 右クリックメニュー, ファイル関連付け, COM, Windows 11, エクスプローラー, MSIX, Windows開発

更新履歴(7件・最終更新 2026年09月07日)

この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。

技術的な主張と条件はそのままに、関連付けと新旧の右クリックメニューの違いを冒頭で示し、目的別の読み方、静的verbの選択、DLLの制約、パッケージのユーザー単位登録、後始末と不具合の切り分けを小見出しで追いやすく整理した。
知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
知識マップの「IContextMenu拡張はWOW6432Nodeを必要とする」という関係を、「ホストプロセスとのビット数一致を必要とする」に改めました。本文の説明は変えていません。
仕組みの説明を図で追えるよう、Mermaid図を19点追加しました。ファイル関連付けの3段構造、HKCRの合成ビュー、アプリ側の3種類の登録、UserChoiceの保護、既定verbの決定順序、コマンドラインの引用符の事故、インプロセス拡張の巻き添え構造・ビット数・マネージコード可否、Windows 11で二重化したメニューの構造、新メニュー登録のマニフェスト構造、sparse packageの流れと登録順序、関連付けと新メニューの役割分担、実装方式の3択の選び方、アンインストール時の掃除の設計、メニューに出ないときの切り分け順序、二重表示の切り分け、原因DLLの特定手順を図にしています。本文の文章とコード、参考リンクは変えていません。
初版公開
この記事を引用する(DOI: 10.5281/zenodo.22054257)

この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。

小村 豪(2026)「Windowsシェル統合の今 ── 右クリックメニュー・ファイル関連付け・Windows 11の変化」合同会社小村ソフト. https://doi.org/10.5281/zenodo.22054257 https://comcomponent.com/blog/windows-shell-integration-context-menu-file-association/

DOI(最新版)
10.5281/zenodo.22054257
DOI(この版)
10.5281/zenodo.22556341

「Windows 11に入れ替えたら、自社アプリの右クリックメニューが見つからない」。確認すると、項目は消えておらず、メニュー末尾の「その他のオプションを確認」を開けば現れる──この相談で起きているのは故障ではなく、Windows 11によるメニューの設計変更です。現場では「クリックが1回増えた」「項目が見つからない」という問い合わせにつながります。

ただし、「ファイルをこのアプリで開くこと」と「独自コマンドを新しい右クリックメニューに出すこと」は、別の対応です。 ここを分けずにシェル拡張DLLを書き始めると、関連付けの登録だけで済む要件まで複雑にしてしまいます。

本記事は、中小企業の情シス担当者と業務アプリを預かるWindows開発者に向けた入門です。関連付けの土台から新旧メニューの違い、実装方式の選択、インストーラでの登録と削除、不具合の切り分けまでをつなげて説明します。

1. まず結論

関連付けとverbの土台は変わらず、Windows 11ではメニューの見せ方が新旧に分かれました。 まず「何を実現したいか」を決め、そのために必要な仕組みだけを選びます。

「開く」だけなら、関連付けと静的verbから考える

ファイル関連付けの土台は、レジストリの「拡張子キー→ProgID→verb」という3段構造です。拡張子キーはProgIDを指し、ProgID配下のshell\<verb>\commandが起動するコマンドラインを持ちます。単に「このアプリで開く」を実現したいだけなら、今もこの登録と静的verbで足り、シェル拡張DLLは不要です。Microsoftも、要件を満たす最も単純な静的verbから検討するよう案内しています。12

登録先は、全ユーザー向けならHKLM、ユーザー単位ならHKCUです。HKCRは両者のClassesを重ねた合成ビューなので、書き込み先はHKLMかHKCUを明示し、HKCRは確認用と考えます。3

なお、候補への登録と、既定アプリへの選択は別です。 ダブルクリックで開く既定アプリはユーザーが選び、OSがその選択を保護します。インストーラが勝手に既定を奪うのではなく、候補として正しく登録するところまでがアプリ側の仕事です。4

独自コマンドを新メニューに出すなら、IExplorerCommandとパッケージ識別が必要

Windows 11では、従来型のIContextMenu拡張は「その他のオプションを確認」(Shift+F10)で開く旧メニュー側に退避されます。新メニューへ独自コマンドを載せるには、IExplorerCommandの実装とパッケージ識別が必要です。56

公式ルートは、IExplorerCommandを実装したネイティブDLLをMSIXマニフェスト(desktop4:FileExplorerContextMenus)で登録する方法です。既存アプリを全面的にMSIX化できない場合は、sparse package(外部ロケーション付きMSIX)で識別だけを与えられます。67

DLLの安全性と、アンインストール時の後始末まで考える

従来型シェル拡張は、エクスプローラーなどのプロセス内に読み込まれるCOM DLLです。拡張のクラッシュや遅延はホスト全体へ波及します。64bitのホストには64bit DLLが必要で、インプロセス拡張をマネージコードで実装することはサポートされません。89

関連付けの登録・変更・削除後はSHChangeNotify(SHCNE_ASSOCCHANGED)で通知します。アンインストールでは自社のProgID等を削除し、拡張子キーの既定値は残すのが公式ガイドです。メニューを出すだけでなく、変更の反映と後始末までがシェル統合です。110

目的別の読み方

知りたいこと・起きている症状 読むところ
どの実装方式を選ぶべきか 6章の判断表。関連付けだけか、新メニューへの独自コマンド追加かを分けます
ダブルクリックや「プログラムから開く」に対応したい 2章の関連付けと3章の静的verb
登録したのに既定アプリにならない 2.4節のUserChoice。候補登録とユーザーの選択を分けます
Windows 11でメニューが一段奥に隠れた 5章の新旧メニュー。対応方法は5.2節、MSIX化できない場合は5.3節
インストーラで何を登録・解除すればよいか 7章。特に7.3節のユーザー単位の登録と7.4節の後始末
メニューが出ない・二重に出る・エクスプローラーが重い 8章の切り分け。DLLの制約は4章

仕組みから学ぶ場合は2章から順に、既存アプリの対応方針を決める場合は6章から読めます。

図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全16件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle

2. ファイル関連付けの仕組み ── 拡張子キー→ProgID→verbの3段構造

この章では、ファイル側の登録 → 書き込み先 → アプリ側の登録 → ユーザーの選択の順に整理します。拡張子がProgIDを指し、verbがコマンドラインを持ち、込み入った拡張はインプロセスCOM DLLとして動く、という土台は20年以上変わっていません。

2.1. 3段構造を1つの例で読む

まず、関連付けの基本形を1つの例で見ます。拡張子キーがProgIDを指し、その中のverbが起動するコマンドを持ちます。1 ユーザーが既定アプリを選んでいる場合の優先関係は、2.4節で説明します。

HKEY_CLASSES_ROOT
   .kmrpt                                  ← (1) 拡張子キー
      (Default) = KomuraSoft.Report.1      ←     ProgIDを指すだけのポインター
      OpenWithProgids
         KomuraSoft.Report.1               ←     「プログラムから開く」の候補
   KomuraSoft.Report.1                     ← (2) ProgID(関連付けの実体)
      (Default) = 小村レポート文書
      DefaultIcon
         (Default) = "C:\Program Files\KomuraSoft\Report.exe",0
      shell                                ← (3) verb(動詞)の一覧
         open
            command
               (Default) = "C:\Program Files\KomuraSoft\Report.exe" "%1"
  • (1) 拡張子キー(.kmrpt)は、既定値でProgIDの名前を指すだけです。ここに直接コマンドを書くのは誤りです。
  • (2) ProgID(KomuraSoft.Report.1)が関連付けの実体で、表示名・アイコン・verb一覧を持ちます。
  • (3) verbは「開く」「印刷」といった動詞で、shell\open\commandの既定値が実際に起動されるコマンドラインです。

この分離のおかげで、複数の拡張子(.kmrptと.kmrpt-fileなど)を同じProgIDに向けたり、アプリのバージョンアップでProgIDを差し替えたりできます。

ファイル関連付けの3段構造拡張子キーは既定値でProgIDを指すだけのポインターで、ProgIDが表示名やアイコンとverb一覧を持つ実体であり、verb配下のcommandの既定値が実際に起動されるコマンドラインになる既定値でProgIDを指す拡張子キー .kmrptProgID KomuraSoft.Report.1verb(shell配下のopenなど)commandの既定値Report.exeが起動される表示名・DefaultIconも持つ

図1: 拡張子キーはポインター、ProgIDが実体、verbのcommandが実際に起動されるコマンドライン。

2.2. HKCRは「合成ビュー」── どこに書くかで意味が変わる

上の例はHKEY_CLASSES_ROOT(HKCR)で示しましたが、HKCRは物理的な保存場所ではなく、HKLM\Software\ClassesとHKCU\Software\Classesを重ねた合成ビューです。同じキーが両方にあればHKCU側が勝ちます。3

HKCRは合成ビューHKLMとHKCUそれぞれのClassesを重ねたものがHKCRで、同じキーが両方にあればHKCU側が優先され、登録の書き込みはHKLMかHKCUを明示してHKCRは読み取り用と割り切るHKLM\Software\Classes(全ユーザー)HKCR(合成ビュー)HKCU\Software\Classes(ユーザー単位)同じキーがあればHKCU側が勝つ読み取り(確認)用と割り切る

図2: HKCRはHKLMとHKCUのClassesを重ねた見え方で、書き込み先は必ずどちらかを明示する。

書き込み先 意味 必要な権限
HKLM\Software\Classes 全ユーザー共通の登録 管理者権限
HKCU\Software\Classes そのユーザーだけの登録 不要
HKCRへ直接書く 既存キーの場所に依存して振り分けられる 場合による

実務では、登録は必ずHKLMかHKCUのどちらかを明示して書き、HKCRは読み取り(確認)用と割り切るのが安全です。

関連付けデータと、COM登録のビット数を混同しない

WOW64のレジストリリダイレクトでは、関連付けデータとCOM登録で扱いが違います。拡張子キーやProgIDなどHKLM\Software\Classes直下の関連付けデータは、Windows 7以降は32bit/64bitのレジストリビュー間で共有されており、32bitインストーラが書いてもWow6432Node側へ逃げることはありません。

一方、Classes\CLSIDなどCOM登録系の一部サブキーはリダイレクト対象で、後述するシェル拡張(インプロセスCOM)の登録では32bit/64bitの書き分けが効いてきます。詳しくは「レジストリの32bit/64bitリダイレクトと仮想化の落とし穴」で扱っています。

2.3. アプリ側の登録 ── App Paths・Applications・RegisteredApplications

ファイル側(拡張子とProgID)と対になる、アプリ側の登録も3種類あります。11

  • App Paths(HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths): 実行ファイル名だけでShellExecuteExから起動できるようにする登録。PATH環境変数を汚さずに済むため、Microsoftはこちらを推奨しています。
  • Applications(HKCR\Applications\<アプリ.exe>): 「プログラムから開く」で任意のファイルを渡されたときの既定の開き方と、アプリの表示名(FriendlyAppName)を定義します。
  • RegisteredApplications + Capabilities: アプリが扱える拡張子・MIMEタイプを宣言し、Windowsの既定アプリ設定画面に候補として並ぶための登録です。

「うちのアプリが既定アプリの一覧に出てこない」という相談の大半は、ProgIDは登録したのにこのCapabilities登録を省略しているケースです。

アプリ側の3種類の登録アプリ側の登録にはApp PathsとApplicationsとRegisteredApplicationsの3種類があり、それぞれ実行ファイル名だけでの起動、プログラムから開くときの既定の開き方、既定アプリ設定画面への掲載という役割を担うアプリ側の登録App PathsApplicationsRegisteredApplicationsファイル名だけで起動プログラムから開く既定既定アプリ画面に載るCapabilitiesで宣言が条件

図3: アプリ側の登録は3種類あり、既定アプリ画面の候補に載るにはCapabilities登録が必要になる。

2.4. 既定アプリはユーザーのもの ── UserChoiceの保護

拡張子キーの既定値にProgIDを書いても、それだけで既定アプリになるとは限りません。ユーザーが「プログラムから開く」等で明示的に選んだ結果は、HKCU\...\Explorer\FileExts\<拡張子>\UserChoiceに保持され、関連付けの解決ではこちらが優先されます。

UserChoiceを直接書き換える設計にはしない

Windowsは既定アプリのプログラムによる変更をサポートしていません。 既定アプリの設定はシステム設定UIを通じてユーザーが行う設計で、UserChoiceのデータは難読化され、フィルタードライバー(UCPD.sys)がアプリからの書き込みをブロックします。管理環境ではグループポリシー/MDMポリシーが公式の手段です。4

かつてSetUserFTAのような「ハッシュを模倣して書き換える」ツールが使われてきたのは、この保護の裏返しです。

インストーラは「選ばれる準備」をする

自社アプリのインストーラに組み込むのは、次の3つです。

  1. ProgIDとverbを正しく登録する。
  2. OpenWithProgIdsへ追加する。
  3. 必要なら既定アプリの設定画面へユーザーを誘導する。

既定を奪うのではなく、ユーザーが選べる状態を整えます。

既定アプリの解決とUserChoiceの保護ユーザーが明示的に選んだ結果はUserChoiceに保持されて関連付けの解決で優先され、アプリからの書き換えはUCPD.sysが遮断するため、インストーラにできるのは候補としての登録と設定画面への誘導までになる優先UCPD.sysが遮断UserChoice(ユーザーの選択)関連付けの解決拡張子キーの既定値アプリからの書き換えインストーラの仕事ProgIDとverbの登録OpenWithProgIdsへ追加設定画面への誘導

図4: 関連付けの解決ではユーザーの選択(UserChoice)が優先され、アプリからの書き換えはOSが保護する。

3. 「開く」以外のverb ── print・edit・runas・カスタムverb

3.1. 標準verbとカスタムverb

verbはopenだけではありません。OSが意味を知っている標準verbにはopenのほかedit、print、play、previewなどがあり、標準verbはOSのロケールに応じた表示名が自動で付きます。ダブルクリック時に使われる既定verbは、shellキーの既定値→レジストリ上の最初のverb→open→openwithの順で決まります。12

既定verbの決定順序ダブルクリック時に使われる既定verbはshellキーの既定値、レジストリ上の最初のverb、open、openwithの順で最初に見つかったものに決まる無ければ無ければ無ければshellキーの既定値レジストリ上の最初のverbopenopenwith

図5: ダブルクリック時の既定verbは、この順で最初に見つかったものが使われる。

独自の動詞を足したいときはカスタムverbを登録します。

KomuraSoft.Report.1
   shell
      open
         command
            (Default) = "C:\Program Files\KomuraSoft\Report.exe" "%1"
      print
         command
            (Default) = "C:\Program Files\KomuraSoft\Report.exe" /print "%1"
      verify                          ← カスタムverb
         (Default) = 帳票を検証(&V)   ← メニューの表示名
         command
            (Default) = "C:\Program Files\KomuraSoft\Report.exe" /verify "%1"

3.2. 昇格・Shift時の表示・古いDDEを区別する

verbには、次のような指定もあります。

  • runasというverbを登録すると「管理者として実行」に相当する昇格起動を定義でき、ShellExecute系APIからrunasを指定した起動にも使われます。
  • verbキーにExtendedという空の値を置くと、Shiftキーを押しながら右クリックしたときだけ表示される拡張verbになります。めったに使わない危険な操作を隠すのに便利です。12
  • 古いアプリの関連付けにはDDE(ddeexecキー)で既存プロセスへ文書を送り込む構成が残っていることがありますが、DDEによるverb起動はすでに非推奨(Deprecated)の遺産です。新規に書く理由はありません。12

3.3. EXEパスと選択ファイルのパスを引用符で囲む

事故が多いのがコマンドラインの引用符です。コマンド文字列の要素にスペースが入り得るなら、必ず引用符で囲む必要があります。C:\Program Files\...のようなEXEパスはもちろん、%1(選択ファイルのパス)は常に"%1"と書くべきです。ユーザーのファイルパスにスペースが含まれないことは保証できないからです。引用符のないMy Program.exeは「MyをProgram.exeという引数付きで起動する」と解釈されます。13

コマンドラインの引用符の事故引用符のないコマンドはスペースの位置で区切られてMyをProgram.exeという引数付きで起動すると誤解釈されるため、スペースを含み得るEXEパスと選択ファイルのパスを表す%1は常に引用符で囲むスペースで分割引用符なしのcommand別のEXEの起動と誤解釈引用符ありのcommand意図どおりに起動EXEパスを引用符で囲む%1も常に引用符で囲む

図6: 引用符のないコマンドはスペースで誤って区切られるため、EXEパスと%1は常に引用符で囲む。

3.4. DLLを書く前に、静的verbで足りるかを確認する

ここまでのレジストリだけの仕組み(静的verb)は、DLLを1つも書かずに実現でき、エクスプローラーを不安定にするリスクもありません。Microsoft自身が「シェル拡張を書く前に、要件を満たす最も単純な静的verbで済まないか検討せよ」と繰り返し述べています。2

4. 従来型シェル拡張 ── エクスプローラーの中で動くDLL

この章で押さえるのは、従来型の拡張DLLは、エクスプローラー等のプロセス内で動くという点です。動作場所を理解すると、安定性・ビット数・実装言語の制約がつながります。

4.1. シェル拡張の種類

静的verbでは足りない「選択内容に応じてメニューを動的に変える」「アイコンやプロパティ画面を差し替える」といった要件には、シェル拡張ハンドラーを使います。代表的な種類は次のとおりです。8

ハンドラー 主なインターフェース できること
コンテキストメニューハンドラー IContextMenu + IShellExtInit メニュー項目を動的に追加・制御
アイコンハンドラー / アイコンオーバーレイ IExtractIcon / IShellIconOverlayIdentifier ファイルごとのアイコン・重ね表示
プロパティシートハンドラー IShellPropSheetExt プロパティ画面へのタブ追加
サムネイル / インフォチップ IThumbnailProvider / IQueryInfo 縮小表示・ホバー時の説明
ドラッグ&ドロップ / コピーフックハンドラー IDropTarget / ICopyHook ドロップ時・コピー移動時の介入

これらはいずれもCOMのクラスとして実装し、CLSIDをレジストリに登録します。COM自体の考え方は「COM / ActiveX / OCX とは何か」を参照してください。

4.2. インプロセスCOMサーバーであることの意味

従来型シェル拡張の本質は、エクスプローラー(や共通ファイルダイアログを開いた任意のアプリ)のプロセス内に読み込まれるインプロセスCOMサーバー(DLL)だということです。ここからすべての注意点が導かれます。8

  • 拡張がクラッシュすれば、エクスプローラーが巻き添えでクラッシュします。ハングすれば右クリックが数秒固まります。しかも被害はエクスプローラーに限らず、ファイルを開くダイアログを表示したすべてのアプリに及びます。
  • メニュー構築はUIスレッドで行われるため、ネットワークアクセスやファイルI/Oのような遅い処理をメニュー表示時に行ってはいけません。
  • スレッディングモデルはApartmentで登録するのが原則です。
インプロセス拡張の巻き添え構造シェル拡張DLLはエクスプローラーだけでなくファイルダイアログを開いた任意のアプリのプロセスにも読み込まれるため、拡張のクラッシュやハングは宿主プロセス全体に波及するプロセス内に読込プロセス内に読込シェル拡張DLLエクスプローラーダイアログを開く任意アプリクラッシュやハングが波及遅い処理を表示時にしない

図7: 拡張DLLは宿主プロセスの中で動くため、クラッシュやハングは宿主全体へ波及する。

「特定のフォルダーを開くとエクスプローラーが固まる」「右クリックに5秒かかる」という相談を調査すると、原因が自社アプリではなくサードパーティ製のシェル拡張だった、ということは珍しくありません。切り分け方法は8章で扱います。

4.3. ビット数の一致 ── 64bit環境では64bit DLLが必須

インプロセスDLLは、読み込むプロセスとビット数が一致しなければなりません。64bit Windowsのエクスプローラーは64bitプロセスなので、32bitでしかビルドしていないシェル拡張DLLは、そもそも読み込まれず、メニューに一切現れません。エラーも出ないため「登録したのに出ない」原因の定番です。

アプリ本体まで64bit化する必要があるわけではない

32bitアプリ本体と64bitシェル拡張DLLの組み合わせは正当な構成ですが、COM登録がbitnessごとに分かれる(Wow6432Node)ことに注意が必要です。なお、verbのcommandから起動するのは別プロセスのEXEなので、この制約を受けません(32bit EXEのままで問題ありません)。

シェル拡張DLLのビット数一致64bitエクスプローラーに読み込めるのは64bitのシェル拡張DLLだけで、32bitのみのDLLはエラーも出ずにメニューへ現れず、verbのcommandから起動するEXEは別プロセスなので制約を受けない読み込める読み込めない別プロセス64bitエクスプローラー64bitシェル拡張DLL32bitのみのDLLエラーなくメニューに出ないverbで起動するEXE32bitのままで問題なし

図8: 64bitエクスプローラーに読み込まれるのは64bit DLLだけで、verbで起動するEXEはこの制約を受けない。

4.4. マネージコードで書いてはいけない理由

「C#でシェル拡張を書けないか」という質問をよく受けますが、Microsoftはインプロセスのシェル拡張をマネージコード(.NET)で書くことを非推奨とし、サポート対象外と明言しています。9

理由は、拡張が任意のプロセスに読み込まれるという性質にあります。宿主アプリを不安定にする要因は、主に次の3つです。

  • CLRのバージョン競合。 特に.NET Framework 4未満で問題になります。
  • 再入。 ロック待ちでCLRがメッセージループへ再入する問題があります。
  • オブジェクト寿命。 ガベージコレクションによる寿命の非決定性が、COMの参照カウント契約と衝突します。

.NET Framework 4以降やモダンな.NETで緩和された項目もありますが、公式の立場は変わっていません。

実務の指針はシンプルです。インプロセス拡張はネイティブC++で書く。マネージコードを使いたければ、verbのcommandで起動する通常のEXEにするか、別プロセスで動くアウトプロセス拡張(プレビューハンドラー等)にする。9

マネージコード可否の判断エクスプローラーのプロセス内で動くインプロセス拡張はネイティブC++で書くのが原則で、マネージコードを使いたい場合はverbのcommandで起動する通常のEXEか別プロセスで動くアウトプロセス拡張にするはいいいえプロセス内で動く拡張?ネイティブC++で書くマネージコードでも可CLR競合や再入で宿主が不安定verbで起動する通常のEXEプレビュー等の別プロセス拡張

図9: インプロセス拡張はネイティブC++が原則で、マネージコードは別プロセスで動く構成に限る。

5. Windows 11の新コンテキストメニュー ── メニューの二重化

ここでは、旧メニューへ移った理由 → 新メニューへの登録 → 既存インストーラを維持する方法の順に説明します。「このアプリで開く」だけの関連付けと、独自コマンドの追加との違いは5.4節で確認します。

5.1. 何が起きたか

Windows 11は、エクスプローラーの右クリックメニューを刷新しました。切り取り・コピー等が上部のアイコン列になり、「開く」「プログラムから開く」がまとめて上部に配置され、アプリが追加するコマンドはシェル標準コマンドの下にグループ化されます。1つのアプリが複数のコマンドを追加する場合は、アプリ名付きのフライアウト(サブメニュー)に集約されます。5

そして肝心の点がこれです。従来型のIContextMenuベースのシェル拡張は削除されたのではなく、「その他のオプションを確認」(Shift+F10)で開く、Windows 10のメニューをそのまま読み込んだ旧メニュー側に退避されました。5 冒頭の相談の「メニューが隠れた」の正体はこの二重化です。

Windows 11で二重化した右クリックメニュー右クリックでまず開くのは新メニューで、そこに載るのはIExplorerCommandとパッケージ識別で登録したコマンドだけであり、従来型IContextMenu拡張はその他のオプションを確認で開く旧メニュー側に退避されるその他のオプションを確認 Shift+F10ファイルを右クリック新メニュー(Windows 11)IExplorerCommand+識別のコマンド旧メニュー(Windows 10のメニュー)従来型IContextMenu拡張複数コマンドはフライアウトに集約

図10: 新メニューに載るのはIExplorerCommand+識別のコマンドだけで、従来型拡張は旧メニュー側に退避される。

5.2. 新メニューに載せる公式ルート ── IExplorerCommand+マニフェスト登録

新メニューに独自コマンドを出す公式ルートは、IExplorerCommandを実装したネイティブDLLと、MSIXマニフェストでの登録です。6

マニフェストには2種類の宣言を書く

以下の例は、前半でCOMサーバー(CLSIDと実装DLL)を、後半でコンテキストメニュー拡張(対象とコマンド)を宣言しています。両方を結び付けるのが同じCLSIDです。

<!-- パッケージマニフェスト(抜粋) -->
<com:Extension Category="windows.comServer">
  <com:ComServer>
    <com:SurrogateServer DisplayName="Komura commands">
      <com:Class Id="01234567-89AB-CDEF-0123-456789ABCDEF"
                 Path="KomuraCommand.dll" ThreadingModel="STA" />
    </com:SurrogateServer>
  </com:ComServer>
</com:Extension>
<desktop4:Extension Category="windows.fileExplorerContextMenus">
  <desktop4:FileExplorerContextMenus>
    <desktop5:ItemType Type=".kmrpt">
      <desktop5:Verb Id="VerifyReport"
                     Clsid="01234567-89AB-CDEF-0123-456789ABCDEF" />
    </desktop5:ItemType>
  </desktop4:FileExplorerContextMenus>
</desktop4:Extension>

ItemTypeのTypeには特定の拡張子のほか、*(すべてのファイル)、Directory(フォルダー)、Directory\Background(フォルダーの背景)を指定できます。DLLはエクスプローラーのアーキテクチャ(64bit/ARM64)に一致させます。6

メニュー構築メソッドは高速に返す

IExplorerCommand自体はWindows 7時代からあるインターフェースで、タイトル(GetTitle)、アイコン(GetIcon)、有効/無効/非表示の状態(GetState)、実行(Invoke)を実装します。メソッドはUIスレッドから呼ばれるため、ネットワーク資源へのアクセスは禁止で、メニュー構築系のメソッドは高速に返す必要があります。重い処理はInvoke後に行います。146

新メニュー登録のマニフェスト構造MSIXマニフェストのCOMサーバー宣言がCLSIDとDLLを対応付け、コンテキストメニュー拡張の宣言がItemTypeとVerbで対象と実装を結び付けることで、独自コマンドが新メニューに表示されるCLSIDとDLLを対応付けItemTypeとVerbで指定MSIXマニフェストCOMサーバー宣言メニュー拡張の宣言IExplorerCommand実装DLL新メニューにコマンド表示対象は拡張子や全ファイル等

図11: マニフェストの2つの宣言が実装DLLと対象を結び付けて、新メニューにコマンドが載る。

5.3. 非パッケージアプリの選択肢 ── sparse packageで識別だけを得る

「うちのアプリはMSIじゃないと配れない。MSIX化は無理」という場合の逃げ道が、sparse package(外部ロケーション付きMSIX)です。アプリ本体を含まない、マニフェストだけの小さなMSIXを署名して作り、既存インストーラの最後に登録します。これでアプリはパッケージ識別を獲得し、上記のマニフェスト登録(=新メニューへの表示)が可能になります。

利用できるのはWindows 10バージョン2004以降で、対象マシンで信頼される証明書によるパッケージの署名が必要です。7 登録・解除の順序と、ユーザー単位の登録であることへの注意は7.3節で扱います。

sparse packageで識別を得る流れ既存インストーラでアプリ本体を配置した後、マニフェストだけのsparse packageを外部ロケーション付きで登録するとアプリはパッケージ識別を獲得し、新メニューへのマニフェスト登録が可能になる既存インストーラアプリ本体を配置sparse packageマニフェストだけで本体なし外部ロケーション付きで登録パッケージ識別を獲得新メニュー登録が可能に信頼される署名が必要

図12: 本体を含まないsparse packageを外部ロケーション付きで登録すると、アプリはパッケージ識別を獲得する。

インストーラを差し替えずに済むのが最大の利点で、既存のMSI/EXEインストーラ資産を持つアプリの現実解です。MSIXへの全面移行との比較は「Windowsアプリ配布方式の選び方」も参照してください。

5.4. 関連付けのverbは新メニューでどう見えるか

誤解されやすい点ですが、2〜3章の関連付け(ProgIDとverb)は、新メニューでも生きています。ダブルクリックの既定verb、「開く」、「プログラムから開く」の候補は関連付けから解決され、新メニューの上部に表示されます。つまり「このアプリで開けるようにしたい」だけなら、Windows 11でも何も追加対応は要りません。

一方、関連付けは汎用のメニュー拡張ではないため、任意のカスタムコマンドを新メニューの第一階層に出したければIExplorerCommand+識別が必要、という役割分担です。6

関連付けと新メニューの役割分担ProgIDとverbの関連付けは新メニューでもダブルクリックの既定verbや開くとプログラムから開くの解決に使われて上部に表示され、任意のカスタムコマンドを新メニューの第一階層に出すにはIExplorerCommandと識別が必要になる関連付け(ProgIDとverb)既定verbと開くの解決新メニュー上部に表示Windows 11でも追加対応不要任意のカスタムコマンドIExplorerCommand+識別新メニュー第一階層に表示

図13: 関連付けは新メニューでも「開く」系の解決を担い、カスタムコマンドだけがIExplorerCommand+識別を要する。

6. 実務の判断表 ── 3つの選択肢のどれを取るか

まず(a)で足りるかを確認し、独自コマンドの新メニュー表示が必要なら(b)を選びます。 既存の従来型拡張を当面維持するのが(c)です。

実現したいこと 推奨する手段 Windows 11での見え方 必要な作業・コスト
(a) ダブルクリックや「開く」で自社アプリを起動したい 関連付け+静的verb(レジストリ登録のみ) 新メニューの「開く」「プログラムから開く」に統合表示 インストーラのレジストリ登録のみ。DLL不要・署名の追加要件なし
(b) 選択したファイル/フォルダーへの独自コマンドを新メニューに出したい IExplorerCommand実装+MSIXマニフェスト登録。非パッケージアプリはsparse packageで識別を付与 新メニューの第一階層(複数コマンドはアプリ名フライアウトに集約) ネイティブC++ DLL+パッケージ識別+コード署名
(c) 既存の従来型IContextMenu拡張を使い続ける 当面そのまま維持(新規開発には選ばない) 「その他のオプションを確認」(Shift+F10)の旧メニュー側のみ 64bitビルドとCOM登録の維持。将来は(b)への移行を計画

判断1: 要件を満たす最も単純な方法を選ぶ

(a)で済む要件に(b)や(c)を持ち出さないことが第一です。シェル拡張は書いた瞬間から、エクスプローラーの安定性に対する責任を負います。

判断2: 旧メニューの維持と、使い勝手の改善を分けて考える

(c)は「壊れてはいない」だけで、ユーザー体験としては一段劣る位置に置かれ続けます。日常操作で使う頻度が高いコマンドほど、(b)への移行の投資対効果が大きくなります。

3つの選択肢の選び方ダブルクリックや開くで起動したいだけなら関連付けと静的verbで足り、新メニューに独自コマンドを出すならIExplorerCommandとMSIXマニフェスト登録で、MSIX化できない場合はsparse packageで識別を付与し、既存の従来型IContextMenu拡張は旧メニュー側で当面維持するはいいいえはいはいいいえいいえ開くだけでよい?関連付け+静的verb新メニューに独自コマンド?MSIX化できる?IExplorerCommand+MSIXsparse packageで識別従来型を当面維持旧メニュー側のみに表示DLL不要でリスク小

図14: 要件に応じて静的verb、IExplorerCommand+識別、従来型維持の3択から選ぶ。

7. 展開・登録の実務 ── インストーラ・sparse package・掃除

実装方式が決まったら、登録先・変更通知・パッケージの登録と解除・アンインストール時の後始末をインストーラに組み込みます。

7.1. HKLMかHKCUか

登録先はインストーラの形態と合わせます。全ユーザー向け(Program Filesへ配置、管理者権限)ならHKLM\Software\Classes、ユーザー単位インストール(権限昇格なし)ならHKCU\Software\Classesです。混ぜると「Aさんでは開けるがBさんでは開けない」型の問い合わせを生みます。

CLSID登録を伴うシェル拡張では、レジストリ登録そのものを不要にするReg-Free COMという選択肢もアプリ内COM利用では有効ですが、エクスプローラーが読み込むシェル拡張には適用できないため、正攻法の登録が必要です(「Reg-Free COMとは」)。

7.2. 変更したら通知する ── SHChangeNotify

関連付けを登録・変更・削除したら、SHChangeNotifyでSHCNE_ASSOCCHANGEDイベントを通知します。これを省くと、変更が再起動までエクスプローラーに認識されないことがあります。110

// インストーラのカスタムアクション等で、関連付け変更の後に1回呼ぶ
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);

7.3. sparse packageの登録と解除

sparse packageの登録・解除はインストーラの仕事です。登録はファイル配置の後、解除はファイル削除の前に行います。7

# インストール時: ファイル配置後に、インストール先を外部ロケーションとして登録
Add-AppxPackage -Path "C:\Program Files\KomuraSoft\KomuraReport.identity.msix" `
                -ExternalLocation "C:\Program Files\KomuraSoft"

# アンインストール時: ファイルを消す前にパッケージ登録を解除
Remove-AppxPackage <パッケージのフルネーム>

実行ユーザーへの登録と、全ユーザーへの展開を分ける

Add-AppxPackageは実行したユーザーに対して登録されます。per-machineのMSIのカスタムアクションからLocalSystemで実行すると、インストールしたユーザーには識別が付与されません。そのため、ユーザー偽装(impersonate)で実行する構成にします。

ただし、偽装で登録されるのも、そのインストールを実行したユーザーだけです。 1台を複数ユーザーで使う場合、他のユーザーや後から作られたユーザーにはパッケージ識別がなく、新メニューにコマンドが出ません。

全ユーザーで使わせるなら、アプリの初回起動時に自分のパッケージ登録を確認し、未登録なら登録する、といったユーザーごとの登録を用意します。アンインストール時も、登録済みの各ユーザーからの解除を計画に含めます。

登録後にメニューへ反映されない場合

マニフェスト登録の反映には、エクスプローラーの再起動(またはサインアウト)が必要な場合があります。6

sparse packageの登録と解除の順序インストール時はファイル配置の後にsparse packageを登録し、アンインストール時はファイル削除の前に登録を解除するが、登録は実行したユーザーだけに有効な点に注意するインストールファイルを配置sparse packageを登録アンインストールパッケージ登録を解除ファイルを削除登録は実行ユーザーだけに有効

図15: 登録はファイル配置の後、解除はファイル削除の前に行い、登録が実行ユーザー単位である点に注意する。

7.4. アンインストール時の掃除 ── 消すものと残すもの

アンインストール時の掃除には、公式ガイドに明確な指針があります。1

  • 消すもの: 自社のProgIDキー一式、Capabilities/RegisteredApplications登録、シェル拡張のCLSID登録、sparse package(Remove-AppxPackage)。
  • 残すもの: 拡張子キー(.kmrpt)の既定値。自社ProgIDを指したままでも消さないのが公式の推奨です。インストール後に別アプリが既定を取っていないかの判定は困難であり、Windowsは既定値のProgIDが未登録なら単に無視するため、残しても実害がないからです。
  • 掃除の最後にもSHChangeNotify(SHCNE_ASSOCCHANGED)を呼びます。

「アンインストールしたのにメニューに残骸が出る」問題の多くは、この掃除設計の漏れです。

アンインストール時の掃除の設計アンインストールでは自社のProgIDキーやCLSID登録とsparse packageは消し、拡張子キーの既定値は未登録なら無視されるため残し、掃除の最後にSHChangeNotifyで変更を通知するアンインストール消すもの残すものProgIDやCLSID登録sparse package拡張子キーの既定値未登録ProgIDは無視される最後にSHChangeNotifyで通知

図16: 自社の登録は消し、拡張子キーの既定値は残し、掃除の最後に変更を通知する。

8. トラブルシューティング ── 出ない・二重・重い

不具合は「出ない」「二重に出る・消えない」「重い・落ちる」に分けて調べます。最後に、登録と後始末をクリーンな環境で確かめる方法を説明します。

8.1. メニューに出ない

最初に、新旧どちらのメニューを見ているかを確認します。 そのうえで、次の順に切り分けます。

  1. どちらのメニューを見ているか: 旧方式の登録はShift+F10の旧メニュー側にしか出ません。まず両方を確認します。
  2. ビット数: 32bitのみのシェル拡張DLLは64bitエクスプローラーに読み込まれません(4.3節)。
  3. 登録先: HKLM/HKCU、Wow6432Nodeの取り違え。reg queryで実際のキーを確認します。
  4. パッケージ登録: 新メニュー向けならGet-AppxPackageで登録の有無、署名証明書の信頼、-ExternalLocationのパスを確認し、エクスプローラーを再起動します。6
  5. 通知漏れ: SHChangeNotify忘れなら、エクスプローラーの再起動で反映されるかで判別できます。
メニューに出ないときの切り分け順序どちらのメニューを見ているかの確認から始め、DLLのビット数、レジストリの登録先、パッケージ登録と署名、SHChangeNotifyの通知漏れの順に切り分ける新旧どちらのメニューか確認DLLのビット数を確認HKLMとHKCUの登録先を確認パッケージ登録と署名を確認通知漏れを再起動で判別

図17: 「出ない」ときは、見ているメニュー・ビット数・登録先・パッケージ登録・通知漏れの順で切り分ける。

8.2. 二重に出る・消えない

まず、どちらのメニューに重複しているかであたりを付けます。

  • 旧メニューにだけ二重に出る: アンインストール時の掃除漏れ(7.4節)や、旧バージョンのProgIDの残骸を疑います。
  • 新旧両方に出る: 旧方式のレジストリ登録と、MSIXマニフェスト登録の併存を疑います。

いずれも典型的な原因の切り分けであり、実際の登録内容を確認して判断します。

二重表示の切り分け旧メニューにだけ二重に出るなら掃除漏れや旧ProgIDの残骸系、新旧両方に出るなら旧方式のレジストリ登録とマニフェスト登録の併存系とあたりを付ける旧メニューだけ新旧両方どちらに二重に出るか残骸系併存系掃除漏れや旧ProgIDの残り旧レジストリ登録と新登録の併存

図18: 旧メニューだけに二重なら残骸系、新旧両方に出るなら併存系とあたりを付ける。

8.3. エクスプローラーが重い・落ちる

右クリックが遅い、特定フォルダーでクラッシュする場合は、まずインストール済みシェル拡張を棚卸しします。

  1. 拡張を一覧する。 NirSoftのShellExViewのようなツールで、非Microsoft製の拡張を確認します。
  2. 一時無効化して絞り込む。 疑わしいものを二分探索し、原因DLLを特定します。クラッシュなら、イベントビューアーの「障害が発生しているモジュール」も手がかりです。
  3. 自社拡張なら、メニュー構築パスを調べる。 同期I/Oやネットワークアクセスを疑います(4.2節・5.2節)。
重い・落ちるときの原因DLL特定ShellExViewで非Microsoft製のシェル拡張を一覧し、疑わしいものを一時無効化しながら二分探索して原因DLLを特定し、クラッシュの場合はイベントビューアーの障害モジュールも手がかりにするシェル拡張の棚卸し非Microsoft製を一覧一時無効化して二分探索原因DLLを特定クラッシュの場合障害モジュールを確認

図19: 非Microsoft製拡張を一時無効化しながら二分探索し、クラッシュ時はイベントビューアーも併用する。

8.4. 検証はWindows Sandboxが便利

シェル統合の検証は「クリーンな環境でインストール→動作→アンインストール→残骸ゼロ」の確認が基本です。ここで便利なのがWindows Sandbox(Pro/Enterprise/Education)で、起動のたびにまっさらな使い捨てWindowsが数秒で立ち上がるため、インストーラの登録・掃除のテストを何度でも回せます。閉じれば全部消えるので、レジストリの残骸調査にも向きます。15

9. まとめ

Windows 11への入れ替えで「メニューが隠れた」と言われたら、まず6章の判断表で、何を実現したいのかを確認してください。考える順序は、次の3段階です。

1. 関連付けで足りるかを判断する

「このアプリで開く」だけなら、関連付けと静的verbで今も足ります。土台は拡張子キー→ProgID→verbで、HKCRはHKLM/HKCUのClassesを重ねた確認用のビューです。書き込み先を明示し、%1は必ず引用符で囲みます。

ただし、既定アプリを選ぶのはユーザーです。インストーラは既定を奪うのではなく、候補として正しく登録します。

2. 独自コマンドを、どちらのメニューに出すかを決める

従来型IContextMenu拡張は、「その他のオプションを確認」で開く旧メニュー側で動きます。新メニューへ独自コマンドを出すには、IExplorerCommandとMSIXマニフェストでの登録が必要です。全面的にMSIX化できないアプリは、sparse packageでパッケージ識別を得るのが現実解です。

従来型拡張のDLLは、エクスプローラーなどのプロセス内で動きます。クラッシュや遅延はホスト全体へ波及し、64bitホストには64bit DLLが必要です。インプロセス拡張をマネージコードで書くことはサポートされず、ネイティブC++での実装が原則です。

3. 登録・変更通知・解除を一組で検証する

関連付けの登録・変更・削除後はSHChangeNotifyで通知します。アンインストールでは自社のProgID等を消し、拡張子キーの既定値は残します。sparse packageはユーザー単位の登録なので、複数ユーザー環境では各ユーザーへの登録と解除も計画に含めます。

Windows Sandboxを使い、クリーンな環境でインストール→動作→アンインストール→残骸の確認を繰り返します。

最も単純な手段から選び、必要な場合だけ新メニューへの独自コマンド追加へ進む。この順番にすると、対応の規模と、維持すべき登録・実装の範囲を整理できます。

関連記事

関連する相談領域

合同会社小村ソフトでは、業務アプリのファイル関連付け・右クリックメニュー・シェル拡張の設計と実装、Windows 11の新コンテキストメニューへの対応(IExplorerCommand化、sparse packageの導入)、既存インストーラの登録・掃除の見直し、エクスプローラーが重い・落ちる問題の原因調査を扱っています。「その他のオプションを確認に隠れてしまったメニューをどうするか」の方針決めからで構いません。

参考リンク

  1. Microsoft Learn, File Types. 拡張子キーがProgIDを指す構造、OpenWithProgIds、HKLM/HKCU\Software\Classesへの登録の使い分け、関連付け変更後にSHChangeNotify(SHCNE_ASSOCCHANGED)を呼ぶべきこと、アンインストール時にProgIDは削除しつつ拡張子キーの既定値は残すべきことについて。 ↩ ↩2 ↩3 ↩4 ↩5

  2. Microsoft Learn, Choosing a Static or Dynamic Shortcut Menu Method. 要件を満たす最も単純な静的verb方式を選ぶべきこと、IContextMenuが最も強力だが最も複雑で非推奨側に分類されること、IExplorerCommand/IExplorerCommandStateが推奨される方式であることについて。 ↩ ↩2

  3. Microsoft Learn, HKEY_CLASSES_ROOT Key. HKEY_CLASSES_ROOTがHKLM\Software\ClassesとHKCU\Software\Classesを合成したビューであること、ユーザー側の定義がマシン側より優先されること、書き込み時の振り分け規則について。 ↩ ↩2

  4. Microsoft Learn, Windows app defaults platform. 既定アプリの変更がシステム設定UIを通じてのみ行える設計であること、ユーザー設定データが難読化されフィルタードライバー(UCPD.sys)で書き込み保護されること、レジストリベースの変更が非サポートであること、管理環境ではグループポリシー/MDMポリシーを使うことについて。 ↩ ↩2

  5. Windows Developer Blog, Extending the Context Menu and Share Dialog in Windows 11. Windows 11の新コンテキストメニューの設計、IExplorerCommand+アプリ識別による拡張、「開く」「プログラムから開く」の上部配置、複数コマンドのアプリ名付きフライアウトへの集約、従来のIContextMenu拡張が「その他のオプションを確認」(Shift+F10)のWindows 10メニューとして読み込まれることについて。 ↩ ↩2 ↩3

  6. Microsoft Learn, Add a File Explorer context menu command to a packaged desktop app. Windows 11の新コンテキストメニューへの登録がIExplorerCommand実装+windows.comServer+desktop4:FileExplorerContextMenusのマニフェスト宣言で行われること、ItemTypeに*・Directory・Directory\Backgroundを指定できること、DLLのアーキテクチャ一致、メニュー構築メソッドを高速に保つこと、sparse packageによる非パッケージアプリの対応、登録反映にエクスプローラー再起動が必要な場合があること、ファイル関連付けは汎用のメニュー拡張ではないことについて。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8

  7. Microsoft Learn, Grant package identity by packaging with external location. 既存インストーラを変えずに外部ロケーション付きパッケージ(sparse package)を登録してパッケージ識別を得られること、Windows 10バージョン2004以降で利用可能なこと、識別が必須のWindows機能(コンテキストメニュー登録・通知等)が使えるようになることについて。 ↩ ↩2 ↩3

  8. Microsoft Learn, Working with Shell Extensions. シェル拡張ハンドラーの種類、拡張がエクスプローラー(およびシェルをホストするプロセス)に読み込まれるインプロセスCOM DLLであり、クラッシュやハングがExplorer全体に波及すること、ThreadingModel=Apartmentでの登録、シェル拡張より単純な代替手段を先に検討すべきことについて。 ↩ ↩2 ↩3

  9. Microsoft Learn, Guidance for Implementing In-Process Extensions. マネージコードによるインプロセスのシェル拡張実装をMicrosoftが推奨せずサポート対象外とすること、CLRのバージョン競合・再入・オブジェクト寿命の非決定性などの理由、アウトプロセス拡張(プレビューハンドラーやshell\verb\commandからの起動)ではマネージコードが許容されることについて。 ↩ ↩2 ↩3

  10. Microsoft Learn, SHChangeNotify function. ファイル関連付けの変更をシステムへ通知するSHCNE_ASSOCCHANGEDイベントの発行方法と、シェルへ変更を認識させるための使い方について。 ↩ ↩2

  11. Microsoft Learn, Application Registration. App Pathsサブキーによる実行ファイルの登録が推奨されること、Applicationsサブキーの役割、SystemFileAssociationsによるverb登録、既定アプリ変更時のProgIDと関連情報の優先順位について。 ↩

  12. Microsoft Learn, Creating Shortcut Menu Handlers. 静的verbの登録方法、既定verbの決定順序(既定値→最初のverb→Open→Open With)、標準verbの表示名がOSにより供給されること、Extendedによる拡張verb、DDEコマンドとの関連付けが非推奨(Deprecated)であること、64bit環境でのWOW64リダイレクトの注意について。 ↩ ↩2 ↩3

  13. Microsoft Learn, Verbs and File Associations. verbがShellExecuteExでも使われる動詞であること、コマンド文字列でスペースを含み得る要素は引用符で囲む必要があり、”%1”を常に引用符付きで書くべきこと、HKCR\Applications配下への既定手続きの登録について。 ↩

  14. Microsoft Learn, IExplorerCommand interface. GetTitle・GetIcon・GetState・Invoke・EnumSubCommands等のメソッド構成、メソッドがUIスレッドで呼ばれるためネットワーク資源と通信してはならないこと、Windows Vista以降で利用可能であることについて。 ↩

  15. Microsoft Learn, Windows Sandbox. 使い捨ての隔離されたWindows環境を数秒で起動でき、閉じるとすべての変更が破棄されること、ソフトウェアのテストやインストーラの検証に適すること、Pro/Enterprise/Educationで利用できることについて。 ↩

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

Windows 11で自社アプリの右クリックメニューが「その他のオプションを確認」の中にしか出ないのはなぜですか?
Windows 11ではエクスプローラーの右クリックメニューが新旧2階層に分かれたためです。新しいメニューに項目を出せるのは、IExplorerCommandインターフェースを実装し、MSIXパッケージのマニフェストで登録した(=パッケージ識別を持つ)コマンドだけで、従来型のIContextMenuベースのシェル拡張は「その他のオプションを確認」(Shift+F10)で開く旧メニュー側に退避されました。拡張自体が壊れたわけではないので当面はそのまま動きますが、新メニューに出したい場合はIExplorerCommandへの移行と、MSIX化またはsparse packageによる識別の付与が必要です。
インストーラから自社アプリをファイルの既定アプリ(ダブルクリックで開くアプリ)に設定できますか?
できません。既定アプリの選択はユーザーが行う設計になっており、Windowsはシステム設定UI以外からの既定アプリ変更をサポートしていません。ユーザーごとの選択を保持するUserChoice情報は難読化され、フィルタードライバー(UCPD.sys)によるアプリからの書き込み保護も行われています。インストーラにできるのは、ProgIDとverbを登録し、OpenWithProgIdsに自分を追加して「プログラムから開く」の候補に載り、既定アプリ設定画面へユーザーを誘導するところまでです。既定を奪うのではなく、選ばれる準備を整えるのが正しい実装です。
シェル拡張をC#などのマネージコードで書いてもよいですか?
インプロセスで読み込まれるシェル拡張(コンテキストメニューハンドラーやアイコンハンドラーなど)をマネージコードで書くことは、Microsoftが非推奨かつサポート外と明言しています。拡張はエクスプローラーや共通ファイルダイアログを開く任意のアプリのプロセスに読み込まれるため、CLRのバージョン競合や再入、オブジェクト寿命の非決定性が宿主アプリを不安定にするからです。実装はネイティブC++が原則です。一方、verbのcommandで起動される通常のEXEや、別プロセスで動くプレビューハンドラーのようなアウトプロセス拡張であれば、マネージコードでも問題ありません。
sparse package(外部ロケーション付きMSIX)とは何ですか?
アプリ本体のファイルを含まず、マニフェスト(識別情報)だけを持つ小さなMSIXパッケージです。既存のインストーラ(MSI、Inno Setupなど)で普通にインストールしたアプリに対して、Add-AppxPackageの-ExternalLocationでインストール先フォルダーを指すよう登録すると、そのアプリはパッケージ識別を獲得し、Windows 11の新コンテキストメニューへの登録やトースト通知など、識別が必須の機能を使えるようになります。Windows 10バージョン2004以降で利用でき、パッケージには対象マシンで信頼されるコード署名が必要です。配布方式をMSIXへ全面移行せずに新メニュー対応したい場合の現実的な選択肢です。
右クリックメニューの項目が二重に出る、または消えないときはどうすればよいですか?
まず原因の切り分けとして、新メニューと旧メニュー(その他のオプションを確認)のどちらに出ているかを確認します。二重表示は、旧方式のレジストリ登録とMSIXマニフェスト登録が併存しているか、アンインストール時にProgIDや拡張機能のCLSID登録が掃除されずに残っているのが典型です。関連付けを変更した後はSHChangeNotify(SHCNE_ASSOCCHANGED)による通知漏れ、パッケージ登録直後はエクスプローラーの再起動漏れも疑ってください。それでも解決しない場合は、ShellExViewで非Microsoft製の拡張を一時無効化して二分探索すると、原因のDLLを特定できます。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る