Windows Shell扩展系列文章 2 - .NET 4为扩展的Windows Shell上下文菜单项添加位图图标
2011-03-29 17:08 Jialiang 阅读(2138) 评论(3) 收藏 举报在“Windows Shell扩展系列文章 1 - .NET 4 编写Windows Shell上下文菜单扩展”一文中,我们介绍了如何使用.NET 4编写VC#或VB.NET代码创建Windows Shell上下文菜单扩展。

 
示例代码下载:C#, VB.NET

实现细节
Windows Shell上下文菜单中的菜单项是通过实现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(); 
    } 
    ...... 
}
 
其中MENUITEMINFO结构可支持在菜单项文字旁添加位图图标。你只需要为MENUITEMINFO.fMask添加上MIIM_BITMAP,并将MSENUITEMINFO.hbmpItem指向一16x16的位图句柄。修改后的代码示例如下:
 
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(); 
    } 
    ...... 
}
 
"this.menuBmp" 在该上下文菜单扩展类的构造函数内被初始化:
 
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(); 
}
 
然后在析构函数内释放该句柄:
 
~FileContextMenuExt() 
{ 
    if (this.menuBmp != IntPtr.Zero) 
    { 
        NativeMethods.DeleteObject(this.menuBmp); 
        this.menuBmp = IntPtr.Zero; 
    } 
}
 
有了这些修改,上下文菜单项就会显示你所指定的位图图标。

注意
1. 务必将Bitmap.GetHbitmap返回的位图在该类对象被析构的时候释放掉,否则将造成句柄溢出。
 
下述示例代码演示了一个开发人员常犯的错误:
 
    // 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. 务必不要将MENUITEMINFO.fType 设置为MFT_BITMAP。 MFT_BITMAP 是为另一个目的而设计的。如果你想把menu item直接做成一张图片,那就设置MFT_BITMAP。效果如下:

                    
                
                
            
        
浙公网安备 33010602011771号