16.2.5 Managing Resources

A resource is read-only data—stored in your application's .EXE file or your library's .DLL file—that Windows reads from disk on demand. Certain types of resources have prescribed formats recognized by Windows. These include bitmaps, icons, cursors, dialog boxes, and fonts. You can create these resources by using the resource editors included in the Microsoft Windows 3.1 Software Development Kit (SDK): Microsoft Image Editor (IMAGEDIT.EXE), Microsoft Dialog Editor (DLGEDIT.EXE), and Microsoft Windows Font Editor (FONTEDIT.EXE). You link these resources into your .EXE or .DLL file by using Microsoft Windows Resource Compiler (RC). You take advantage of Windows' ability to work with these resource formats by calling associated functions such as LoadIcon and CreateDialog.

A resource is read into memory by Windows as a single data segment. The resource may be declared in the resource-definition file to be fixed, movable, or discardable. When determining whether a resource should be fixed, movable, or discardable, you should take into account the same considerations as you would for a global memory object.

If you declare a resource by using the PRELOAD option, Windows loads the resource into memory during the startup of your application. Otherwise, Windows loads it when it is needed (the LOADONCALL option).

In addition to using resources whose formats Windows recognizes, you can also develop resources only your application recognizes. The data may be in any format that you design, including ASCII text, binary data, or a mixture of these.

When deciding whether to maintain data as a resource or as a separate file, consider the following:

By compiling the resource into your application's .EXE file, you simplify the packaging of your application. You and your user need not worry about installing additional data files along with the application's .EXE file.

On the other hand, maintaining the data as a resource means that you must recompile your application's .EXE file if you change the data. If you plan to distribute updated data to several users, you may find it easier to distribute a new data file rather than a new .EXE file.

For more information about compiling a user-defined resource into an .EXE or .DLL file, see Microsoft Windows Programming Tools.

16.2.5.1 Locating a Custom Resource

The FindResource function determines the location of the resource according to the name specified in your resource-definition file. The function returns a handle, which you can then use in a call to the LoadResource function to load the resource. The resource handle returned by FindResource refers to information that describes the resource type declared in the resource-definition file, the position of the resource in the .EXE or .DLL file, and the size of the resource.

For example, suppose you want to maintain an ASCII text file as a resource. The source text file is named MYTEXT.TXT. You name the resource MyText, and you arbitrarily name the resource type TEXT. The resource-definition statement for this resource is as follows:

MyText TEXT MyText.txt

In your application, you retrieve the resource handle by calling FindResource, as follows:

HANDLE hMyTextResLoc;
      .
      .
      .

    hMyTextResLoc = FindResource(hinst, "MyText", "TEXT");

16.2.5.2 Loading a Custom Resource

The call to FindResource does not load the resource from the .EXE or .DLL file into memory. Rather, it finds only the location of the resource and returns the result of the search as a handle that points to the resource-location information. To load the resource into memory, you call the LoadResource function, as follows:

HRSRC hMyTextResLoc;
    HGLOBAL hMyTextRes;
      .
      .
      .

    hMyTextResLoc = FindResource(hinst, "MyText", "TEXT");
    if (!hMyTextRes = LoadResource(hinst, hMyTextResLoc)) {

        /*
         * Handle the case that memory is not available
         * to load resource.
         */

    }

LoadResource itself calls GlobalAlloc to allocate the memory object for the resource data, and then copies the data from disk to the memory object.

16.2.5.3 Locking and Unlocking a Custom Resource

To access the resource data now residing in a global memory object, you must call the LockResource function to lock the resource and retrieve a far pointer to the data. This is equivalent to using the GlobalLock function to retrieve the far pointer to a memory object allocated by the GlobalAlloc function. The following example continues the previous one:

LPSTR lpstrMyText;
      .
      .
      .

    lpstrMyText = LockResource(hMyTextRes);

Once you have the far address to the resource, you can read it as you would from a global memory object locked by GlobalLock.

If you have defined the resource as discardable and it has been discarded, LockResource will first load the resource back from disk. Unlike GlobalLock, LockResource saves you the trouble of calling LoadResource again if the resource has been discarded.

You should call UnlockResource when you are not in the process of accessing the resource data. This function is equivalent to GlobalUnlock. If you declare the resource as movable or discardable, this provides Windows the flexibility to move or discard the resource from memory as necessary to satisfy other memory-allocation requests.

16.2.5.4 Freeing a Custom Resource

The FreeResource function is similar to the GlobalFree function. It discards the memory used by the resource data as well as by the resource handle. If you need to load the resource again, you can call LoadResource, using the resource location handle returned by your initial call to FindResource.