Windows Programming/Resource Script Reference

From Wikibooks, the open-content textbooks collection

Jump to: navigation, search

This appendix page will attempt to list the different types of resources, and will attempt to show how to use those resources.

Contents

[edit] Identifiers

Identifiers are generally named in a certain way, although the reader and all programmers are free to alter this naming scheme. It is simply a suggestion. Identifiers generally start with the prefix "ID", followed by a letter that denotes the type of identifier:

  • IDS: A string resource
  • IDM: A menu resource
  • IDC: A command identifier
  • IDD: A dialog box resource
  • IDA: An Accelerator table resource
  • IDI: An Icon or bitmap resource
  • IDB: A Bitmap resource
  • ID: A custom resource, or an uncommon resource type.

Sometimes, the command identifiers in a menu are given an "IDM_" prefix, to distinguish between commands from other sources.

[edit] DISCARDABLE

Resources are loaded into memory when the program is run. However, if a resource is not in use, and if Windows does not need them immediately, resources can be optionally unloaded from memory until needed. To specify that it is okay to unload an unused resource from memory, you may list the DISCARDABLE keyword with the resource. DISCARDABLE resources allow more efficient memory usage, but can slow down your program if they need to be loaded from disk.

The DISCARDABLE keyword is ignored for 32-bit Windows, but remains for compatibility. [1]

[edit] Icons

Icons can be stored in a resource file using the ICON keyword. Here is a general example of using an Icon in a resource script:

(icon ID number or name) ICON [DISCARDABLE] "iconfile.ico"

Windows explorer will display the program executable with the first icon from the script. For instance, if we load 2 icons, as such:

IDI_ICON1 ICON DISCARDABLE "icon1.ico"
IDI_ICON2 ICON DISCARDABLE "icon2.ico"

And we define our macros as such in our resource.h:

#define IDI_ICON1 1
#define IDI_ICON2 2

The executable file will have icon1.ico as its icon.

To Load an icon from an executable module, assuming we have an instance handle to the module ("hInst" in this example), we can get a handle to the icon as such:

HICON hIcon;
hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1));

This will return a handle to the icon associated with the identifier "IDI_ICON1". Icon identifiers are generally prefixed with an "IDI_" which is short for "ID for an Icon".

The second parameter to the LoadIcon function is a pointer to a string. String pointers are 32 bit values. However, if the most signficant 16 bits are all zero, Windows will treat the value as a resource number, and not a string. To make the conversion between a string and a 16-bit integer, Microsoft provides the MAKEINTRESOURCE macro. Similarly, we could have used a string to define our Icon:

MYICON1 ICON DISCARDABLE "icon1.ico"

And we could load this string by name:

HICON hIcon;
hIcon = LoadIcon(hInst, "MYICON1");

String identifiers for resources are case insensitive.

WNDCLASSEX has handle values for 2 icons: a large icon and a small icon. The small icon is the icon used in the upper-left corner. Small icons are generally 16 pixels square. Larger icons are 32 pixels square. If no small icon handle is provided, the large icon will be shrunk down to fit.

If the LoadIcon function is supplied with a NULL instance handle, Windows will supply a default icon for use.

Recently, the Win32 API provides the LoadImage function for loading icons, bitmaps, and mouse cursors from a single function. You can find more information about this function on MSDN.

[edit] Bitmaps

Bitmaps can be loaded similarly to Icons in resource files:

(bitmap ID or name) BITMAP [DISCARDABLE] "bitmapfile.bmp"

Bitmaps can be accessed with the aptly named LoadBitmap function (again, new versions of the Win32 API prefer you use LoadImage to load a bitmap, icon, or cursor). LoadBitmap returns an HBITMAP handle type:

HBITMAP hBmp;
hBmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP1));

Or, if we have named our bitmap resource:

hBmp = LoadBitmap(hInst, "MyBitmapRes");

Bitmaps are large resources, and if windows can't load the bitmap into memory (or if the ID or name value is invalid), the function will return a NULL value. Make sure you test this value before you use the handle.

Bitmaps must be unloaded from memory by passing the handle to the DestroyObject function. You can find more information about this on MSDN

Bitmap identifiers generally use a "IDB_" prefix, to indicate that it is the ID of a bitmap.

[edit] Mouse Cursors

Mouse cursors are specified similarly to icons and bitmaps, and are loaded with the LoadCursor function.

[edit] String Tables

A resource script can have many string tables, although this is unneccessary: the tables aren't differentiated, and each string object, in any table, must have a unique identifier. Strings in a string table also may not use names, but instead must use numeric identifiers. After all, it doesn't make any sense to have to address a string with a string, does it?

Here is a general string table:

STRINGTABLE DISCARDABLE
BEGIN
   IDS_STRING1, "This is my first string"
   IDS_STRING2, "This is my second string"
   ...
END

It is important to note that in place of the BEGIN and END keywords, the programmer may also use the more C-like curly brackets, as such:

STRINGTABLE DISCARDABLE
{
   IDS_STRING1, "This is my first string"
   IDS_STRING2, "This is my second string"
   ...
}

Some people prefer one over the other, but they are all the same to the resource compiler.

Strings can be loaded using the LoadString function. LoadString is more involved then the LoadBitmap or LoadIcon functions:

int LoadString(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax);

The hInstance parameter, as we know, is the instance handle for the module that contains the string. The uID parameter contains the string number that we are trying to access. lpBuffer is the character array variable that will receive the string, and the nBufferMax number tells windows what the maximum number of characters that can be loaded is. This count is a security precaution, so make sure not to allow Windows to write character data beyond the end of the string. MSDN displays a large warning on the page for this function, and it is important that programmers heed this warning. msdn

Windows will automatically zero-terminate the string, once it is written to the buffer. LoadString will return the number of characters that were actually written into the string, in case the number of characters is less then the maximum number allowed. If this return value is 0, the string resource does not exist, or could not be loaded.

[edit] Accelerators

Keyboard accelerators are a common part of nearly every windows application, and therefore it is a good idea to simplify the job of creating accelerators by putting them in a resource script. Here is how to create an accelerator table:

(Accelerator Table ID or name) ACCELERATORS [DISCARDABLE]
BEGIN
   (key combination), (Command ID)
   ...
END

Key combinations are specified in terms of either a string literal character ("A" for instance) or a virtual key code value. Here are some examples:

IDA_ACCEL_TABLE ACCELERATORS DISCARDABLE
BEGIN
   "A", IDA_ACTION_A //Shift+A
END

Now, when the key combination "Shift+A" is pressed, your window procedure will receive a WM_COMMAND message with the value IDA_ACTION_A in the WPARAM field of the message.

If we want to use combinations of the "Alt" key, or the "Ctrl" key, we can use the ALT and CONTROL keywords, respectively:

IDA_ACCEL_TABLE ACCELERATORS DISCARDABLE
BEGIN
   "a", IDA_ACTION_A, ALT          //Alt+A
   "b", IDA_ACTION_B, CONTROL      //Ctrl+B
   "c", IDA_ACTION_C, ALT, CONTROL //Alt+Ctrl+A
END

Also, we can use the "^" symbol to denote a CONTROL key code:

IDA_ACCEL_TABLE ACCELERATORS DISCARDABLE
BEGIN
   "^a", IDA_ACTION_A //Control+A
END

Similarly, if we want to be super hackers, would could use the ASCII code directly:

IDA_ACCEL_TABLE ACCELERATORS DISCARDABLE
BEGIN
   65, IDA_ACTION_A, ASCII //65 = "A", Shift+A
END

Or, we could refer to keys (including non-alphanumeric keys) with their Virtual Key Code identifiers, by using the VIRTKEY identifier:

IDA_ACCEL_TABLE ACCELERATORS DISCARDABLE
BEGIN
   VK_F12, IDA_ACTION_F12, VIRTKEY             //press the "F12 Key"
   VK_DELETE, IDA_ACTION_DEL, VIRTKEY, CONTROL //Ctrl+Delete
END

Now, If we make an accelerator correspond to a menu command, the menu command will light up when we press the accelerator. That is, the menu will light up unless we specify the "NOINVERT" keyword:

IDA_ACCEL_TABLE ACCELERATORS DISCARDABLE
BEGIN
   "A", IDA_ACTION_A, NOINVERT //Shift+A (non inverted menu selection)
END

To Load an accelerator table, we need to use the LoadAccelerators function, as such:

HACCEL hAccel;
hAccel = LoadAccelerators(hInst, MAKEINTRESOURCE(IDA_ACCEL_TABLE));

Again, we could have given our resource a string name, and used that string to load the table.

When using accelerators, we need to alter our message loop to intercept the keypress messages, and translate them into command messages according to our accelerator table rules. We use the TranslateAccelerator function, to intercept the keypress messages, and translate them into command messages, as such:

while ( (Result = GetMessage(&msg, NULL, 0, 0)) != 0)
{
    if (Result == -1)
    {
        // error handling
    }    
    else
    {
        if (!TranslateAccelerator(hwnd, haccel, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }    
    }    
}   

Also, if we are writing an MDI application, we need to intercept Accelerator messages from the child windows, we use the TranslateMDISysAccel function also:

while ( (Result = GetMessage(&msg, NULL, 0, 0)) != 0)
{
    if (Result == -1)
    {
        // error handling
    }    
    else
    {
        if (  !TranslateMDISysAccel(hwndClient, &msg)
           && !TranslateAccelerator(hwndFrame, haccel, &msg) )
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }    
    }    
}   

Where "hwndFrame" is the handle to the frame window, and "hwndClient" is the handle to the MDI client window.

[edit] Menus

Menus can be defined in a resource script using the MENU keyword. There are 2 types of items that appear in a menu, the top level "POPUP" menu items, and the secondary "MENUITEM" items. These are defined in a menu as such:

(ID or name) MENU [DISCARDABLE]
BEGIN
   POPUP "File"
   POPUP "Edit"
   BEGIN
      MENUITEM "Copy", IDM_EDIT_COPY
      MENUITEM "Paste", IDM_EDIT_PASTE
   END
   ...
 END

We have included a few examples here, so that you can see the difference between a POPUP and a MENUITEM. When we have a menu with the ID_MENU identifier, we can load it into our program as such:

HMENU hmenu;
hmenu = LoadMenu(hInst, MAKEINTRESOURCE(ID_MENU));

Once we have this handle, we can pass it to the CreateWindow function, and apply it to our window.

When a menu item is selected, the host program receives a WM_COMMAND message, with the menu item identifier in the WPARAM parameter. If we have a basic window procedure switch-case statement, we can see this as follows:

case WM_COMMAND:
   switch(WPARAM)
   {
       case IDM_EDIT_COPY:
          //handle this action
          break;
       case IDM_EDIT_PASTE:
          //handle this action
          break;
   }
   break;

In a menu, if we want to associate a menu item with an accelerator, we can define it as such:

ID_MENU MENU DISCARDABLE
BEGIN
   POPUP "File"
   POPUP "Edit"
   BEGIN
      MENUITEM "&Copy", IDM_EDIT_COPY
      MENUITEM "&Paste", IDM_EDIT_PASTE
   END
   ...
 END

Notice how we put the ampersand (&) in front of the "C" in "Copy" and the "P" in "Paste". This means that those letters will be underlined, but more importantly, if an accelerator key combination is pressed, those items in the menu will be highlighted (unless the NOINVERT tag is specified in the accelerator table). If an ampersand is placed before a POPUP menu item, pressing ALT+ that letter will popup that menu. For instance, lets define our menu:

ID_MENU MENU DISCARDABLE
BEGIN
   POPUP "&File"
   POPUP "&Edit"
   BEGIN
      MENUITEM "Copy", IDM_EDIT_COPY
      MENUITEM "Paste", IDM_EDIT_PASTE
   END
   ...
 END

Now, if we press ALT+F, we will pop open the File menu, and if we press ALT+E it will open the Edit menu. That's pretty nice functionality for only a single extra character to type.

[edit] Version Information

A program can include certain information about its version, and its author in a resource script. This version information appears when you right-click the executable in Windows, and click "Properties". In the properties dialog box, this information appears on the "Version" tab.

[edit] Dialog Boxes

Dialog box resources follow a general pattern:

(Dialog ID or name) DIALOG [DISCARDABLE] x, y, width, height
TITLE "(dialog box title)"
[CLASS "(class name)"]
FONT "(font name)"
BEGIN
   ...
END

if a dialog box is not being associated with a class, the CLASS field does not need to be filled in. All strings listed as being in quotes must be in quotes in the resource script or there will be an error. Individual items in a dialog box are then specified between the BEGIN and END tags.

[edit] Generic Controls

[edit] Specific Buttons

[edit] Edit Boxes

[edit] User-Defined Items

[edit] Generic Resources

Personal tools
Create a book