Microsoft All-In-One Code Framework

The Microsoft All-In-One Code Framework is a free, centralized code sample library provided by the Microsoft Community team. Our goal is to provide typical code samples for all Microsoft development technologies.

Writing Windows Shell Extension with .NET Framework 4 (C#, VB.NET) - Part 4: Context Menu Handler with Menu-item Bitmaps

Writing Windows Shell Extension with .NET Framework 4 (C#, VB.NET) - Part 4: Context Menu Handler with Menu-item Bitmaps

Rate This
  • Comments 4

[Updated on 2011-4-2: In .NET 4, with the ability to have multiple runtimes in process with any other runtime, writing managed shell extensions becomes possible.  However, Microsoft has not fully tested all of the scenarios involved with managed shell extensions and has not determined whether it will support managed shell extensions for the long term.  Therefore, Microsoft will not support managed shell extensions and recommends against writing them.. I will update this blog article if it becomes officially supported in future.]

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,

Leave a Comment
  • Please add 3 and 1 and type the answer here:
  • Post
  • Great post, thanks. I had already implemented my own handler based on Pt.1, found out how/where to show an image, and was just about to ask how/where to destroy the bmp handle to avoid a memory leak.

  • When I follow your example, it puts the bitmap in a different column than any of the other context menu items. There is no space between the image and the start of the menuitem text where there should be.  Would anyone happen to know why, I'm trying to run this on XP.

  • different column than any of the other context menu item images*

  • How do I download the sample code for this one simple example?

Page 1 of 1 (4 items)