Marc Adler
The first article in this series introduced the concepts behind programming an application for the Microsoft WindowsÔ graphical environment. It demonstrated the message-based architecture of Windows1 and showed how Windows uses a message loop to maintain cooperative processing among the various tasks running in a session. I defined a window as not only a visual object in which data is displayed, but also as an object that receives and processes messages. Each window has a message handler, called a window procedure, that processes the messages sent to it.
While the first article contained some initialization code, I really did not begin writing the sample stock- charting application. In this issue, I will create the main window and add a menu system to it. The user will choose a command from the menu, the command will be sent to the main window, and the main window will respond in some way.
All that you need to do to create a complete pull-down menu system is define the menu in the application's resource file. Resource files are therefore the first items I'll discuss. Next, menuing systems and the API functions and messages associated with them are described. Finally, I'll discuss shortcut keys, called accelerators, that permit the user to invoke any command in your application.
Resources
A resource is a binary description of a Windows object. Windows resources include dialog boxes, menus, strings, accelerators, fonts, icons, bitmaps, cursors, and user-defined binary data.
A resource file is an ASCII text file that contains an English-like description of the resources used by an application. This file contains the actual definitions of some of the resources such as menus, strings, accelerators, and dialog boxes. Other resources, such as icons, fonts, and bitmaps, cannot be defined in ASCII. Therefore, the ASCII resource file contains the names of files in which these resources are stored in binary form.
The non-ASCII resources must be created with special tools. For a bitmap image, for example, you can use the SDKPAINT program in the Windows 3.0 Software Development Kit (SDK). After you have created the bitmap image, you can use a good old text editor to modify the resource file yourself, adding a reference to the bitmap file you've just created. The resource file usually has the same name as the application but has an RC extension.
After an RC file is made, it must be "compiled" into a binary resource file. Binary images of resources are much faster to load into an application than ASCII resource descriptions because the application doesn't have to interpret them. The resource compiler generates binary images from the resources defined in ASCII format and combines these with the binary images stored in external files. The result is a file with a RES extension. To compile the RC file into a RES, invoke the Windows Resource Compiler (RC.EXE) on the resource file using the -r option.
rc -r app.rc
The last step in compiling and linking any Windows application is merging together the binary resource file (RES) and the application's EXE file. To tack the RES file onto the EXE file, invoke the resource compiler a second time without the -r option:
rc app
This is the last command you invoke when building a Windows program.
There are several good reasons to use resources. First, a resource is not initially loaded into memory when its application is. A resource can be loaded explicitly at the request of the application programmer, or loaded implicitly by Windows when Windows needs the resource. This means that the memory taken up by the program is less than it would be if the resource were stored statically within the data segment.
Second, compiling a resource file is extremely fast. If you need to change, for example, the the layout of controls in a dialog box, all you need to do is change the RC file, recompile it with the resource compiler, tack it on to the application's EXE file, and rerun the application. There is no need for you to change your program's source code and then have to recompile and relink the program.
Third, by isolating all of the text strings your program uses in a resource file, your program is much easier to adapt to a foreign language. For instance, if you wanted to create a Swedish version of an application, all you would have to do is to edit the strings, menus, and dialog boxes in the resource file and recompile the resource file.
Now that you know what a resource file is, I will create one from scratch and define the pull-down menu system in it.
Menus
Most Windows applications rely on a pull-down menu system for their top-level user interface. Windows 3.0 improves on the standard pull-down menus. One addition is hierarchical pull-down menus. Using this menu style, individual pull-down menus can be attached not only to items on the menu bar, but also to items on other menus (see Figure 1). This facility permits an application to granularize its command set better and lets the user find the proper command more easily. It also eases the command overcrowding that characterizes the pull-down menus of large, complex applications.
Another nice addition to the pull-down menu system is the floating pop-up menu. These menus are not attached to a menu bar. Windows gives you the ability to create or load a predefined pop-up menu and place it anywhere within a window. For example, the user can click on a button and have a menu of choices appear over that button.
A menu can be activated in a variety of ways. You can click a menu bar item with the mouse; you can press the Alt key with the key that corresponds to the underlined letter of a menu bar item. This combination is called a hotkey. Or you can press Alt without pressing any other keys. This activates the menu bar, highlighting the first entry without activating an attached pull-down menu. You can use the cursor keys to move along the menu bar, pressing Enter when you reach an item whose pull-down menu you want to invoke.
The other type of menu supported by Windows is the system menu, which is usually attached to each top-level or pop-up window. It is represented by an icon in the upper-left corner of the window. Certain predefined items appear on the system menu across each class of windows. For example, every top-level application window has a system menu with the entries Restore, Move, Size, Minimize, Maximize, Close, and Switch To. Almost all dialog boxes have a system menu with only two entries, Move and Close. Most Windows applications do not alter the system menu, although the Windows API provides that option. Users expect to find certain entries in the system menu, so it's best to keep these standard throughout Windows applications.
Menus and Resource Files
The first step in defining a menu system in the sample stock-charting application is to create the resource file. I used a text editor to create a file called STOCK.RC (see Figure 2). The first line in any resource file should be the following:
#include <windows.h>
WINDOWS.H, the main include file used by Microsoft Windows programs, is a large file that defines most of the constants, messages, data structures, and function prototypes in Windows. As far as resource files are concerned, WINDOWS.H contains the #defines of the keys used in the definitions of the accelerator keys and the constants for the style bits used by control windows.
Now it is time to define the application's menu system. The syntax of a menu definition is shown in Figure 3.
The POPUP keyword defines a pop-up menu that is activated when the user selects the associated string from a lower-level menu. The string following the POPUP keyword is actually placed on the pop-up menu's parent menu. In fact, most menu bars are defined as a series of pop-up menus, with each string associated with the pop-up menu placed in sequence in the menu bar.
The MENUITEM keyword defines an atomic menu item, meaning that selecting this item does not invoke another pop-up. The MENUITEM definition contains the text string associated with that item, a command identifier used to distinguish a command from others in the application, and a list of menu attributes. A menu item can have several attributes associated with it that serve as visual cues for the end user.
An ampersand in a menu item string indicates to Windows that the character following the ampersand will be the hotkey for that item at run time. The ampersand itself is invisible. On a menu bar, you invoke the menu by pressing Alt-character. In a pull-down menu, pressing the hotkey will move the selection bar to that menu item.
One thing to note in Figure 2 is a multilevel pop-up menu. The Graph pull-down menu has an entry called "&Grid." Pressing Enter at this menu item reveals a higher-level pull-down menu that prompts the user to draw the horizontal or vertical grid lines. Windows 2.x programmers had to add two menu items to the Graph menu, "Horizontal Grid" and "Vertical Grid." In Windows 3.0, you need only one generalized entry for the grid, simply adding a lower-level submenu.
Also note that the "Help" menu bar item has the characters "\a" prefixed to the string. A menu item with this prefix will be right-justified in the menu bar. This style is usually reserved for the menu that invokes the application's help facility.
After the menu system is defined, you can run it through the resource compiler with the following command:
rc -r stock
Loading Menus Into an Application
When an application starts up, a binary description of the menu system sits within the executable file on disk. One way to get it into memory and attach it to a window is to associate the menu with a window class. In the initialization code presented in the previous article, you saw how to register a window class by filling it with the elements of a WNDCLASS structure and calling the RegisterClass function. One of the members of the WNDCLASS structure is:
LPSTR lpszMenuName;
By assigning the name of the menu to lpszMenuName before calling RegisterClass, you tell Windows that every time a window of that class is created, the specified menu should be loaded into memory and attached to that window automatically. Recall that one of the arguments in the CreateWindow function wasthe handle of the menu that should be attached to the created window. If you specify NULL for the hMenu parameter when calling CreateWindow, the class menu (if any) will be attached to that window (see Figure 4).
Another way to load a menu from a resource file is to call LoadMenu. The syntax for LoadMenu is:
HMENU LoadMenu
(HINST hInstance,
LPSTR lpszMenuName)
The first argument to LoadMenu is the instance handle of the instance of your Windows application; the second parameter is the name of the menu in the resource file. The name of the menu, or any resource, can be either a text name or a numeric identifier. If it is a numeric value, you must use the MAKEINTRESOURCE macro in order to cast the numeric value to an LPSTR. For example,
hMenu = LoadMenu(hInst, "MyMenu");
or
hMenu = LoadMenu(hInst, MAKEINTRESOURCE(ID_MYMENU));
LoadMenu returns the handle of the loaded menu, which can then be used as the hMenu parameter in the CreateWindow call. This is how you would attach a menu other than the class menu to a window.
You can also create a menu on the fly using CreateMenu. This function creates an empty menu and returns its handle to the application. You can then use InsertMenu or AppendMenu to add both atomic items and pop-ups to this menu.
HMENU hMenu;
hMenu = CreateMenu( );
AppendMenu(hMenu, MF_STRING, ID_OPEN, "&Open...");
AppendMenu(hMenu, MF_STRING, ID_CLOSE, "&Close");
The WM_COMMAND Message
When defining a menu system in a resource file, you saw that each MENUITEM had a command identifier associated with it. For instance, in the menu item defined by the following line, the constant ID_GRAPH_VOLUME is the command identifier associated with the "Volume" menu item.
MENUITEM "&Volume", ID_GRAPH_VOLUME
This command identifier should be a unique number that distinguishes the command from any other command in the application.
Fortunately, Windows makes menu handling automatic, so the programmer doesn't have to worry about polling the menu system to determine whether the user has selected an item from a menu. When the user selects a menu item, Windows simply posts a WM_COMMAND message to the window procedure of the window that owns the menu. If the user selects an item from a window's system menu, Windows posts the similar WM_SYSCOMMAND message to that window.
The previous article stated that when a message is sent to a window procedure, two other data elements are also passed to the window procedure. These two pieces of data, wParam and lParam, provide the window procedure with additional information concerning the message.
When the WM_COMMAND message is sent to a window, the wParam field contains the command identifier of the command invoked. This command identifier is the same value specified for a menu item in the resource file. By examining the wParam field, you can tell which menu item the user selected. And, because you know which command was sent, you can call one of your own routines to handle that command. A piece of skeleton code for handling WM_COMMAND messages is shown in Figure 5.
WM_SYSCOMMAND Message
The WM_SYSCOMMAND message is sent to a window when the user selects an item from that window's system menu. Windows uses the low-order 4 bits of wParam internally, so to determine which command was chosen, you need to logical-AND wParam with FFF0H to mask off the low-order nibble. Some of the messages and operations the system menu allows for a standard window are shown in Figure 6.
Most of the time, you would let the DefWindowProc handle the processing of the WM_SYSCOMMAND message. However, there might be special cases in which you want to prevent the user from maximizing or minimizing a window. You can do this by handling the WM_SYSCOMMAND message yourself, not passing it on to the DefWindowProc.
Other Menu Messages
When the user selects an item from the top-level menu bar, the WM_INITMENU message is sent to the window that owns the menu. This permits the application to alter the appearance of the menu bar if necessary, but most of the time this message will be simply passed on to DefWindowProc.
Windows convention dictates that the appearance of the menu bar should remain constant, and that you should only change the appearance of the lower-level items appearing on the pop-up menus. To this end, Windows sends the WM_INITMENUPOPUP message to the window that owns the menu bar just before a pop-up is displayed. This gives you the opportunity to change the appearance of one or more of the pop-up's menu items. You can disable, enable, check, or uncheck certain items at this point. For example, many Windows applications with an Edit pop-up menu use the WM_INITMENUPOPUP message to disable the "Paste" menu item if the clipboard is empty.
WM_INITMENUPOPUP contains the handle of the pop-up menu in wParam and the index of the pop-up item in the low word of lParam. To use this message to handle the "Paste" menu item, the following code could be used:
case WM_INITMENUPOPUP :
bTextToPaste = (AppClipboard.iLength > 0);
EnableMenuItem(wParam, ID_PASTE, bTextToPaste);
break;
When the user moves the selection bar over a menu item, whether it's in the menu bar or in a pop-up list, Windows sends the WM_MENUSELECT message to the window that owns the menu bar. For atomic menu items, wParam contains the command identifier associated with that menu item. If a pop-up menu is attached to that menu item, wParam contains the handle of the menu. In both cases, lParam contains the current state of the menu item. Its state can be a combination of MF_BITMAP, MF_CHECKED, MF_DISABLED, MF_GRAYED, MF_HELP, MF_MOUSESELECT, MF_POPUP, and MF_SYSMENU. These state flags are discussed later.
If you want to display some help text in a status window when the highlighted selection bar moves across a menu, use the WM_MENUSELECT message. An example is shown in Figure 7. People wonder how certain Windows applications, such as Microsoft Excel, manage to print the help text at the bottom of the main window as you move the highlight bar over a new menu selection. It is done in the following way. The WM_MENUSELECT message is sent to the window procedure of the main window (or to the window that owns the menu bar), with wParam set to the identifier of the currently highlighted menu item. You define a structure that maps each menu identifier to a string of help text and implement a small routine to scan the list of identifiers sequentially upon receipt of the WM_MENUSELECT message. The returned string is then displayed in a hypothetical status window, which is probably located at the bottom of the main window.
The last menu message that you need to know about is the WM_MENUCHAR message. This message is sent by Windows to the owner of the menu bar when the user presses a hotkey character that does not correspond to an item on the menu. If the menu is composed solely of text strings, this message can be ignored and passed onto DefWindowProc. This message is more useful when a menu is composed of bitmaps or user-drawn items. Using the WM_MENUCHAR message, you can associate a hotkey with a bitmap on the menu. For example, assume that you have a pull-down menu in which each menu item is a color strip; you can associate each color with a hotkey corresponding to the first letter of the name of that color. If the user types "B," the menu selection would be the Blue color strip (see Figure 8).
The Menu API
The Windows menu system has a complete API that allows you to manipulate a menu in many ways. Functions exist that set and retrieve the text or state of a menu item; add, insert, remove, and change the text or state of an item; and create, destroy, and draw a menu. For a demonstration of these capabilities, examine the MENU program included with the Windows 3.0 SDK.
Besides loading a menu from a resource file, you can also create a complete menu system on the fly. CreateMenu creates an empty menu bar, returning the handle to your application. You can then append items to this menu bar handle. A menu can be destroyed by calling the DestroyMenu function. DestroyMenu will free the memory occupied by the menu.
If you programmed earlier versions of Windows, you probably relied on the ChangeMenu function as an all-purpose function to manipulate menus. Windows 3.0 augments the ChangeMenu function with several functions, each of which performs one of the tasks that ChangeMenu used to perform (see Figure 9).
For the functions that have the nPosition parameter, you can refer to a menu item by either its zero-based position within the menu or its associated command identifier. You would logically OR the value MF_BYPOSITION with the other flags in the wFlags argument if you wanted to refer to the menu item by its position, and you would use the MF_BYCOMMAND flag if you wanted to refer to an item by its command identifier.
/*
Get rid of the first menu item
*/
DeleteMenu(hMenu, 1, MF_BYPOSITION);
/*
Attach a new pop-up menu to the ID_EDIT menu item
*/
InsertMenu(hMenu, ID_EDIT, MF_BYCOMMAND | MF_POPUP,
hSubMenu, 0);
Figure 10 lists the possible values for the wFlags argument.
You can enable or disable a menu item by calling EnableMenuItem. A disabled item does not generate a WM_COMMAND message when selected.
You can place or remove a check mark next to a menu item by calling CheckMenuItem. Check marks should be placed next to items whose states can be toggled.
Windows 3.0 permits you to define a custom bitmap to check or uncheck a menu item. To create these bitmaps, you must first determine what its size should be to fit on a row of the menu. Starting with Windows 3.0, the GetMenuCheckMarkDimensions function is provided, which returns the height and width in pixels that the bitmap should be. StretchBlt can be used to shrink or expand a bitmap to a desired size, but more on this in a later article.
Once you have the handles for the two bitmaps, call SetMenuItemBitmaps to associate them with the menu item.
SetMenuitemBitmaps(hMenu, nPosition, wFlags,
hBitMapCheckOff, hBitMapCheckOn);
If either bitmap is NULL, nothing will be displayed next to the menu item when the item has a corresponding check state. For instance, if hBitMapCheckOff is NULL, nothing will be displayed next to the item when it is not checked.
Owner Draw Items
One nice feature of Windows 3.0 is the ability to draw custom menu items. For instance, imagine a Change Font pop-up menu in a word processor in which each item in the menu is drawn in a different font. Windows 3.0 lets you do this.
One of the state flags associated with a menu item can be MF_OWNERDRAW. This flag tells Windows that the application will take care of drawing the menu item. When you create an owner-draw menu item, you can attach a 32-bit value to the item, which will assist you in the drawing of the item. For example, in the following call, the last parameter is the special 32-bit value.
AppendMenu(hMenu, MF_OWNERDRAW | MF_BYCOMMAND,
ID_HELVETICA, (LPSTR) ul32bitValue);
This will take the place of the menu item's text string.
When the owner-draw item needs to be drawn, Windows sends two messages to the window procedure of the window that owns the menu bar. The first message is WM_MEASUREITEM. The wParam is not used in this message; the lParam points to a MEASUREITEMSTRUCT data structure (see Figure 11). The window procedure must fill in both the itemWidth and the itemHeight fields of this structure in response to the WM_MEASUREITEM message.
The second message sent is WM_DRAWITEM. In this message, the lParam field points to a DRAWITEMSTRUCT data structure (see Figure 12). This menu item can be drawn using any Windows graphics function.
Floating Pop-up Menus
As mentioned, Windows 3.0 allows you to create floating pop-up menus. A new function, CreatePopupMenu, has been added so you can create an empty pop-up menu. This function is analogous to the CreateMenu function that lets you create an empty menu bar. CreatePopupMenu returns the handle of an empty pop-up. Once you have this handle, you can then add menu items by calling AppendMenu or InsertMenu. Any function that operates on the menu bar will also operate on a pop-up menu.
Once a pop-up menu has been created, you can position it anywhere on the screen. To do this, Windows 3.0 adds a new function called TrackPopupMenu.
TrackPopupMenu(HWND hMenu, WORD wFlags, int x, int y,
int cx, HWND hWnd, LPRECT lprect)
The upper-left corner of the menu will be displayed at screen coordinates x,y. If you want to position the menu in a window at a certain point, you must use the ClientToScreen function to translate the window coordinates into screen coordinates. hWnd is the handle of the window that the menu notification messages will be sent to.
You can create and use a floating pop-up menu with the following code fragment.
hMenu = CreatePopup;
AppendMenu(hMenu, ....); /* add menu items here */
o
o
o
ClientToScreen(hWnd, (LPPOINT) &pt);
TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hWnd, NULL);
DestroyMenu(hMenu);
CreatePopup is called to create an empty pop-up menu, and then AppendMenu is called repeatedly to add menu items to it. Once all of the items have been added to the menu, you need to determine the absolute screen coordinates where the pop-up should be displayed. Suppose you want to have the upper-left corner of the menu 10 units from the top of the window hWnd and 20 units from the left border. Call ClientToScreen to derive the absolute screen coordinates from a set of window coordinates.
Then you call TrackPopupMenu to display the menu. At this point, the second, fifth, and seventh parameters of TrackPopupMenu are reserved by Windows and must be set to zero. After the user makes a selection from the menu, you call DestroyMenu to get rid of the pop-up.
Accelerators
Another way for the end user to choose a command, besides picking an item from a menu, is to press a key combination known as an accelerator. An accelerator is a pairing of a keystroke and a command identifier. When the user presses an accelerator key, Windows sends a WM_COMMAND message to a window.
You can define one or more tables of accelerators in your resource file. The syntax of an accelerator table definition is shown below.
AccelName ACCELERATORS
BEGIN
event, idvalue, [type] [NOINVERT] [ALT] [SHIFT] [CONTROL]
END
The event field can be one of the following :
o A single ASCII character enclosed in double quotes. If the character is preceded by a caret (^), the character is assumed to be a control character.
o An integer representing an ASCII character.
o An integer or double-quoted single character representing a virtual key. The type field must be VIRTKEY. A list of virtual key codes can be found in the WINDOWS.H file. Virtual key codes usually begin with the prefix VK_; for example, the virtual key code for the F1 key is VK_F1.
The idvalue field contains the unique command identifier that will be sent as part of the WM_COMMAND message. The type field can either be VIRTKEY if you are using a virtual key combination, or ASCII if you are using an ASCII key.
As you can see, the keystroke can contain any combination of the Control, Alt, or Shift shift states.
To use accelerators, you must load the accelerator table from the resource file. This can be done by using the LoadAccelerators function:
HANDLE LoadAccelerators(HINST hInstance,
LPSTR lpszAccelerator)
The first parameter is the instance handle for this instance of your application. The second parameter is the name of the accelerator table as defined in the resource file. LoadAccelerators returns a handle to the loaded accelerator table.
Once the accelerator table is loaded, you must tell Windows to check the keyboard events to determine whether the user pressed an accelerator key. To do this, you must add the TranslateAccelerator function to the basic Windows message loop. The TranslateAccelerator function tries to translate WM_KEYDOWN and WM_KEYUP events into accelerators. The message loop now looks like this:
while (GetMessage(&msg, hWnd, 0, 0))
{
if (!TranslateAccelerator(hWnd, hAccel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
If the msg structure contains a keyboard event, TranslateAccelerator will search all of the accelerators in the accelerator table hAccel. If the keystroke corresponds to an accelerator, TranslateAccelerator puts the window handle hWnd into the msg.hWnd and sends a WM_COMMAND message to window hWnd. Since you do not have to call TranslateMessage and DispatchMessage (it has already been done), the program loops back to read another message.
If you need to find out whether a WM_COMMAND message was sent by an accelerator key rather than a menu selection, you can examine the high word of lParam. If it is 1, the WM_COMMAND message was generated by an accelerator key; if 0, it was generated by a menu item.
Putting It All Together
Now that you have seen code to put up a window, created a resource file with menu and accelerator definitions, and created an icon for the application to use when a window is minimized, let's see how to combine everything into one glorious executable file and run the program. Included with the source code is a make file that you can submit to the Microsoft MAKE utility to automate the compile and link cycle.
The files that are needed to develop a Windows application are listed in Figure 13, and the processes that each file must go through to create the final executable file are shown in Figure 14. First, the icon is created using SDKPAINT and written into a binary icon file. This icon file is referred to in the ASCII resource file. The resource file is compiled with the "-r" option to create a binary resource file.
The C source code is then compiled into an object file. To compile an application for Windows, you must include the following switches :
cl -c -Gsw -Zp -AS fileopen.c
The -c switch tells the compiler to compile the code without linking it. The -Gsw switch disables stack checking and tells the compiler to emit special Windows code before and after each function that you have declared as FAR. The -Zp switch packs all structures. Since all structures in Windows are packed, you must use this switch when writing any Windows application. The -AS switch indicates that the small memory model is to be used.
Now that the object file has been created, link it with the Windows run-time libraries to create an executable file. In the past, you had to use a special linker called LINK4, but if you use Microsoft C Version 6.0, you use the linker that comes with the C compiler. The Windows 3.0 SDK includes libraries that completely replace the C run-time libraries that came with your C compiler. These new libraries provide Windows-aware versions of every C function.
A special user-written file called a definition file provides additional information about the linking process to the linker. The DEF file is required for every Windows application; in it is the name of your application and a description of it. It may also contain the name of a stub file, which is a normal DOS executable program that will be run if the user tries to run the Windows program from a DOS prompt. The SDK includes a sample stub program called WINSTUB.EXE, which merely displays the message "This program requires Microsoft Windows." You can also create your own stub file to do something more elaborate. The linker puts the stub file into the executable file, so there are really two programs contained in one EXE file-a Windows version and a non-Windows version. Another requirement of a DEF file is the specification of the executable header type. For Windows programs, you must specify "WINDOWS." So far, the definition file looks like this:
NAME STOCK
DESCRIPTION 'MSJ Stock Application'
EXETYPE WINDOWS
STUB 'WINSTUB.EXE'
You can specify the size of the application's local heap and stack by using the HEAPSIZE and STACKSIZE statements. Windows gives your application a default heap size of zero, so if you need to do any kind of local memory allocation, you should specify some size for the heap. Add the following two lines to the DEF file:
HEAPSIZE 2048
STACKSIZE 8192
Now you need to tell Windows about the code and data segments in your application. If memory space is at a premium in your system, Windows will try to move code and data segments around in memory to reduce memory fragmentation, and if necessary, discard code and data segments to free up memory. If Windows discards a segment, it will try to reread it from an application's EXE file on disk when it needs the segment again. Careful planning can reduce Windows swapping. Below is what you should use in this version of the application.
CODE MOVEABLE DISCARDABLE PRELOAD
DATA MOVEABLE MULTIPLE
This tells the linker that the standard code segment is movable in memory and can be discarded if Windows runs low on memory. The code segment is loaded when the application is loaded, instead of being loaded on demand. You also tell the linker that each instance of the application has its own data segment, and that this data segment can be relocated in memory by Windows.
You can also tailor the characteristics of each segment in the program by using the following statement:
SEGMENTS segment name [CLASS classname] [minalloc] [FIXED|MOVEABLE]
[DISCARDABLE] [SHARED|NONSHARED] [PRELOAD|LOADONCALL]
In the last part of the DEF file, you usually define the functions that you want to export to Windows and the functions that you want to import from dynamic-link libraries. You generally need to export any functions that will be called directly by Windows, including the window procedures and callback functions for dialog boxes and timer messages. This is the export section for the stock application:
EXPORTS MainWndProc
StatusWndProc
The linker then uses the DEF file to create an EXE file. Finally, use the resource compiler again to combine the binary resource file with the EXE file to form a new executable file with the binary resources tacked on. Once this is done, you have an executable file. To run the program, just enter the following command:
WIN STOCK
Finishing Up
There are no fancy features in this stock-charting application yet, but at least I created some generic skeleton code that you can use in all of your future Windows programming. This version of the program doesn't really do very much except display menu help items in response to a command being chosen.
You should now understand resource files, menus, and accelerators. You saw how menus and accelerators generate WM_COMMAND messages, which inform the application that the user chose a command. The next article will discuss child windows and control windows.