Introduction and a bare-bones PM application (Resources)

From EDM2
Jump to: navigation, search

Written by Gavin Baker

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 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

Screen Capture

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

IntroPM-dialog.gif

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 excercise 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