In "Writing Windows Shell Extension with .NET Framework 4 (C#, VB.NET) - Part 1: Context Menu Handler", we introduced how to write Windows shell context menu handler using .NET 4:
Lots of developers have this follow-up question: how can I add bitmap icons to those context menu items?
Here you are the directly working code samples from Microsoft All-In-One Code Framework!
Implementation Details
The menu items in the context menu were added in the implementation of IContextMenu.QueryContextMenu:
public int QueryContextMenu(
IntPtr hMenu,
uint iMenu,
uint idCmdFirst,
uint idCmdLast,
uint uFlags)
{
......
// Use either InsertMenu or InsertMenuItem to add menu items.
MENUITEMINFO mii = new MENUITEMINFO();
mii.cbSize = (uint)Marshal.SizeOf(mii);
mii.fMask = MIIM.MIIM_STRING | MIIM.MIIM_FTYPE | MIIM.MIIM_ID | MIIM.MIIM_STATE;
mii.wID = idCmdFirst + IDM_DISPLAY;
mii.fType = MFT.MFT_STRING;
mii.dwTypeData = this.menuText;
mii.fState = MFS.MFS_ENABLED;
if (!NativeMethods.InsertMenuItem(hMenu, iMenu, true, ref mii))
{
return Marshal.GetHRForLastWin32Error();
}
......
}
The MENUITEMINFO structure supports displaying a bitmap next to the menu item text. You just need to add the MIIM_BITMAP mask in MENUITEMINFO.fMask, and point MSENUITEMINFO.hbmpItem to the HBITMAP handle of a 16x16 bitmap. The modified code is as follows.
public int QueryContextMenu(
IntPtr hMenu,
uint iMenu,
uint idCmdFirst,
uint idCmdLast,
uint uFlags)
{
......
// Use either InsertMenu or InsertMenuItem to add menu items.
MENUITEMINFO mii = new MENUITEMINFO();
mii.cbSize = (uint)Marshal.SizeOf(mii);
mii.fMask = MIIM.MIIM_BITMAP | MIIM.MIIM_STRING | MIIM.MIIM_FTYPE |
MIIM.MIIM_ID | MIIM.MIIM_STATE;
mii.wID = idCmdFirst + IDM_DISPLAY;
mii.fType = MFT.MFT_STRING;
mii.dwTypeData = this.menuText;
mii.fState = MFS.MFS_ENABLED;
mii.hbmpItem = this.menuBmp;
if (!NativeMethods.InsertMenuItem(hMenu, iMenu, true, ref mii))
{
return Marshal.GetHRForLastWin32Error();
}
......
}
The "this.menuBmp" is initialized in the constructor of the context menu extension class:
public FileContextMenuExt()
{
// Load the bitmap for the menu item.
Bitmap bmp = Resources.OK; // A 16x16 bmp added to the Resources of the project.
bmp.MakeTransparent(bmp.GetPixel(0, 0));
this.menuBmp = bmp.GetHbitmap();
}
And the handle is released in the destructor of the class:
~FileContextMenuExt()
{
if (this.menuBmp != IntPtr.Zero)
{
NativeMethods.DeleteObject(this.menuBmp);
this.menuBmp = IntPtr.Zero;
}
}
With these modifications, the context menu extension will display menu items with bitmap icons.
NOTE:
1. Do release the HBITMAP handle created by Bitmap.GetHbitmap.
A common mistake is as follows. It will leak the bitmap handle.
// Use either InsertMenu or InsertMenuItem to add menu items.
MENUITEMINFO mii = new MENUITEMINFO();
mii.cbSize = (uint)Marshal.SizeOf(mii);
mii.fMask = MIIM.MIIM_BITMAP | MIIM.MIIM_STRING | MIIM.MIIM_FTYPE |
MIIM.MIIM_ID | MIIM.MIIM_STATE;
mii.wID = idCmdFirst + IDM_DISPLAY;
mii.fType = MFT.MFT_STRING;
mii.dwTypeData = this.menuText;
mii.fState = MFS.MFS_ENABLED;
mii.hbmpItem = Resources.OK.GetHbitmap(); // This will leak the bitmap handle!
if (!NativeMethods.InsertMenuItem(hMenu, iMenu, true, ref mii))
{
return Marshal.GetHRForLastWin32Error();
}
2. Do not set MFT_BITMAP in MENUITEMINFO.fType.
The MFT_BITMAP type is for a different bitmap purpose. It displays the menu item using a bitmap. The low-order word of the dwTypeData member is the bitmap handle. For example,
No comments:
Post a Comment