How to show menu item with icon AND text in WinForms system menu
Asked Answered
F

1

4

While adapting the answer of ygoe, I discovered that it's possible to add an icon to the menu.

I tried and succeeded in doing so by using this code for a text-only item:

var item = new MenuItemInfo
{
  cbSize = (uint)Marshal.SizeOf(typeof(MenuItemInfo)),
  cch = (uint)label.Length,
  dwTypeData = label,
  fMask = 0x2 | 0x10, // MIIM_ID | MIIM_TYPE
  fState = 0x0,       // MFS_ENABLED
  fType = 0x0,        // MFT_STRING
  wID = id
};
InsertMenuItem(hMenu, 0, true, ref item);

For an icon-based item, I changed fMask and added hbmpItem like this:

var item = new MenuItemInfo
{
  cbSize = (uint)Marshal.SizeOf(typeof(MenuItemInfo)),
  cch = (uint)label.Length,
  dwTypeData = label,
  fMask = 0x80 | 0x2 | 0x100, // MIIM_BITMAP | MIIM_ID | MIIM_FTYPE
  fState = 0x0,               // MFS_ENABLED
  fType = 0x0,                // MFT_STRING
  hbmpItem = hIcon            // handle provided by Bitmap.GetHbitmap()
  wID = id
};
InsertMenuItem(hMenu, 0, true, ref item);

But by doing so, the label's text is gone - only the icon is shown, no matter which combinations of fMask and fType I try. 😞

Please, help me figuring out what I'm doing wrong.

Foti answered 1/3, 2018 at 18:37 Comment(8)
I think you need to set both MIIM_BITMAP and MIIM_STRING. browse the documentation, there was a lot of merging and obsolete combinations going on so it is no longer trivial to guess the correct combination of flags and values. – Obstreperous
Set fMask = MIIM_FTYPE and set fType = MFT_BITMAP | MFT_STRING – Within
You also must declare dwTypeData as IntPtr since the string needs to survive past the pinvoke call. Right now you have a dangling pointer bug that can crash your program or corrupt the menu randomly. Use Marshal.StringToHGlobalUni(). – Cantabile
Thanks for your suggestions, guys! However, none of them worked: @HansPassant Changing dwTypeData as you suggested results in only the first letter being shown. @MarkBenningfield Doing so, shows no item at all. Also, the docs (linked to by @dlatikay & read by me before posting this question) state MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values **cannot** be combined with one another and Set fMask to MIIM_TYPE to use fType, too. fType is used only if fMask has a value of MIIM_FTYPE. ` See edited question for details. Any help is still greatly appreciated! πŸ™ – Foti
Your declarations use CharSet.Ansi, the default. That is not good, use [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)] on the struct declaration and use CharSet in the [DllImport] declaration. Note that this struct is wrapped in .NET, have a look-see. – Cantabile
There is a limitation with the olden menu support, you get a bitmap or text, not both. Working around that requires ownerdraw or SetMenuItemBitmaps(), shown here. – Cantabile
@HansPassant thanks for the additional help. That fixed it all. It's a pity that NativeMethods is an internal class, because otherwise I needn't to declare MenuItemInfo myself. Thanks for pointing out the limitation. I'll look into SetMenuItemBitmaps(). – Foti
@HansPassant since your suggestions got it working for me, I'd like to ask for an answer that I can in turn accept. If you decline, I'll write the answer myself - but I'd love to give credit where credit is due. – Foti
C
7

These are the declarations (all come from the related MSDN Docs):

MSDN Documentation:
The main function used: InsertMenuItem()
The MENUITEMINFO structure.
The System Menu Handle is retrieved using GetSystemMenu()

As a curiosity, these are not referenced on PInvoke.net.

[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool InsertMenuItem(IntPtr hMenu, uint uItem, bool fByPosition, ref MenuItemInfo lpmii);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);


public enum MenuItemInfo_fMask : uint
{
    MIIM_BITMAP = 0x00000080,           //Retrieves or sets the hbmpItem member.
    MIIM_CHECKMARKS = 0x00000008,       //Retrieves or sets the hbmpChecked and hbmpUnchecked members.
    MIIM_DATA = 0x00000020,             //Retrieves or sets the dwItemData member.
    MIIM_FTYPE = 0x00000100,            //Retrieves or sets the fType member.
    MIIM_ID = 0x00000002,               //Retrieves or sets the wID member.
    MIIM_STATE = 0x00000001,            //Retrieves or sets the fState member.
    MIIM_STRING = 0x00000040,           //Retrieves or sets the dwTypeData member.
    MIIM_SUBMENU = 0x00000004,          //Retrieves or sets the hSubMenu member.
    MIIM_TYPE = 0x00000010,             //Retrieves or sets the fType and dwTypeData members.
                                        //MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
}

public enum MenuItemInfo_fType : uint
{
    MFT_BITMAP = 0x00000004,            //Displays the menu item using a bitmap. The low-order word of the dwTypeData member is the bitmap handle, and the cch member is ignored.
                                        //MFT_BITMAP is replaced by MIIM_BITMAP and hbmpItem.
    MFT_MENUBARBREAK = 0x00000020,      //Places the menu item on a new line (for a menu bar) or in a new column (for a drop-down menu, submenu, or shortcut menu). For a drop-down menu, submenu, or shortcut menu, a vertical line separates the new column from the old.
    MFT_MENUBREAK = 0x00000040,         //Places the menu item on a new line (for a menu bar) or in a new column (for a drop-down menu, submenu, or shortcut menu). For a drop-down menu, submenu, or shortcut menu, the columns are not separated by a vertical line.
    MFT_OWNERDRAW = 0x00000100,         //Assigns responsibility for drawing the menu item to the window that owns the menu. The window receives a WM_MEASUREITEM message before the menu is displayed for the first time, and a WM_DRAWITEM message whenever the appearance of the menu item must be updated. If this value is specified, the dwTypeData member contains an application-defined value.
    MFT_RADIOCHECK = 0x00000200,        //Displays selected menu items using a radio-button mark instead of a check mark if the hbmpChecked member is NULL.
    MFT_RIGHTJUSTIFY = 0x00004000,      //Right-justifies the menu item and any subsequent items. This value is valid only if the menu item is in a menu bar.
    MFT_RIGHTORDER = 0x00002000,        //Specifies that menus cascade right-to-left (the default is left-to-right). This is used to support right-to-left languages, such as Arabic and Hebrew.
    MFT_SEPARATOR = 0x00000800,         //Specifies that the menu item is a separator. A menu item separator appears as a horizontal dividing line. The dwTypeData and cch members are ignored. This value is valid only in a drop-down menu, submenu, or shortcut menu.
    MFT_STRING = 0x00000000             //Displays the menu item using a text string. The dwTypeData member is the pointer to a null-terminated string, and the cch member is the length of the string.
                                        //MFT_STRING is replaced by MIIM_STRING.
}

//The menu item state. This member can be one or more of these values. Set fMask to MIIM_STATE to use fState. 
public enum MenuItemInfo_fState : uint
{
    MFS_CHECKED = 0x00000008,           //Checks the menu item. For more information about selected menu items, see the hbmpChecked member.
    MFS_DEFAULT = 0x00001000,           //Specifies that the menu item is the default. A menu can contain only one default menu item, which is displayed in bold.
    MFS_DISABLED = 0x00000003,          //Disables the menu item and grays it so that it cannot be selected. This is equivalent to MFS_GRAYED.
    MFS_ENABLED = 0x00000000,           //Enables the menu item so that it can be selected. This is the default state.
    MFS_GRAYED = 0x00000003,            //Disables the menu item and grays it so that it cannot be selected. This is equivalent to MFS_DISABLED.
    MFS_HILITE = 0x00000080,            //Highlights the menu item.
    MFS_UNCHECKED = 0x00000000,         //Unchecks the menu item. For more information about clear menu items, see the hbmpChecked member.
    MFS_UNHILITE = 0x00000000,          //Removes the highlight from the menu item. This is the default state.
}

//A handle to the bitmap to be displayed, or it can be one of the values in the following Enum. 
//It is used when the MIIM_BITMAP flag is set in the fMask member. (ex. (hBitmap)HBMMENU_SYSTEM)
public enum MenuItemInfo_hItem
{
    HBMMENU_CALLBACK = -1,              //A bitmap that is drawn by the window that owns the menu. The application must process the WM_MEASUREITEM and WM_DRAWITEM messages.
    HBMMENU_MBAR_CLOSE = 5,             //Close button for the menu bar.
    HBMMENU_MBAR_CLOSE_D = 6,           //Disabled close button for the menu bar.
    HBMMENU_MBAR_MINIMIZE = 3,          //Minimize button for the menu bar.
    HBMMENU_MBAR_MINIMIZE_D = 7,        //Disabled minimize button for the menu bar.
    HBMMENU_MBAR_RESTORE = 2,           //Restore button for the menu bar.
    HBMMENU_POPUP_CLOSE = 8,            //Close button for the submenu.
    HBMMENU_POPUP_MAXIMIZE = 10,        //Maximize button for the submenu.
    HBMMENU_POPUP_MINIMIZE = 11,        //Minimize button for the submenu.
    HBMMENU_POPUP_RESTORE = 9,          //Restore button for the submenu.
    HBMMENU_SYSTEM = 1,                 //Windows icon or the icon of the window specified in dwItemData.
}

public struct MenuItemInfo
{
    public uint cbSize;                 //The size of the structure, in bytes. The caller must set this member to sizeof(MENUITEMINFO). 
    public MenuItemInfo_fMask fMask;    //See MenuItemInfo_fMask
    public MenuItemInfo_fType fType;    //See MenuItemInfo_fType
    public MenuItemInfo_fState fState;  //See MenuItemInfo_fState
    public uint wID;                    //An application-defined value that identifies the menu item. Set fMask to MIIM_ID to use wID.
    public IntPtr hSubMenu;             //A handle to the drop-down menu or submenu associated with the menu item. If the menu item is not an item that opens a drop-down menu or submenu, this member is NULL. Set fMask to MIIM_SUBMENU to use hSubMenu.
    public IntPtr hbmpChecked;          //A handle to the bitmap to display next to the item if it is selected. If this member is NULL, a default bitmap is used. If the MFT_RADIOCHECK type value is specified, the default bitmap is a bullet. Otherwise, it is a check mark. Set fMask to MIIM_CHECKMARKS to use hbmpChecked.
    public IntPtr hbmpUnchecked;        //A handle to the bitmap to display next to the item if it is not selected. If this member is NULL, no bitmap is used. Set fMask to MIIM_CHECKMARKS to use hbmpUnchecked. 
    public IntPtr dwItemData;           //An application-defined value associated with the menu item. Set fMask to MIIM_DATA to use dwItemData.
    public IntPtr dwTypeData;           //The contents of the menu item. The meaning of this member depends on the value of fType and is used only if the MIIM_TYPE flag is set in the fMask member.
                                        //To retrieve a menu item of type MFT_STRING, first find the size of the string by setting the dwTypeData member of MENUITEMINFO to NULL and then calling GetMenuItemInfo. The value of cch+1 is the size needed. Then allocate a buffer of this size, place the pointer to the buffer in dwTypeData, increment cch, and call GetMenuItemInfo once again to fill the buffer with the string. If the retrieved menu item is of some other type, then GetMenuItemInfo sets the dwTypeData member to a value whose type is specified by the fType member.
                                        //When using with the SetMenuItemInfo function, this member should contain a value whose type is specified by the fType member.
                                        //dwTypeData is used only if the MIIM_STRING flag is set in the fMask member 
    public uint cch;                    //The length of the menu item text, in characters, when information is received about a menu item of the MFT_STRING type. However, cch is used only if the MIIM_TYPE flag is set in the fMask member and is zero otherwise. Also, cch is ignored when the content of a menu item is set by calling SetMenuItemInfo.
                                        //Note that, before calling GetMenuItemInfo, the application must set cch to the length of the buffer pointed to by the dwTypeData member. If the retrieved menu item is of type MFT_STRING (as indicated by the fType member), then GetMenuItemInfo changes cch to the length of the menu item text. If the retrieved menu item is of some other type, GetMenuItemInfo sets the cch field to zero.
                                        //The cch member is used when the MIIM_STRING flag is set in the fMask member.

    public IntPtr hbmpItem;             //A handle to the bitmap to be displayed, or it can be one of the values MenuItemInfo_hItem Enum. It is used when the MIIM_BITMAP flag is set in the fMask member. 
};

if you want to show text and Bitmap:

private MenuItemInfo_fMask InsMenuFlags = MenuItemInfo_fMask.MIIM_STRING |
                                          MenuItemInfo_fMask.MIIM_BITMAP |  
                                          MenuItemInfo_fMask.MIIM_FTYPE | 
                                          MenuItemInfo_fMask.MIIM_STATE | 
                                          MenuItemInfo_fMask.MIIM_ID;

System Menu with custom images

You can create a Menu Item this way:

private IntPtr hSysMenu;
hSysMenu = GetSystemMenu(someform.Handle, false);

private void InsertMenu(uint id, uint icIndex, string icText, IntPtr hBitmap)
{
    MenuItemInfo mInfo = new MenuItemInfo()
    {
        cbSize = (uint)Marshal.SizeOf(typeof(MenuItemInfo)),
        fMask = InsMenuFlags,
        fType = MenuItemInfo_fType.MFT_STRING,
        fState = MenuItemInfo_fState.MFS_ENABLED,
        wID = id,
        hbmpItem = hBitmap,
        hbmpChecked = hBitmap,
        hbmpUnchecked = hBitmap,
        dwTypeData = Marshal.StringToHGlobalAuto(icText),
        dwItemData = IntPtr.Zero,
        hSubMenu = IntPtr.Zero,
        cch = (uint)icText.Length,
    };

    InsertMenuItem(hSysMenu, icIndex, true, ref mInfo);
}

UPDATE:
Since it was referenced in the OP, here's a modified SystemMenu class (credits go to ygoe) which now supports InsertMenuItem() to allow Bitmaps in System Menus.

The original GitHub source code of SystemMenu

This class can be used in this way (insert in a Form constructor):

  SystemMenu systemMenu;
  Bitmap menuIcon;

  //In a Form contructor
  { 
      systemMenu = new SystemMenu(this);
      menuIcon = new Bitmap(Properties.Resources.[Some 16x16 Bitmap]);
      systemMenu.InsertCommand(0, "Bitmap Menu", menuIcon.GetHbitmap(), OnSysBitmapMenu);
      systemMenu.AddCommand("&About…", OnSysMenuAbout, true);
  }

   // Handle menu command click
  private void OnSysMenuAbout()
  {
      MessageBox.Show("My about message");
  }

  private void OnSysBitmapMenu()
  {
      MessageBox.Show("My other bitmap menu message");
  }

  protected override void WndProc(ref Message msg)
  {
      base.WndProc(ref msg);

      // Let it know all messages so it can handle WM_SYSCOMMAND
      // (This method is inlined)
      systemMenu.HandleMessage(ref msg);
  }

All declarations previously posted must be inserted in the #region Native methods of the SystemMenu class with the exception of the InsMenuFlags field.
Note: The 16x16 Bitmap should be padded 2 pixels on the left.

public class SystemMenu
{
    private const int WM_SYSCOMMAND = 0x112;
    
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool AppendMenu(IntPtr hMenu, MenuItemInfo_fType uFlags, int uIDNewItem, string lpNewItem);

    public enum CommandType : int
    {
        AppendMenu = 0,
        InsertMenu
    }

    private MenuItemInfo_fMask InsMenuFlags = MenuItemInfo_fMask.MIIM_STRING |
                                              MenuItemInfo_fMask.MIIM_BITMAP |  
                                              MenuItemInfo_fMask.MIIM_FTYPE | 
                                              MenuItemInfo_fMask.MIIM_STATE | 
                                              MenuItemInfo_fMask.MIIM_ID;

    private Form form;
    private IntPtr hSysMenu;
    private int lastId = 0;
    private List<Action> actions = new List<Action>();
    private List<CommandInfo> pendingCommands;


    /// <summary>
    /// Initialises a new instance of the <see cref="SystemMenu"/> class for the specified
    /// <see cref="Form"/>.
    /// </summary>
    /// <param name="form">The window for which the system menu is expanded.</param>
    public SystemMenu(Form form)
    {
        this.form = form;
        if (!form.IsHandleCreated) {
            form.HandleCreated += OnHandleCreated;
        }
        else {
            OnHandleCreated(null, null);
        }
    }


    /// <summary>
    /// Adds a command to the system menu.
    /// </summary>
    /// <param name="text">The displayed command text.</param>
    /// <param name="action">The action that is executed when the user clicks on the command.</param>
    /// <param name="separatorBeforeCommand">Indicates whether a separator is inserted before the command.</param>
    public void AddCommand(string text, Action action, bool separatorBeforeCommand)
    {
        int id = ++lastId;
        if (!form.IsHandleCreated) {
            // The form is not yet created, queue the command for later addition
            if (pendingCommands == null) {
                pendingCommands = new List<CommandInfo>();
            }
            pendingCommands.Add(new CommandInfo() {
                Id = id,
                Text = text,
                Action = action,
                CommandType = SystemMenu.CommandType.AppendMenu,
                Separator = separatorBeforeCommand
            });
        }
        else {
            // The form is created, add the command now
            if (separatorBeforeCommand) {
                AppendMenu(hSysMenu, MenuItemInfo_fType.MFT_SEPARATOR, 0, "");
            }
            AppendMenu(hSysMenu, MenuItemInfo_fType.MFT_STRING, id, text);
        }
        actions.Add(action);
    }

    /// <summary>
    /// Adds a command to the system menu.
    /// </summary>
    /// <param name="icText">The displayed command text.</param>
    /// <param name="icAction">The action that is executed when the user clicks on the command.</param>
    /// <param name="separatorBeforeCommand">Indicates whether a separator is inserted before the command.</param>
    public void InsertCommand(uint icIndex, string icText, IntPtr hBitmap, Action icAction)
    {
        int id = ++lastId;
        InsertCommand(id, icIndex, icText, hBitmap, icAction);
    }

    private void InsertCommand(int id, uint icIndex, string icText, IntPtr hBitmap, Action icAction)
    {
        if (!form.IsHandleCreated) {
            // The form is not yet created, queue the command for later addition
            if (pendingCommands == null) {
                pendingCommands = new List<CommandInfo>();
            }
            pendingCommands.Add(new CommandInfo() {
                Id = id,
                Index = (int)icIndex,
                Text = icText,
                Action = icAction,
                CommandType = SystemMenu.CommandType.InsertMenu,
                hBitmap = hBitmap,
                Separator = false
            });
        }
        else {
            MenuItemInfo mInfo = new MenuItemInfo()
            {
                cbSize = (uint)Marshal.SizeOf(typeof(MenuItemInfo)),
                fMask = InsMenuFlags,
                fType = MenuItemInfo_fType.MFT_STRING,
                fState = MenuItemInfo_fState.MFS_ENABLED,
                wID = (uint)id,
                hbmpItem = hBitmap,
                hbmpChecked = hBitmap,
                hbmpUnchecked = hBitmap,
                dwTypeData = Marshal.StringToHGlobalAuto(icText),
                dwItemData = IntPtr.Zero,
                hSubMenu = IntPtr.Zero,
                cch = (uint)icText.Length,
            };
            // The form is created, add the command now
            InsertMenuItem(hSysMenu, icIndex, true, ref mInfo);
        }
        actions.Add(icAction);
    }
    
    /// <summary>
    /// Tests a window message for system menu commands and executes the associated action. This
    /// method must be called from within the Form's overridden WndProc method because it is not
    /// publicly accessible.
    /// </summary>
    /// <param name="msg">The window message to test.</param>
    public void HandleMessage(ref Message msg)
    {
        // This method is kept short and simple to allow inlining (verified) for improving
        // performance (unverified). It will be called for every single message that is sent to
        // the window.
        if (msg.Msg == WM_SYSCOMMAND) {
            OnSysCommandMessage(ref msg);
        }
    }


    private void OnHandleCreated(object sender, EventArgs args)
    {
        form.HandleCreated -= OnHandleCreated;
        hSysMenu = GetSystemMenu(form.Handle, false);

        // Add all queued commands now
        if (pendingCommands != null) {
            foreach (CommandInfo command in pendingCommands) {
                switch (command.CommandType)
                {
                    case CommandType.AppendMenu:
                        if (command.Separator) {
                            AppendMenu(hSysMenu, MenuItemInfo_fType.MFT_SEPARATOR, 0, "");
                        }
                        AppendMenu(hSysMenu, MenuItemInfo_fType.MFT_STRING, command.Id, command.Text);
                        break;

                    case CommandType.InsertMenu:
                        InsertCommand(command.Id, (uint)command.Index, command.Text, command.hBitmap, command.Action);
                        break;
                    default:
                        break;
                }
            }
            pendingCommands = null;
        }
    }

    private void OnSysCommandMessage(ref Message msg)
    {
        if ((long)msg.WParam > 0 && (long)msg.WParam <= lastId) {
            actions[(int)msg.WParam - 1]();
        }
    }

    private class CommandInfo
    {
        public int Id { get; set; }
        public int Index { get; set; }
        public string Text { get; set; }
        public Action Action { get; set; }
        public IntPtr hBitmap { get; set; }
        public bool Separator { get; set; }
        public CommandType CommandType { get; set; }
    }
}
Carving answered 2/3, 2018 at 8:9 Comment(18)
Thanks for the well-prepared documentation. Though, it only shows the icon, no text. @HansPassant provided the missing bits in order for me to get it working. – Foti
This method shows both Bitmap and Text (tested). Posted just because it looked like there was something to write down. – Carving
Using your code, it only compiles if I cast MenuItemInfo_fState.MFS_ENABLED and MenuItemInfo_fType.MFT_STRING both to uint before setting their respective properties within new MenuItemInfo(). I don't understand why, because you declared both enums being uint in the first place!? Nonetheless, with both casts added, your solution works. If @HansPassant doesn't provide his hints as an answer later today, I'll accept your answer. Thanks for your dedication! πŸ‘ – Foti
Though, as a suggestion: all uints are unnecessary, because Microsoft itself uses int only as shown here: referencesource.microsoft.com/#System.Windows.Forms/winforms/… – Foti
If you have to cast, something is not declared as it should. Give it a closer look. I agree that (in this case) you could use int instead of uint. But why would you do it? Those are the original native types as declared in their respective headers. Btw, don't worry about accepting anything. – Carving
About the type mismatch, I posted the MenuItemInfo struct I was testing elsewhere; some members where still declared uint (as they originally are). Updated. Also, if you are interested, I've modified the entire SystemMenu class you linked, to enable it to use InsertMenuItem(). I can post it you want it. – Carving
Oh, yes! I'd love to see that! πŸ‘ Lastly, the answer's updated code worked perfectly - the type mismatch is gone. – Foti
@Foti Here it is. Give ygoe a +1 in the answer you linked for this. – Carving
@Foti You didn't say whether you'll be using ygoe modified code or not. If you don't tell me, I will delete it from the answer. If you keep it, I'll have to inform ygoe that his original code has been modified and posted here. – Carving
First of all: been busy with my birthday & normally don't reply to business related mails on the weekend. Straightforward to your questions: thought stating "adapting" in my question's first line made it clear, but anyway: I don't use his code, I read it for increased P/Invoke knowledge about Win API & wrote my own code. Didn't "Copy & Paste" your code either, rather used it for even more increased P/Invoke knowledge. So, I rewrote my MenuItemInfo struct to contain enums instead of consts for usage in fMask property, changed int to uint & dwTypeData to IntPtr. – Foti
@Foti Well, happy birthday then :). However, this is your Question, you do whatever you want with the results you get. I was asking if you care to keep ygoe modified code here (and I'll inform him) or you don't. If the latter, I'ld prefer to delete it, since it's not necessarily related to your question. – Carving
Thanks, nice birthday present from you, too. ;) Seems like I got your comment totally wrong. Sorry about that. Since your answer solves my initial problem/question, I believe the modified code should stay here. Makes it easier for others to understand the overall picture in the future. :) – Foti
Allright then, I'll tell ygoe he's been modified :) – Carving
Note that there's an error in the class above in the AddCommand method - the second call to AppendMenu is passing MFT_SEPARATOR as the menu type instead of MFT_STRING. – Smutch
@Richard Moss Yes, thanks, corrected. There was another typo: the InsertMenu command was called InesertMenu :) – Carving
I had noted that too, but I only wanted to correct the obvious bug :). I actually suggested an edit to fix the wrong value as per your own edit but it was rejected, go figure. – Smutch
@Richard Moss That happens most of the time when you try to corrent living code. People on Review usually deny it because they don't really have means to test the code and the correction (unless it's obvious). In this case (unless you have more than 2,000 rep), you're supposed to notify the author, as you did. – Carving
Interesting, I didn't know that - shall keep in mind for the next time I spot an error in a code sample. Thanks! – Smutch

© 2022 - 2024 β€” McMap. All rights reserved.