Feedback Search Top Backward Forward
EDM/2

Questions and Answers

Written by Larry Salomon, Jr.

  Gordon W. Zeglinski (zeglins@cc.umanitoba.ca) writes:

Q: Here's a Q that may make good EDM/2 material. I want to define a menu in memory, and then create it using WinCreateMenu. This will eventually be a submenu. It is impossible to create the submenu in resource files, as its contents are not know until runtime. The reason I want to create the whole submenu at once instead of placing them the entries into an existing submenu is because placing 18 entries into the sub menu is taking about 1 min on a 486 DX33. A very slow process :(.

Anyways, I digress...

The documentation states that the WinCreateMenu item takes a Binary Menu template. After searching through much IBM documentation, I find no such binary template documented...

So what is the format of this template?

A: Before everyone gasps at the "1 minute on a 486/33" statement, let me add that Gordon subsequently found that his code was trying to delete several thousand non-existant menu items first, which was causing the severe time delay.

In order to answer the question, one first needs to look at the data structures involved. In pmwin.h, there are two little-known data structures known as MTI (none) and MT (LMTI), (the datatype names for pointers to these structures are shown in paratheses) which are acronyms for menu template item and menu template.


typedef struct _mti {
   USHORT afStyle;
   USHORT pad;
   USHORT idItem;
   CHAR c[2];
} MTI;

typedef struct _mt {
   ULONG len;
   USHORT codepage;
   USHORT reserved;
   USHORT cMti;
   MTI rgMti[1];
} MT, *LPMT;

The MTI structure fields are explained below:

afStyle
one or more MIS_* constants
pad
reserved and must be zero.
idItem
menu item identifier.
c
variable length data depending on which bits in afStyle are set:
  • MIS_TEXT -- specifies the NULL-terminated menu item text
  • MIS_BITMAP -- If the first byte is '#', the remaining bytes specify the ASCII representation of the bitmap resource. If the first byte is zero, then the next four bytes define a bitmap handle that has already been loaded. Otherwise, there is no bitmap handle associated and the application must set one using the MM_SETITEM message.
  • MIS_OWNERDRAW, MIS_SEPARATOR -- the data is ignored
  • MIS_SUBMENU -- the data is a menu template

The MT structure fields are explained below:

len
specifies the size of the menu template in bytes
codepage
specifies the code page to be used
reserved
reserved and must be zero.
cMti
specifies the number of MTI structures in rgMti
rgMti
specifies the MTI structures that comprise the menu items.

As you can see, the menu template size will - in all likelihood - have to be calculated at run-time as well, making this a nasty section of code. Once you have calculated this, allocated the memory, and initialized the structures, you then do one of two things: if a top-level menu does not already exist, you call WinCreateMenu() and you are done; otherwise, you call WinCreateWindow() to create the submenu as in the following example:


hwndSubMenu=WinCreateWindow(HWND_DESKTOP,       // parent
                            WC_MENU,            // window class
                            "",                 // no text
                            0,                  // no style :)
                            0,                  // no position
                            0,                  //   :
                            0,                  // nor size
                            0,                  //   :
                            HWND_DESKTOP,       // owner
                            HWND_TOP,           // z-order
                            M_TESTMENU,         // window id
                            pmtMenu,            // pCreateParms=menu template
                            NULL);              // no pres params

After this, you need to insert the top-level item representing the pulldown by sending the menu control a MM_INSERTITEM message. The hwndSubMenu field of the MENUITEM structure gets the value returned by the WinCreateWindow() call.


miSubMenu.iPosition=MIT_END;
miSubMenu.afStyle=MIS_SUBMENU|MIS_TEXT;
miSubMenu.afAttribute=0;
miSubMenu.id=M_TESTMENU;
miSubMenu.hwndSubMenu=hwndSubMenu;
miSubMenu.hItem=NULLHANDLE;

strcpy(achText,"~Test");

WinSendMsg(hwndMenu,
           MM_INSERTITEM,
           MPFROMP(&miSubMenu),
           MPFROMP(achText));
Note that the value of miSubMenu.id is the same as the id specified on the WinCreateWindow() call.

Obviously, using menu templates can be a real headache, and the headache gets worse if you have "pull-right" menus. It might be better for you to determine where your performance bottleneck is in your current code and try to optimize that if possible.

A sample program illustrating these concepts has been provided as MENUTEST.ZIP.