t_menu

Structure that describes menu items in OllyDbg.

typedef struct t_menu {                // Menu descriptor
  wchar_t        *name;                // Menu command
  wchar_t        *help;                // Explanation of command
  int            shortcutid;           // Shortcut identifier, K_xxx
  MENUFUNC       *menufunc;            // Function that executes menu command
  struct t_menu  *submenu;             // Pointer to descriptor of popup menu
  union {
    ulong        index;                // Argument passed to menu function
    HMENU        hsubmenu;             // Handle of pulldown menu
  };
} t_menu;

Members:

name
Text that will appear in menu. NULL indicates end of menu or submenu. Note that empty name has different meaning.
If the first symbol in the name is a vertical line ('|'), menu item is preceded by a separator (horizontal line that divides items into the logical groups). OllyDbg automatically removes unnecessary separators (duplicated, at the very beginning or at the end of menu). If you want to force separator, use double vertical line ('||')
If the first character is a greater than sign followed by a keyword (">STANDARD", ">FULLCOPY", ">APPEARANCE"), this menu item is a forwarder to the standard menu. Forwarder also means the end of the menu, subsequent items are not processed. Forwarders to standard menu are not allowed in the main OllyDbg menu or in the submenus of standard OllyDbg windows.
If name begins with an exclamation sign ('!'), this structure is an initializer. Initializers do not appear in menu. Their menufunc is called with mode=MENU_VERIFY to initialize global variables used by other menu items both in standard mode and when looking for a shortcut. Initializer must be the first item in menu or submenu.
Characters '$' and '*' are reserved by OllyDbg. Menu text can't begin with any of these characters.
During menu creation, menu function has the opportunity to change the text associated with menu item
help
Help string associated with the menu item, may be empty or NULL
shortcutid
Shortcut or shortcut identifier associated with menu item, or K_NONE if there is no associated shortcut. Shortcuts are ignored if item is a forwarder or points to submenu.
menufunc
Menu function associated with the menu item. During menu creation and shortcut search it determines whether given item applies or not. If menu item is selected or shortcut is found, menu function performs necessary actions. Ignored if submenu is not NULL. See MENUFUNC for details
submenu
If name is empty (L""), this is a forwarder to the menu that will continue on the same level (and simultaneously the end of the current menu). If name is not empty, this is a pointer to submenu. Note that if pointed menu is empty or all its items are excluded by menu functions, submenu is not created.
index
(submenu is NULL) User-defined argument which is passed to the menufunc. Allows use of the same menu finction with different menu items
hsubmenu
(submenu is defined) Used internally by OllyDbg, keeps handle of submenu


Standard menus

Pop-up menus in many table windows end with standard sections. Plugins may reference them as ">STANDARD", ">FULLCOPY" or ">APPEARANCE". STANDARD menu includes submenus "Copy to clipboard", "Sort by" and "Appearance". FULLCOPY consists of "Copy to clipboard" and "Appearance", and APPEARANCE includes only "Appearance". Here is an example of the FULLCOPY menu:

Standard menu

Table windows process standard menus automatically.

Standard menus are allowed only in the menus owned by plugin windows. Never use them in main menu or insert them into the existing windows!

Keyboard shortcuts

OllyDbg supports immediate and indirect shortcuts.

Immediate shortcut is a virtual key code (VK_xxx) or a character code combined with KK_DIRECT and optionally with any of the following flags:
KK_CHAR - when flag is set, shortcut contains character code ('A', '+' etc.) Otherwise, shortcut contains virtual key code (letter or one of the constants VK_xxx, for example VK_RETURN, defined in the Windows header files)
KK_SHIFT - shortcut includes Shift key. Not allowed with KK_CHAR
KK_CTRL - shortcut includes Ctrl key
KK_ALT - shortcut includes Alt key
KK_WIN - shortcut includes WIN ("flying windows") key
KK_NOSH - shortcut ignores state of the Shift key. Used only in the main OllyDbg menu. Not allowed with KK_SHIFT
KK_DIRECT - indicates immediate shortcut

Available indirect shortcuts (constants in the range 1..1024)
are listed in the file plugin.h. They are named K_xxx, for example K_UNDO, K_EDIT or K_COPY. Key combinations associated with indirect shortcuts can be redefined with Shortcut Editor. Plugins can't define new indirect shortcuts, but they can reuse existing. Don't use indirect shortcuts belonging to the main menu!


Example:

This is the slightly modified menu of the INT3 Breakpoints window:

static t_bpoint  *menubrk;             // Pointer to selected item

// Initialization function of breakpoints menu.
static int Minitbreakmenu(t_table *pt,wchar *name,ulong index,int mode) {
  menubrk=(t_bpoint *)Getsortedbyselection(&(pt->sorted),pt->sorted.selected);
  return MENU_NORMAL;
};

// Menu function that executes menu command "Delete".
static int Mdeletebreak(t_table *pt,wchar *name,ulong index,int mode) {
  int selected;
  if (menubrk==NULL || (menubrk->type & BP_MANUAL)==0)
    return MENU_ABSENT;
  if (mode==MENU_VERIFY)
    return MENU_NORMAL;
  else if (mode==MENU_EXECUTE) {
    selected=pt->sorted.selected;
    Removeint3breakpoint(menubrk->addr,BP_MANUAL);
    if (selected>=pt->sorted.n)
      selected--;
    Settableselection(pt,selected);
    return MENU_REDRAW; };
  return MENU_ABSENT;
};

// Menu function that executes menu commands "Disable" (index=0) and "Enable"
// (index=1).
static int Menablebreak(t_table *pt,wchar *name,ulong index,int mode) {
  if (menubrk==NULL || (menubrk->type & BP_MANUAL)==0)
    return MENU_ABSENT;
  if (mode==MENU_VERIFY) {
    if (((menubrk->type & BP_DISABLED)==0 && index!=0) ||
      ((menubrk->type & BP_DISABLED)!=0 && index==0)) return MENU_ABSENT;
    return MENU_NORMAL; }
  else if (mode==MENU_EXECUTE) {
    Enableint3breakpoint(menubrk->addr,index);
    // If menu function is called from shortcut, move selection down.
    if (Menufromshortcut() && pt->sorted.selected<pt->sorted.n-1)
      Settableselection(pt,pt->sorted.selected+1);
    return MENU_REDRAW; };
  return MENU_ABSENT;
};

// Menu function that executes menu command "Edit properties" (where index
// is either K_CONDBREAK or K_LOGBREAK, allowing both shortcuts to work).
static int Meditbreak(t_table *pt,wchar *name,ulong index,int mode) {
  POINT coord;
  if (menubrk==NULL || (menubrk->type & BP_MANUAL)==0)
    return MENU_ABSENT;
  if (mode==MENU_VERIFY) {
    if (index==K_CONDBREAK) return MENU_SHORTCUT;
    return MENU_NORMAL; }
  else if (mode==MENU_EXECUTE) {
    if (Gettableselectionxy(pt,2,&coord)<0)
      coord.x=coord.y=-1;            // Unknown coordinates, use defaults
    if (index==K_CONDBREAK) Condbreakpoint(pt->hw,&(menubrk->addr),1,NULL,
      coord.x,coord.y,pt->font);
    else Condlogbreakpoint(pt->hw,&(menubrk->addr),1,0,NULL,
      coord.x,coord.y,pt->font);
    return MENU_REDRAW; };
  return MENU_ABSENT;
};

// Menu function that executes menu command "Follow break in Disassembler".
static int Mfollowbreak(t_table *pt,wchar *name,ulong index,int mode) {
  if (menubrk==NULL)
    return MENU_ABSENT;
  if (mode==MENU_VERIFY)
    return MENU_NORMAL;
  else if (mode==MENU_EXECUTE) {
    Setcpu(0,menubrk->addr,0,0,0,CPU_ASMHIST|CPU_ASMCENTER|CPU_ASMFOCUS);
    return MENU_NOREDRAW; };
  return MENU_ABSENT;
};

// Menu function that executes menu commands "Disable all" (index=0) and
// "Enable all" (index=1).
static int Menableallbreaks(t_table *pt,wchar *name,ulong index,int mode) {
  int i,nenabled,ndisabled;
  t_bpoint *pbrk;
  nenabled=ndisabled=0;
  for (i=0; i<pt->sorted.n; i++) {
    pbrk=(t_bpoint *)Getsortedbyindex(&(pt->sorted),i);
    if ((pbrk->type & BP_MANUAL)==0)
      continue;
    if (pbrk->type & BP_DISABLED)
      ndisabled++;
    else
      nenabled++;
    ;
  };
  if (mode==MENU_VERIFY) {
    if (index==0 && nenabled==0) return MENU_ABSENT;
    if (index!=0 && ndisabled==0) return MENU_ABSENT;
    return MENU_NORMAL; }
  else if (mode==MENU_EXECUTE) {
    for (i=0; i<pt->sorted.n; i++) {
      pbrk=(t_bpoint *)Getsortedbyindex(&(pt->sorted),i);
      if ((pbrk->type & BP_MANUAL)==0)
        continue;
      if (index==0 && (pbrk->type & BP_DISABLED)!=0)
        continue;
      if (index!=0 && (pbrk->type & BP_DISABLED)==0)
        continue;
      Enableint3breakpoint(pbrk->addr,index); };
    return MENU_REDRAW; };
  return MENU_ABSENT;
};

static t_menu bpointmenu[] = {
  { L"!",              NULL,           // Initialization function
                       K_NONE, Minitbreakmenu, 0, 0 },
  { N(L"Delete"),      N(L"Delete INT3 breakpoint"),
                       K_DELETEBP, Mdeletebreak, 0, 0 },
  { N(L"Disable"),     N(L"Disable breakpoint but don't remove it "
                       "from the list"),
                       K_ENABLEBP, Menablebreak, 0, 0 },
  { N(L"Enable"),      N(L"Re-enable INT3 breakpoint"),
                       K_ENABLEBP, Menablebreak, 0, 1 },
  { N(L"Edit properties..."), N(L"Edit properties associated with breakpoint"),
                       K_CONDBREAK, Meditbreak, 0, K_CONDBREAK },
  { N(L"Edit properties..."), N(L"Edit properties associated with breakpoint"),
                       K_LOGBREAK, Meditbreak, 0, K_LOGBREAK },
  { N(L"Follow in Disassembler"), N(L"Follow breakpoint in CPU Disassembler"),
                       K_BPINDASM, Mfollowbreak, 0, 0 },
  { N(L"|Disable all"), N(L"Disable all INT3 breakpoints"),
                       K_DISABLEALLBP, Menableallbreaks, 0, 0 },
  { N(L"Enable all"),  N(L"Re-enable all INT3 breakpoints"),
                       K_ENABLEALLBP, Menableallbreaks, 0, 1 },
  { L"|*BPOINT",       L"",            // Plugin menus
                       0, NULL, NULL, 0 },
  { L"|",              L"",            // Forwarder to standard menus
                       K_NONE, NULL, standardmenus, 0
  }
};


See also:
Menus and shortcuts, MENUFUNC, t_table, t_frame, ODBG2_Pluginmenu()