Introduction to PM Programming - May 1995
Written by Larry Salomon Jr.
The purpose of this column is to provide the readers out there who are not familiar with PM application development the information necessary to satisfy their curiosity, educate themselves, and give them an advantage over the documentation supplied by IBM. Of course, much of this stuff could probably be found in one of the many books out there, but the problem with books in general is that they don't answer the questions you have after you read the book the first time through.
I will gladly entertain feedback from the readers about what was "glossed over" or what was detailed well, what tangential topics need to be covered and what superfluous crap should have been removed. This feedback is essential in guaranteeing that you get what you pay for. <grin>
It should be said that you must not depend solely on this column to teach you how to develop PM applications; instead, this should be viewed as a supplement to your other information storehouses (books, the network conferences, etc.). Because this column must take a general approach, there will be some topics that you would like to see discussed that really do not belong here. Specific questions can be directed to me via email and I will do my best to answer them in a timely fashion.
Last month we began looking at the menu control, which we will continue with this month.
Basic Knowledge Required
Before we may continue, we should take a brief look at the typical use of a menu control, from the programmer's perspective. This involves the definitions of the manifest constants, the menu template definition, the "loading" of the menu (you'll see why "loading" is in quotes in a minute), and the processing of the user's actions. We're taking this different approach to looking at the window class because - as we stated last month - the menu provides the most widely used functionality of any of the window classes; as such, you'll need to know how to use it because you'll be writing this code more times than any other.
Manifest constants - a.k.a. #define's - are a convenient language element which allow us to use a "name" in place of something else. For menus, the "something else" is a number which represents an identifier unique to that menu template. You'll find that in larger applications that the file containing these constants can grow quite large, so it would be helpful if, at a glance, you could determine the use of the constant from looking at its name. To accomplish this, I defined a naming convention. You can use this one or your own - it doesn't matter. What does matter is that you spend less time trying to find out how a constant is used and more time on actually using the constant. For menus, I use the following:
Constant form What it represents M_id Menu or submenu identifier MI_id Menuitem identifier
The constants that are used for resource definitions I keep in a separate file to allow me to make the file a dependancy of all files that use resources. This is simply a suggestion.
Under Windows, there is App Studio which allows you to define and maintain all of your resources. How come there isn't something like this for OS/2? Regardless, you have to design your menus "blind," meaning that you can't see the result until you actually use the menu you've built.
As it is with writing applications, designing your menu layout should be the most important action; a confusing or deep (i.e. many pullrights) menu structure will often confuse the user and turn them away from using your application. Group the items in submenus in a logical fashion so that the user can "take a guess" at where to look when trying to execute a particular action.
IBM's "Common User Access" (CUA) guidelines define a number of pulldown menus and a (non-inclusive) list of what they should contain. I've included a brief list of these (since I cannot find my CUA book <pout>) below:
|Pulldown name||Menu items contained therein|
|File||New, Open, Close, Save, Save as, etc.|
|Edit||Undo, Copy, Cut, Paste, etc.|
|Help||Help index, General help, Using help, Keys help|
Another important CUA note is the use of the ellipsis and bang punctuation marks on text. An ellipsis should be appended to menu item text when selecting the menu item results in a dialog being displayed. A bang should be appended to text belonging to items on the action bar (note that this therefore excludes pullrights and any popup menu items) when selecting them does not display a pulldown menu (i.e. when it is a leaf-node). These are used as feedback indicators to the user to alert them about the behavior of the application without having them find out "the hard way."
Loading a Menu
Loading a menu usually involves the setting of a flag only. No explicit loading is usually performed by the application code. (Popup menus are the exception to this rule, since the current CUA specification eliminates action bars.) In the call to WinCreateStdWindow(), simply include FCF_MENU on the set of flags passed (by reference) as the third parameter.
#define RES_CLIENT 256 HWND hwndFrame; HWND hwndClient; ULONG ulCreate=FCF_SYSMENU | FCF_TITLEBAR | FCF_MINMAX | FCF_MENU | FCF_SHELLPOSITION | FCF_TASKLIST; hwndFrame=WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE, &ulCreate, CLS_CLIENT, "Test application" 0, NULLHANDLE, RES_CLIENT, &hwndClient);
It has been stated before in this column (I hope) that, when using FCF_MENU, FCF_ICON, or FCF_ACCELTABLE that the eighth parameter must specify the resource identifier of the resources corresponding to these flags. Since we specified FCF_MENU, we should have a menu template defined that begins with:
MENU RES_CLIENT :
If we do not have this defined, the WinCreateStdWindow() function will fail. A useful note here is that, as each component of the window specified in ulCreate is successfully created, the corresponding bit in ulCreate is set to 0. So, the components that were not created successfully can be determined by examining ulCreate after the function fails.
Processing the User's Requests
Now we learn how to utilize the menu in our application code. There are usually two messages that we will be interested in when coding our application: WM_INITMENU and WM_COMMAND. Note that, if any MENUITEMs have the MIS_SYSCOMMAND or MIS_HELP style, we will need to add the WM_SYSCOMMAND and WM_HELP messages to this list, but for the moment we'll assume that we have none with these menu item styles.
WM_INITMENU is sent to the client window whenever a menu or submenu is about to be used by the user, e.g. when the user presses F10 to get to the action bar, when the user clicks on a pulldown menu to display the pulldown, etc. Intercepting this message allows us to dynamically enable or disable menu items according to the state of our application. For example, if the user selects the "Print" menuitem, you might want to disable the "Exit" menuitem until printing is completed. We will see later how to change menuitem attributes.
SHORT1FROMMP(mpParm1) specifies the identifier of the menu. If the actionbar is the cause of the message, this will be FID_MENU; otherwise, it will be the identifier you specified on the SUBMENU statement in the menu template.
HWNDFROMMP(mpParm2) is the handle of the window corresponding to the identifier. You should know that pulldown and pullright menus are actually separate windows which belong to something called an "object" window when not in use. When you click on a pulldown, the appropriate window is retrieved from the object window and displayed on the desktop. This window handle is needed to send messages to the menu.
WM_COMMAND, WM_SYSCOMMAND, and WM_HELP are all sent whenever the user selects a menuitem with the corresponding style. This is your indicator that the user wants something done and that you are to process this request.
SHORT1FROMMP(mpParm1) specifies the identifier of the menuitem selected.
SHORT1FROMMP(mpParm2) specifies the source of the message and will always be CMDSRC_MENU when this message is sent via a menu control.
SHORT2FROMMP(mpParm2) is TRUE if this message was sent as the result of a mouse action or FALSE if sent as the result of a keyboard action.
Next month we'll start to look at a sample application that uses the menu control, and we'll begin to look at the MM_ message family which allows you to interact with the menu control. As always, feedback will be enjoyed immensely; send any comments, suggestions, etc. to firstname.lastname@example.org.