「Windowsの右クリックメニューから複数ファイルをまとめて開く」の版間の差分

Notion-MW
Notion-MW
 
(同じ利用者による、間の10版が非表示)
10行目: 10行目:
まず、Windows11に移行すると右クリックメニューの項目数が大幅に削られており、とても使いにくいので、Windows10までの仕様に戻す必要がある。[https://pc-karuma.net/right-click-context-menu-back-on-windows-11 Windows 11 &#45; 右クリックメニューを旧仕様に戻す方法 &#45; PC設定のカルマ]などに従って修正しよう。コマンド例は以下。これはユーザーごとの設定なので、<strong>管理者権限は不要</strong>である。
まず、Windows11に移行すると右クリックメニューの項目数が大幅に削られており、とても使いにくいので、Windows10までの仕様に戻す必要がある。[https://pc-karuma.net/right-click-context-menu-back-on-windows-11 Windows 11 &#45; 右クリックメニューを旧仕様に戻す方法 &#45; PC設定のカルマ]などに従って修正しよう。コマンド例は以下。これはユーザーごとの設定なので、<strong>管理者権限は不要</strong>である。


<pre class="dummy_str_javascript">reg add &quot;HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32&quot; /f /ve</pre>
<syntaxhighlight lang="javascript">reg add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve</syntaxhighlight>
ファイルを開く操作ならダブルクリックでできるわけで、それでもあえてファイルを右クリックするユーザーの層を考えれば、使用頻度の高いメニューに絞る必要がないことは明らかである。右クリックメニューは動作が重いという問題点も指摘されてきたが、それなら項目数を削る以外の方法でパフォーマンスを改善するのが筋だろう。そもそも、Windows 11の右クリックメニューもそれほど快適な動作ではない。
ファイルを開く操作ならダブルクリックでできるわけで、それでもあえてファイルを右クリックするユーザーの層を考えれば、使用頻度の高いメニューに絞る必要がないことは明らかである。右クリックメニューは動作が重いという問題点も指摘されてきたが、それなら項目数を削る以外の方法でパフォーマンスを改善するのが筋だろう。そもそも、Windows 11の右クリックメニューもそれほど快適な動作ではない。


31行目: 31行目:
これはどうやらClipchampのメニューが悪いらしく、[https://www.elevenforum.com/t/add-or-remove-edit-with-clipchamp-context-menu-in-windows-11.6882/ Add or Remove Edit with Clipchamp Context Menu in Windows 11 Tutorial | Windows 11 Forum]([https://www.elevenforum.com/t/clipchamp-context-menu-removal.6150/ Clipchamp context menu removal | Windows 11 Forum]に書いてあった)や[https://www.naporitansushi.com/clipchamp-context-menu-disable/# Windowsの右クリックの「Clipchampで編集」を削除する方法 | ナポリタン寿司のPC日記]に書いてある通り、Clipchampのメニューを非表示にすると治る。コマンド例は以下。
これはどうやらClipchampのメニューが悪いらしく、[https://www.elevenforum.com/t/add-or-remove-edit-with-clipchamp-context-menu-in-windows-11.6882/ Add or Remove Edit with Clipchamp Context Menu in Windows 11 Tutorial | Windows 11 Forum]([https://www.elevenforum.com/t/clipchamp-context-menu-removal.6150/ Clipchamp context menu removal | Windows 11 Forum]に書いてあった)や[https://www.naporitansushi.com/clipchamp-context-menu-disable/# Windowsの右クリックの「Clipchampで編集」を削除する方法 | ナポリタン寿司のPC日記]に書いてある通り、Clipchampのメニューを非表示にすると治る。コマンド例は以下。


<pre class="dummy_str_javascript">reg add &quot;HKCU\Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Blocked&quot; /v {8AB635F8-9A67-4698-AB99-784AD929F3B4} /f</pre>
<syntaxhighlight lang="javascript">reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Blocked" /v {8AB635F8-9A67-4698-AB99-784AD929F3B4} /f</syntaxhighlight>
* HKLMでも設定できる。また、「デバイス キャスト」を非表示にする場合はUUIDを<code>&#123;7AD84985&#45;87B4&#45;4a16&#45;BE58&#45;8B72A5B390F7&#125;</code>に変える。
 
Clipchampを表示したまま順番を治す方法は不明だが、自分でメニューを作ればできるかもしれない。Clipchampのメニューの実装に使われていると思われるIContextMenuについては後でも述べているのでそちらも参照。おそらくClipchampによるこのインターフェースの実装にバグがあるためにこのような挙動をしているのであろう。
Clipchampを表示したまま順番を治す方法は不明だが、自分でメニューを作ればできるかもしれない。Clipchampのメニューの実装に使われていると思われるIContextMenuについては後でも述べているのでそちらも参照。おそらくClipchampによるこのインターフェースの実装にバグがあるためにこのような挙動をしているのであろう。


99行目: 101行目:
拡張子ごとの設定は<code>HKEY_CLASSES_ROOT\SystemFileAssociations</code>にある(編集時は<code>HKEY_CURRENT_USER\Software\Classes\SystemFileAssociations</code>を使うのがいいだろう)(比較的新しいWindowsだと<code>HKEY_CURRENT_USER\Software\Classes\SystemFileAssociations</code>キー自体が存在しないことがあるが、自分で作ればちゃんと動作する)。<code>command</code>キーは<code>HKEY_CURRENT_USER\Software\Classes\SystemFileAssociations\.xxx\shell\yourcommandname\command</code>のような場所に作られることになる。
拡張子ごとの設定は<code>HKEY_CLASSES_ROOT\SystemFileAssociations</code>にある(編集時は<code>HKEY_CURRENT_USER\Software\Classes\SystemFileAssociations</code>を使うのがいいだろう)(比較的新しいWindowsだと<code>HKEY_CURRENT_USER\Software\Classes\SystemFileAssociations</code>キー自体が存在しないことがあるが、自分で作ればちゃんと動作する)。<code>command</code>キーは<code>HKEY_CURRENT_USER\Software\Classes\SystemFileAssociations\.xxx\shell\yourcommandname\command</code>のような場所に作られることになる。


また、全てのファイルを対象にするメニューは<code>HKEY_CLASSES_ROOT\SystemFileAssociations\&#42;</code>、フォルダを右クリックしたときのメニューは<code>HKEY_CLASSES_ROOT\Directory</code>、ドライブ(C&#58;\など)を右クリックしたときのメニューは<code>HKEY_CLASSES_ROOT\Drive</code>、フォルダ(・ドライブ)内で何もないところを右クリックしたときのメニューは<code>HKEY_CLASSES_ROOT\Directory\Background</code>以下でそれぞれ管理されている。
また、全てのファイルを対象にするメニューは<code>HKEY_CLASSES_ROOT\SystemFileAssociations\&#42;</code>、フォルダを右クリックしたときのメニューは<code>HKEY_CLASSES_ROOT\Directory</code>、ドライブ(C&#58;\など)を右クリックしたときのメニューは<code>HKEY_CLASSES_ROOT\Drive</code>、フォルダ(・ドライブ)の背景(何もないところ)を右クリックしたときのメニューは<code>HKEY_CLASSES_ROOT\Directory\Background</code>以下でそれぞれ管理されている。また、<code>HKEY_CLASSES_ROOT\AllFilesystemObjects</code>というのもあり、これはディレクトリとファイルの両方に適用される(ドライブやフォルダ背景には影響なし)。
 
* 一覧は[https://learn.microsoft.com/ja-jp/windows/win32/shell/reg-shell-exts ここ]かな?


<span id="複数種類に一括で追加"></span>
<span id="複数種類に一括で追加"></span>
153行目: 157行目:
動作確認できたサンプルとしては、[https://github.com/microsoft/Windows-classic-samples/tree/main/Samples/Win7Samples/winui/shell/appshellintegration/NonDefaultDropMenuVerb https&#58;//github.com/microsoft/Windows&#45;classic&#45;samples/tree/main/Samples/Win7Samples/winui/shell/appshellintegration/NonDefaultDropMenuVerb]はIContextMenuを使って実装されており、dllをビルドしてCLSIDのInProcServer32でそれを指定するとちゃんと右クリックメニューが追加される。
動作確認できたサンプルとしては、[https://github.com/microsoft/Windows-classic-samples/tree/main/Samples/Win7Samples/winui/shell/appshellintegration/NonDefaultDropMenuVerb https&#58;//github.com/microsoft/Windows&#45;classic&#45;samples/tree/main/Samples/Win7Samples/winui/shell/appshellintegration/NonDefaultDropMenuVerb]はIContextMenuを使って実装されており、dllをビルドしてCLSIDのInProcServer32でそれを指定するとちゃんと右クリックメニューが追加される。


また、メニューを追加する関数であるQueryContextMenuが呼ばれる時点で、引数となっているファイルの情報がわかる(Initialize関数においてIDataObjectが渡されているのでそれをクラスのフィールドなどとして持っておけばよい)ので、特定の拡張子のファイルのみに対してメニューを表示することもできる。もちろんファイルの内容まで読み取ってからメニューを表示するといったこともできるが、そこまですると右クリックするだけで動作が重くなるといった副作用が大きくなるのでやめた方が無難だろう。またエラーが発生した場合はexplorer自体が強制終了することもあり、全体的に実装は慎重に行ったほうがよい。
また、メニューを追加する関数であるQueryContextMenuが呼ばれる時点で、引数となっているファイルの情報がわかる(Initialize関数においてIDataObjectが渡されているのでそれをクラスのフィールドなどとして持っておけばよい)ので、特定の拡張子のファイルのみに対してメニューを表示することもできる。もちろんファイルの内容まで読み取ってからメニューを表示するといったこともできるが、そこまですると右クリックするだけで動作が重くなるといった副作用が大きくなるのでやめた方が無難だろう。ただ、スタートメニューへのピン留め<code>&#123;a2a9545d&#45;a0c2&#45;42b4&#45;9708&#45;a0b2badd77c8&#125;</code>やPDF XChange Editor(9.3や10.2.1で確認)のメニューは実際にそのような挙動をする(余談だが、InfoTipの表示もexplorerが操作しづらくなる原因なのでshowinfotipを0にしたほうがいい)(サムネイルなどはバックグラウンドで並列に走るので操作にはあまり影響がない)。またエラーが発生した場合はexplorer自体が強制終了することもあり、全体的に実装は慎重に行ったほうがよい。


==== コード例 ====
==== コード例 ====
159行目: 163行目:
拡張子が.tで始まるファイル(&#42;.txt, &#42;.ttfなど)のみにメニューを追加するサンプル(から抜粋)。
拡張子が.tで始まるファイル(&#42;.txt, &#42;.ttfなど)のみにメニューを追加するサンプル(から抜粋)。


<pre class="dummy_str_visual_basic">IFACEMETHODIMP CNonDefaultDropMenuVerb::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT /*idCmdLast*/, UINT /*uFlags*/)
<syntaxhighlight lang="c++">IFACEMETHODIMP CNonDefaultDropMenuVerb::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT /*idCmdLast*/, UINT /*uFlags*/)
{
{
     FORMATETC fmte = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
     FORMATETC fmte = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
     STGMEDIUM medium;
     STGMEDIUM medium;
     HRESULT hr = _pdtobj-&gt;GetData(&amp;fmte, &amp;medium);
     HRESULT hr = _pdtobj->GetData(&fmte, &medium);
     if (SUCCEEDED(hr))
     if (SUCCEEDED(hr))
     {
     {
170行目: 174行目:
         DragQueryFile(hdrop, 0, szFile, ARRAYSIZE(szFile));
         DragQueryFile(hdrop, 0, szFile, ARRAYSIZE(szFile));
         const WCHAR* ext = wcsrchr(szFile, L'.');
         const WCHAR* ext = wcsrchr(szFile, L'.');
         ReleaseStgMedium(&amp;medium);
         ReleaseStgMedium(&medium);
         if (ext &amp;&amp; *(ext+1) != L't') {
         if (ext && *(ext+1) != L't') {
             return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);  // Add nothing
             return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);  // Add nothing
         }
         }
189行目: 193行目:


     return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (USHORT)(2));  // indicate that we added 2 verbs.
     return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (USHORT)(2));  // indicate that we added 2 verbs.
}</pre>
}</syntaxhighlight>
* 特定の拡張子に対して追加できるのは以下で知った
* 特定の拡張子に対して追加できるのは以下で知った
** できるという情報<br />
** できるという情報<br />
216行目: 220行目:
<ul>
<ul>
<li><p>Windows 11の右クリックメニューに追加してくれるソフト</p>
<li><p>Windows 11の右クリックメニューに追加してくれるソフト</p>
<p>[https://github.com/ikas-mc/ContextMenuForWindows11 link_preview]</p>
<p>[https://github.com/ikas-mc/ContextMenuForWindows11 https://github.com/ikas-mc/ContextMenuForWindows11]</p>
<p>フォルダ背景を右クリックしたメニューに追加できない([https://github.com/ikas-mc/ContextMenuForWindows11/issues/44 https://github.com/ikas-mc/ContextMenuForWindows11/issues/44])(いや、使ってみたら普通にできてるっぽい?)、アプリ1つにつき1メニューしか追加できない([https://github.com/ikas-mc/ContextMenuForWindows11/issues/45 https://github.com/ikas-mc/ContextMenuForWindows11/issues/45])(これはWindows側がそういう仕様っぽいので厳しそう)</p></li>
<p>フォルダ背景を右クリックしたメニューに追加できない([https://github.com/ikas-mc/ContextMenuForWindows11/issues/44 https://github.com/ikas-mc/ContextMenuForWindows11/issues/44])(いや、使ってみたら普通にできてるっぽい?)、アプリ1つにつき1メニューしか追加できない([https://github.com/ikas-mc/ContextMenuForWindows11/issues/45 https://github.com/ikas-mc/ContextMenuForWindows11/issues/45])(これはWindows側がそういう仕様っぽいので厳しそう)</p></li>
<li><p>Microsoftの関連するサンプル<br />
<li><p>Microsoftの関連するサンプル<br />
230行目: 234行目:
まずは、COMを用いて実装するという方法がある。基本的にはこちらが綺麗な解決策である。
まずは、COMを用いて実装するという方法がある。基本的にはこちらが綺麗な解決策である。


IExecuteCommandというインターフェースを具体的に実装している[https://learn.microsoft.com/en-us/windows/win32/shell/samples-executecommandverb Microsoftのサンプル]があったので、それを参考に、「任意コマンドを引数にとり、取得したファイル・フォルダの情報をそのコマンドの標準入力にUTF&#45;8で送信する」というプログラムを作成した。
IExecuteCommandというインターフェースを具体的に実装している[https://learn.microsoft.com/en-us/windows/win32/shell/samples-executecommandverb Microsoftのサンプル]があったので、それを参考に、「取得したファイル・フォルダの情報を引数または標準入力として渡しつつ指定されたコマンドを起動する」というプログラムを作成した。


[https://github.com/ge9/ExecuteCommand-Pipe link_preview]
[https://github.com/ge9/ExecuteCommand-Pipe https://github.com/ge9/ExecuteCommand-Pipe]


COMを使っていることからわかるように、コマンドラインを介さず直接Explorerからデータが送られてくるので、他の方法に共通してみられるパス長さやファイル個数の制限が(事実上)皆無であり、非常に強力である。
COMを使っていることからわかるように、コマンドラインを介さず直接Explorerからデータが送られてくるので、他の方法に共通してみられるパス長さやファイル個数の制限が(事実上)皆無であり、非常に強力である。
278行目: 282行目:
README.mdにもあるが起動に用いる基本的な構文(レジストリに登録する値)は以下のようである(※ここでは64bit版を使うものとして説明しているが、32bit版でも全く同様)。
README.mdにもあるが起動に用いる基本的な構文(レジストリに登録する値)は以下のようである(※ここでは64bit版を使うものとして説明しているが、32bit版でも全く同様)。


<pre class="dummy_str_c">&quot;C:\path\to\singleinstance_x64.exe&quot; &quot;%1&quot; &quot;C:\Program Files\path\to\app.exe&quot; &quot;$files&quot; --si-timeout 1000 --option-to-app-1 --option-to-app-2</pre>
<syntaxhighlight lang="c">"C:\path\to\singleinstance_x64.exe" "%1" "C:\Program Files\path\to\app.exe" "$files" --si-timeout 1000 --option-to-app-1 --option-to-app-2</syntaxhighlight>
&quot;C&#58;\path\to\singleinstance_x64.exe&quot;、&quot;%1&quot;、&quot;C&#58;\Program Files\path\to\app.exe&quot;、&quot;$files&quot;の順番はおそらくこの通りである必要がある。その後にあるものはapp.exeにオプションとしてそのまま渡されるが、<strong><code>&#45;&#45;si&#45;timeout n</code></strong><strong>に限り</strong>、singleinstance_x64.exeが解釈し、app.exeに渡されない。このオプションはSingleInstance&#45;Launcherに対して次のファイルが渡されてくるのを待つタイムアウト期間をミリ秒で指定するものである。短すぎると、右クリックメニューの処理が遅い場合に途中で打ち切られてしまう可能性がある。長すぎると、その期間待つまでapp.exeは呼ばれないため、タイムラグが長く不便に感じる可能性がある。特に動作が重いPCでなければ1000(1秒)くらいにしておけば十分だろう。もう少し短くてもいいかもしれない。
&quot;C&#58;\path\to\singleinstance_x64.exe&quot;、&quot;%1&quot;、&quot;C&#58;\Program Files\path\to\app.exe&quot;、&quot;$files&quot;の順番はおそらくこの通りである必要がある。その後にあるものはapp.exeにオプションとしてそのまま渡されるが、<strong><code>&#45;&#45;si&#45;timeout n</code></strong><strong>に限り</strong>、singleinstance_x64.exeが解釈し、app.exeに渡されない。このオプションはSingleInstance&#45;Launcherに対して次のファイルが渡されてくるのを待つタイムアウト期間をミリ秒で指定するものである。短すぎると、右クリックメニューの処理が遅い場合に途中で打ち切られてしまう可能性がある。長すぎると、その期間待つまでapp.exeは呼ばれないため、タイムラグが長く不便に感じる可能性がある。特に動作が重いPCでなければ1000(1秒)くらいにしておけば十分だろう。もう少し短くてもいいかもしれない。


%1や$filesの両側にダブルクォーテーションがないと、空白を含むファイル名を正しく扱えない。GitHubのサンプルでは付いていないものもあるので注意。
%1や$filesの両側にダブルクォーテーションがないと、空白を含むファイル名を正しく扱えない。GitHubのサンプルでは付いていないものもあるので注意。
[[Category:IT]][[Category:Windows]]{{#seo:|title={{FULLPAGENAME}} - Turgenev's Wiki}}
[[Category:IT]][[Category:Windows]]{{#seo:|title={{FULLPAGENAME}} - Turgenev's Wiki}}