Introduction and a bare-bones PM application (Resources)
Written by Gavin Baker
Introduction to PM Programming | ||
---|---|---|
Part 1 | Part 2 | Part 3 |
Contents
Introduction
Menus, dialog boxes and icons are all examples of Resources in OS/2. Resources are stored in their own read-only segment within the executable file (or DLL), can be shared between multiple instances of a program, and are normally loaded only when required at runtime rather than at the load time of the application.
The most commonly used resource types along with their definition are shown below:
Type | Description |
---|---|
ACCELTABLE | Keyboard Accelerator table |
BITMAP | Bitmap |
DIALOG | Dialog box template |
FONT | Font |
MENU | Menu definition |
MESSAGETABLE | Application Message Strings |
POINTER | Icon or mouse pointer |
RCDATA* | Custom-defined resource |
STRINGTABLE | Strings |
Resources are created in two ways (depending on the type of resource). They are either text or binary. The binary resources are POINTER, BITMAP, and FONT. All the other resources are textual. The RCDATA type is special, as it allows the programmer to define a custom structure for a resource.
The RC.EXE program is called the Resource Compiler, and it takes the your source file and compiles it into a binary form (.RES). It also binds the .RES file with your executable.
We will examine the general syntax of resources and the structure of the RC file, and then examine each type in detail.
Scope
I am assuming that you are a competent C programmer, and have a working knowledge of OS/2 from a user's perspective. The sample code here was produced with Borland's Resource Workshop for PM and tested with the OS/2 Resource Compiler (RC).
Syntax and the RC File
Resources are defined in a text file with the .RC extension. There are a number of keywords for the different resource types, and each keyword defines one resource. Resources are referenced by an identifier, which takes the form of a C #define. Since the Resource Compiler (RC.EXE) supports C-like #includes and #defines, it is convenient to have all the symbols defined in one header file for the resources and their IDs. (Obviously they must have unique numbers). Resources are usually named according to a certain convention - ID followed by a single letter denoting the resource type, an underscore and then a descriptive name. Here are some examples:
#define IDM_FILE 10 /* the ID of the FILE Menu */ #define IDS_ERROR 300 /* the ID of the ERROR String */ #define IDD_OPTIONS 436 /* the ID of the OPTIONS Dialog */
Generally speaking, a resource statement consists of the following:
TYPE | IDENTIFIER | +-----+ | | | MEMORY | OPTIONS | | +-----+ | RESOURCE DEFINITION | | -
Due to the differing nature of resources, it is easier to show the syntax for each type's definition rather than to generalize here.
The options refer to the Memory Options, which specify how OS/2 treats the memory occupied by the resource. The memory options are as follows:
Option | Meaning |
---|---|
FIXED or MOVEABLE* |
Resource remains at a fixed point in memory Resource can be moved by the system in memory |
PRELOAD or LOADONCALL* |
Resource is loaded at load-time Resource is loaded when first referenced (run-time) |
DISCARDABLE | Resource can be discarded if not needed |
Note that the default options are marked with an asterisk. These options apply to all of the resource types.
Resources
In the following sections we will see each type of resource (at least the most common ones) and some examples, along with how to use them in your programs.
The syntax diagrams follow those conventions used in the Command Reference, but also note that keywords are underlined.
String Table
Syntax
STRINGTABLE | IDENTIFIER | +-----+ | | | MEMORY | OTIONS | | +-----+ | BEGIN | |<---------+ | | | IDENTIFIER | | | | STRING | | | +----------+ | END | | -
Notes
String tables are used to keep all of the static text which is used in a program in one place, thus making it easier to manage, and also to maintain versions in multiple languages. Ideally the program source code should be free of static or literal text, and instead use a STRINGTABLE to manage the text. Strings are loaded by using the WinLoadString call, and once loaded, are used exactly the same way as a normal string.
Example
STRINGTABLE ID_ERRORS FIXED BEGIN IDS_FILENOTFOUND "Sorry - I can't find that file anywhere!" IDS_NOGAMES "Games are not allowed during office hours." IDS_BYEBYE "Are you sure you really truly want to go?" END
Output
There is no output as such from this resource - you would use it in your program like this:
WinLoadString(hab, NULLHANDLE, IDS_BADCMD, MAXERRORLEN, pszError); WinMessageBox(HWND_DESKTOP,HWND_DESKTOP, pszError,"Error!",0, MB_CUACRITICAL | MB_OK);
This will load an error message from the executable file and display an error message in a box.
Message Table
Syntax
MESSAGETABLE | IDENTIFIER | +-----+ | | | MEMORY | OPTIONS | | +-----+ | BEGIN | |<---------+ | | | IDENTIFIER | | | | STRING | | | +----------+ | END | | -
Notes
A Message table works just the same way as a STRINGTABLE. Most applications use a STRINGTABLE, or use the MKMSGF (the Make MeSsaGe File utility, documented in the Toolkit Tools Reference).
Example
MESSAGETABLE ID_ERRORS BEGIN IDM_PRINTEDOK "The file has been successfully printed." IDM_SYNTAX "A syntax error was found on line %1." END
Menu
Syntax
MENU | IDENTIFIER | +----+ | | | MEMORY | OPTIONS | | +----+ | BEGIN | |<-----------------+ | | | MENUITEM | | | | TEXT | | | | IDENTIFIER | | | | STYLE | | | | BEGIN | | | |<-----------+ | | | | | | MENUITEM | | | | | | | TEXT | | | | | | | IDENTIFIER | | | | | | | STYLE | | | | | | | ATTRIBUTES | | | | | +------------+ | | | | END | | | +------------------+ | END | | -
Notes
I hope this diagram isn't too confusing - if you examine it, all it means is that a MENU consists of one or more SUBMENUs, which consist of one or more MENUITEMs. You can leave off the style and attributes if you don't want to specify any (see the example). Put a tilde ~ character in to specify that the following letter will be the underlined shortcut key.
Note: If you make the ID of the menu the same as your main window that you create with WinCreateStdWindow and use the FCF_MENU style when you create it, PM will automatically load the menu and assign it to the window.
Example
MENU ID_MAIN BEGIN SUBMENU "~File", IDM_FILE BEGIN MENUITEM "~New", IDM_FILENEW MENUITEM "~Open...", IDM_FILEOPEN MENUITEM "~Save", IDM_FILESAVE MENUITEM "Save ~As...",IDM_FILESAVEAS END SUBMENU "Fon~t", IDM_FONT BEGIN MENUITEM "~Small", IDM_FONTSMALL MENUITEM "~Medium", IDM_FONTMED, MIS_TEXT, MIA_CHECKED MENUITEM "~Large", IDM_FONTLARGE MENUITEM SEPARATOR MENUITEM "~Options...",IDM_FONTOPTIONS END END
Output
Dialog
Syntax
The dialog template itself:
DLGTEMPLATE | IDENTIFIER | +----+ | | | MEMORY | OPTIONS | | +----+ | BEGIN | DIALOG | TITLE, ID, X, Y, WIDTH, HEIGHT | +----+ | | | STYLES | | +----+ | BEGIN | |<---------+ | | | CONTROL | DEFINITION | | | +----------+ | END | | END | | -
The Control Definition:
CONTROL | TEXT | ID | X | Y | WIDTH | HEIGHT | +----+ | | | STYLES | | +----+ | -
Notes
A dialog template is used to define a dialog, which contains many controls. The control can be a custom control, or one of the following:
- AUTOCHECKBOX
- AUTORADIOBUTTON
- CHECKBOX
- DEFPUSHBUTTON
- GROUPBOX
- PUSHBUTTON
- RADIOBUTTON
- ENTRYFIELD
to name a few. Consult the Toolkit documentation for a complete description of all the different controls. Once you know how to use one, the others work basically the same.
Example
This example was produced with Borland's Resource Workshop for PM (part of Borland C++ for OS/2), which makes it easy to visually design dialogs and other resources. The IBM Toolkit also includes a Dialog Editor.
As you can see, a reasonably simple dialog can get fairly complex. If you were to write this by hand it would take hours to figure out the X and Y positions, flags, etc. This is not practical for anything but the simplest of dialogs, so a dialog editor (such as the two mentioned above) is invaluable.
This may seem complicated, but it is fairly straightforward. Everything except the buttons is defined as a CONTROL (a generic way of specifying a control). The type of control is given in the flags, for example the comment edit field is defined as a WC_ENTRYFIELD, and has its own specific flags (ES_LEFT and the others). There are lots of flags specified (more than if you had done it by hand) but most have reasonable defaults.
Three things to note:
- The order is important - it is the order the user tabs through in.
- The WS_TABSTOP flag must be specified if you want the user to be able to tab to the control under keyboard control.
- Groups (WS_GROUP) are mainly used to group together automatic radio buttons, so they turn each other off and on.
DLGTEMPLATE 1 BEGIN DIALOG "Sample Dialog", 100, 30, 90, 300, 150, WS_VISIBLE, FCF_SYSMENU | FCF_TITLEBAR BEGIN CONTROL "", 109, 44, 104, 72, 35, WC_COMBOBOX, CBS_DROPDOWN | ES_ANY | WS_VISIBLE | WS_GROUP | WS_TABSTOP CONTROL "", 112, 156, 128, 133, 9, WC_ENTRYFIELD, ES_LEFT | ES_AUTOSCROLL | ES_MARGIN | ES_ANY | WS_VISIBLE | WS_GROUP | WS_TABSTOP CONTROL "~Preload", 102, 20, 96, 50, 10, WC_BUTTON, BS_AUTORADIOBUTTON | WS_VISIBLE | WS_GROUP | WS_TABSTOP CONTROL "~Load on Call", 103, 20, 80, 72, 10, WC_BUTTON, BS_AUTORADIOBUTTON | WS_VISIBLE | WS_TABSTOP CONTROL "~Fixed", 104, 104, 96, 50, 10, WC_BUTTON, BS_AUTORADIOBUTTON | WS_VISIBLE | WS_GROUP | WS_TABSTOP CONTROL "~Moveable", 105, 104, 80, 50, 10, WC_BUTTON, BS_AUTORADIOBUTTON | WS_VISIBLE | WS_TABSTOP CONTROL "~Discardable", 106, 20, 56, 68, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE | WS_GROUP | WS_TABSTOP CONTROL "", 107, 172, 84, 48, 12, WC_SPINBUTTON, SPBS_MASTER | SPBS_ALLCHARACTERS | SPBS_JUSTLEFT | WS_VISIBLE | WS_GROUP | WS_TABSTOP CONTROL "", 108, 236, 84, 48, 12, WC_SPINBUTTON, SPBS_MASTER | SPBS_ALLCHARACTERS | SPBS_JUSTLEFT | WS_VISIBLE | WS_GROUP | WS_TABSTOP CONTROL "", 113, 172, 56, 48, 12, WC_SPINBUTTON, SPBS_MASTER | SPBS_ALLCHARACTERS | SPBS_JUSTLEFT | WS_VISIBLE | WS_GROUP | WS_TABSTOP CONTROL "", 114, 236, 56, 48, 12, WC_SPINBUTTON, SPBS_MASTER | SPBS_ALLCHARACTERS | SPBS_JUSTLEFT | WS_VISIBLE | WS_GROUP | WS_TABSTOP CONTROL "", 121, 16, 26, 268, 12, WC_ENTRYFIELD, ES_LEFT | ES_AUTOSCROLL | ES_MARGIN | ES_ANY | WS_VISIBLE | WS_GROUP | WS_TABSTOP CONTROL "~Memory Options", 101, 10, 48, 150, 72, WC_STATIC, SS_GROUPBOX | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE | WS_GROUP CONTROL "T~ype", 110, 8, 128, 27, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE | WS_GROUP CONTROL "~Text", 111, 130, 128, 24, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE | WS_GROUP CONTROL "X", 115, 172, 96, 32, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE CONTROL "Size & Position", 116, 163, 48, 129, 72, WC_STATIC, SS_GROUPBOX | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE | WS_GROUP CONTROL "Y", 117, 238, 96, 32, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE CONTROL "Width", 118, 172, 72, 45, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE CONTROL "Height", 119, 236, 72, 45, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE CONTROL "Comment", 120, 10, 20, 282, 28, WC_STATIC, SS_GROUPBOX | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE | WS_GROUP DEFPUSHBUTTON "OK", DID_OK, 6, 4, 51, 14 PUSHBUTTON "Cancel", DID_CANCEL, 60, 4, 51, 14 PUSHBUTTON "Help", 998, 114, 4, 51, 14, BS_HELP END END
Output
Fonts, Icons, Pointers, and Bitmaps
Syntax
| +-------+ | | FONT | BITMAP | POINTER | | | +-------+ | IDENTIFIER | +----+ | | | MEMORY | OPTIONS | | +----+ | FILENAME | | -
Notes
Fonts, icons, pointers and bitmaps are all treated in the same way. (In fact icons and pointers are more or less identical). They are all defined externally in their own binary file, and are bound in when the resources are compiled.
There are editors available to design your own binary resources. An Icon Editor (also used for pointers and small bitmaps) is included in base OS/2, and there is a Font Editor in the Toolkit.
Example
BITMAP IDB_SMILEY Smiley.Bmp ICON IDI_MYPROG Whiz.Ico FONT IDF_BIGFONT Large.Fnt
Output
<Insert your favourite graphic here>
Roundup
Well, there you have Resources in a nutshell. You will find that tools such as Borland's Resource Workshop and those included with IBM's Toolkit can save you from ever having to understand all that we have just discussed, as you can point and click and the work is done for you.
However, it is very useful to know just how resources are created as it gives you a better understanding of just what you are doing.
Now for those of you who have eagerly gone to consult your manuals (or the header files for that matter), you will have noticed that I left out a few resource types. I did this to save both time and space, and also because they are infrequently used. I won't dare say that it is left as an exercise for the reader, but if there is enough demand I will cover the remaining types in a later article.
What Next?
Next we look at the Graphics Programming Interface (GPI).
I would love to hear from you about what you thought, how useful it was, whether or not there was too much or not enough information, if it was too wordy or too simple - in short any and all comments are most welcome. Also, if there is something specific you would like to see covered, drop me a line too.
Bibliography
The following references were used in the preparation of this article:
- OS/2 Version 2.0 - The Redbooks
- OS/2 Version 2.0 Technical Library
The following products were mentioned:
- IBM OS/2 Toolkit Version 2.0
- Borland C++ for OS/2 Version 1.0