仅在我的应用程序中添加到shell上下文菜单

时间:2012-07-10 04:29:33

标签: c# menu contextmenu windows-shell

在我的.NET Framework 4应用程序中,我显示文件,文件夹和其他不属于文件系统的东西。对于文件和文件夹,我设法显示该项目的Windows Shell上下文菜单,感谢this code on MSDN。 (它仍然无法显示Carbonite Shell扩展,但我离题了。)

我的目标是将自己的子菜单添加到Shell上下文菜单中。我的所有研究都提到了所谓的Shell Extensions ,如果我理解的话,这是一个全系统的变化。我只想在从我的应用程序中访问它时添加到Shell上下文菜单

抓住吸管,不可否认,我尝试在上述课程“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. 我是否认为我所尝试的与创建Shell扩展不同?

  2. 根据this post,这仍然被认为是托管代码的危险活动吗?

  3. 如何实际做到这一点?

1 个答案:

答案 0 :(得分:1)

好的,看起来 可以将自定义菜单项添加到Windows Shell上下文菜单中,就在您的应用程序中(无需执行任何影响整个Windows系统的操作)。以下是我的所作所为。请记住,此答案应在首次提到的MSDN代码的上下文中进行。这是链接:

ShellContextMenu class on MSDN

在该类中,具体来说,方法ShowContextMenu是对QueryContextMenu的调用,我学习的目的是用菜单填充菜单 - 在这种情况下,相应的Windows Shell菜单项对于要显示其上下文菜单的文件/文件夹。在那次调用之后,我添加了以下代码来添加子菜单和分隔符:

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。通过这种方式,整个上下文菜单在某种程度上是混合的,包括托管和非托管菜单项。到目前为止,我没有看到这个问题;它只是意味着处理两种菜单项的选择必须以不同的方式完成,如下所述...

将托管项目插入菜单后,ShowContextMenu方法会调用TrackPopupMenu。对于Shell菜单项,已编写的类负责处理它们的选择。对于我自己的菜单项,我不得不采取额外的步骤,因为TrackPopupMenu是一个Windows API函数,因此它对托管子菜单项“Click事件不能很好地工作。您可以将Click事件处理程序连接到子菜单项,但是当从Shell上下文菜单中选择它们时,它们的Click事件不会触发。我确实仍然连接他们的Click,因为有时我只是自己显示我的托管菜单。

为了响应从Shell上下文菜单中选择托管菜单项而采取操作,我使用了TrackPopupMenu的返回值,它是所选菜单项的资源ID。这就是事情变得有点迂回的地方。当创建托管上下文菜单时,每个菜单项都有一个索引。您可以使用Windows API函数GetMenuItemID,它返回菜单项的资源ID。我从托管ContextMenu类继承并封装了一个Dictionary,它帮助我从此资源ID映射到菜单项,稍后在调用TrackPopupMenu之后使用。出于我的目的,这就是调用处理程序所需的全部因为在我的应用程序中,我使用命令模式并在创建菜单时将命令对象存储在菜单项的Tag属性中。 (一旦字典给了我正确的菜单项,我就可以通过从Tag中提取命令对象来执行相应的处理程序。

这已经好几天了。如果有人看到漏洞,比如我应该清理的非托管资源,请提及。