4

.NET Framework 4アプリでは、ファイルシステムの一部ではないファイル、フォルダー、その他のものを表示します。ファイルとフォルダーについては、MSDNのこのコードのおかげで、そのアイテムのWindowsシェルコンテキストメニューを表示することができました。(それでもCarbonite Shell Extensionを表示できませんが、逸脱します。)

私の苦労は、シェルのコンテキストメニューに自分のサブメニューを追加することです。私の研究はすべて、いわゆるシェル拡張機能をほのめかしています。これは、私が正しく理解していれば、システム全体の変更です。アプリ内からアクセスした場合にのみ、シェルのコンテキストメニューに追加したいと思います。

ShowContextMenu確かに、ストローをつかんで、呼び出した直後に、上記のクラスのメソッドに次のものを追加しようとしましたQueryContextMenu

var mii = new MENUITEMINFO();
mii.cbSize = Marshal.SizeOf(mii);
mii.fMask = MIIM.SUBMENU | MIIM.STRING | MIIM.FTYPE | MIIM.ID;
mii.fType = MFT.BYPOSITION;
mii.wID = 0;
mii.hSubMenu = subMenu.Handle;
mii.dwTypeData = "Test";
var success = InsertMenuItem(pMenu, 0, true, ref mii);

しかし、「成功」はありません。(subMenuこれはSystem.Windows.Forms.ContextMenuStrip私が以前に作成したものです。)

私の質問は次のとおりです。

  1. 私が試みていることは、シェル拡張機能の作成とは異なるということは正しいですか?

  2. この投稿によると、これはまだマネージコードからの危険な活動と見なされていますか?

  3. 実際にこれをどのように行うのですか?

4

1 に答える 1

1

OK、アプリだけでカスタムメニュー項目をWindowsシェルのコンテキストメニューに追加できるようです(Windowsシステム全体に影響を与えることは何もする必要はありません)。以下は私がしたことです。この回答は、最初に述べたMSDNコードのコンテキストで解釈する必要があることに注意してください。ここに再びリンクがあります:

MSDNのShellContextMenuクラス

そのクラスでは、具体的には、メソッドShowContextMenuはへの呼び出しですQueryContextMenu。その目的は、メニューに項目を追加することです。この場合、コンテキストメニューが表示されるファイル/フォルダーに適切なWindowsシェルメニュー項目です。その呼び出しの後、サブメニューとセパレーターを追加するために次のコードを追加しました。

var mii = new MENUITEMINFO();
mii.fMask = MIIM.SUBMENU | MIIM.STRING | MIIM.FTYPE | MIIM.ID | MIIM.STATE | MIIM.BITMAP;
mii.fState = MFS.ENABLED;
mii.fType = MFT.STRING;
mii.wID = 0;    // Application-defined value that identifies the menu item.
mii.hSubMenu = **subMenu**.Handle;
mii.dwTypeData = Program.ShortTitle;
mii.cch = mii.dwTypeData.Length;
var bmp = new System.Drawing.Icon(ac.Properties.NeutralResources.MyAppIcon, 16, 16).ToBitmap();
this.hMyAppSubmenuIcon = bmp.GetHbitmap();
mii.hbmpItem = this.hMyAppSubmenuIcon;
mii.cbSize = Marshal.SizeOf(typeof(MENUITEMINFO));
var success = InsertMenuItem(pMenu, 0, true, ref mii);

mii = new MENUITEMINFO();
mii.fMask = MIIM.FTYPE;
mii.fType = MFT.SEPARATOR;
mii.cbSize = Marshal.SizeOf(mii);
success = InsertMenuItem(pMenu, 1, true, ref mii);

subMenuはタイプSystem.Windows.Forms.ContextMenuです。このように、コンテキストメニュー全体は、管理されたメニュー項目と管理されていないメニュー項目の両方で構成される、いくぶんハイブリッドです。これまでのところ、これに問題はありません。これは、以下に説明するように、2種類のメニュー項目の選択の処理を異なる方法で実行する必要があることを意味します...

管理項目をメニューに挿入した後、ShowContextMenuメソッドはを呼び出しますTrackPopupMenu。シェルメニュー項目の場合、すでに作成されているクラスがそれらの選択を処理します。私自身のメニュー項目については、Windows API関数であるため、追加の手順を実行する必要 がありました。これは、管理対象サブメニュー項目のイベントTrackPopupMenuではうまく機能しません。Clickイベントハンドラーをサブメニュー項目に接続できClickますが、シェルコンテキストメニューから選択した場合、Clickイベントは発生しません。Click管理メニューを単独で表示することもあるので、私はまだそれらを接続しました。

シェルのコンテキストメニューからの管理対象メニュー項目の選択に応じてアクションを実行するために、選択TrackPopupMenuされたメニュー項目のリソースIDである戻り値のを使用しました。それは物事が少し回り道をしたところです。管理コンテキストメニューを作成する場合、各メニュー項目にはインデックスがあります。これは、メニュー項目のリソースIDを返すWindowsAPI関数GetMenuItemIDで使用できます。管理対象クラスから継承し、ContextMenuをカプセル化しDictionaryて、このリソースIDからメニュー項目にマップし、後でを呼び出した直後に使用できるようにしましたTrackPopupMenu。私の目的では、ハンドラーを呼び出すために必要なのはこれだけです。これは、アプリでコマンドパターンを使用し、コマンドオブジェクトをメニュー項目のに保存したためです。Tag メニューを作成するときのプロパティ。(辞書から正しいメニュー項目が表示されたら、からコマンドオブジェクトを抽出することで、対応するハンドラーを実行できましたTag)。

これは数日間正常に実行されています。管理されていないリソースのように、クリーンアップする必要のある穴を誰かが見つけた場合は、そのことを伝えてください。

于 2012-07-15T23:16:26.377 に答える