![]() |
Questions and AnswersWritten 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:
The MT structure fields are explained below:
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. |