The Easiest Way to Code the Owner Drawn Menu

Environment: VC6 Win 9x/ME/2000/XP (DirectX 9 needed); NT will not be supported


Well, if you ask what’s so different with a context menu, try making a context.

Menu owner draw has a pop-up menu in it. At the same time, it removes the reference of the menu from the dialog. You won’t be able make the pop-up menu element owner draw so easily. So, here is an easier approach.

Popup menu items can be easily made owner draw if there is a menu already present in the dialog. But, what if you want only the context menu and not the main menu to be displayed? Host a surrogate dialog window. To create the dialog window, I do not use any resource; I use the rarely used CreateDialogIndirectParam(…) win32 API. It uses only a structure variable of the type DLGTEMPLATE (see MDSN) and most importantly a Callback function to act as a dialog procedure. So, I host the menu in the dynamically created dialog and hide the dialog. Before that, I used some traditional Charles Petzold coding to create a menu dynamically. See the CreateOwnerDrawPopUpMenu() function.

The action actually begins much before the menu and the dialog are created. It all happens when InitPopUpMenu() is called in OnInitDialog(). In InitPopUpMenu(), I make a call to CreateOwnerDrawPopUpMenu() and hook the main dialog’s window procedure. I do this because only I and not the main program knows where the context is, in the WindowProcMain(..) function. I trap the WM_CONTEXTMENU message and retrieve the menu from the surrogate dialog and call TrackPopupMenu(..) to display the context menu.

Now the real action starts. The menu belongs to the surrogate dialog, and because the menu is owner draw, messages such as WM_MEASUREITEM and WM_DRAWITEM go only to the surrogate dialog. But, if you see the source code, they are handled in the main dialog and not in the surrogate. How is this magic achieved? The truth is, this is no magic. When I call CreateDialogIndirectParam(..), I secretly send in the main window handle as the last parameter; this parameter shows up as the lParam value in the WM_INITDIALOG message of the surrogate. I tuck it away in the Owner variable for future use. Having saved the handle of the Owner, when the WM_MEASUREITEM and WM_DRAWITEM messages come, I simply call SendMessage(Owner,message,wParam,lParam), bouncing them back to the main dialog.

So, finally here it is, the bare bones necessary to make the whole menu owner draw, including the TOP MENU LINE. Once this is understood, one can proceed to write all kinds of classes to encompass the menu and make it look as fancy as one wants.

Let me explain it as clearly as possible, as I always attempt to do.

First of all, insert a menu resource in the dialog application; that’s easy. Then, after clicking OK, I remove the file and edit menu items and also the pop ups and again add all of them in the Owner draw mode. Once that is done, a ON_WM_MEASUREITEM message is sent to Dialog, so trap it and set the individual item’s width and height as shown in the code.

Now, trap the WM_NCPAINT too!!! Create a rectangular region that denotes the Menu’s region minus the combined size of the two Top menu items and send it through DefWindowProc(WM_NCPAINT,(WPARAM)hRgnWhole,NULL) (just say return from this point); you will see that there is a rectangular hole in the window shifted to a little right from the menu. (Please comment all the (1)’s in code before you do this to see the correct effect.) Having done this, simply Bitblt anything you want in this region.

Next, in the OnDrawItem handler of the dialog, we now take up the responsibly to draw the top menu line. Actually, James L. Conger said you cannot make the top line owner draw, but my memory of that dates back to Windows 3.11, maybe now we can do it. I do not have his latest copy of the Windows API Bible to tell you exactly what it is; nevertheless, it works and I am happy about it.

Because the top menu line does not have any ID, I have chosen to trap when the top menu line needs to be painted by eliminating it from all the elements of the pop-up menu; you can do as you wish. Once trapped, happily Bitblt what ever you want.

I have purposefully kept one pop-up menu default to show that in a menu one submenu can be owner draw and another self draw.


Download source – 93 Kb

Download source for second part of article – 189 Kb

More by Author

Must Read