The MicroStation Resource Manager

The MicroStation Resource Manager provides the applications programmer with a number of functions that allow the user to read (load), modify, write, create and delete resources to and from resource files. These are the low level functions used by the other subsystems mentioned above and are the only safe direct interface to resources. The following sections discuss various aspects of resource file and resource item management.

Resource File Management

In order to reference any resources, an application must have access to the resource file containing those resources. An application gains access to resources through three methods:

  1. Opening resource files using the mdlResource_openFile function.
  2. By "importing" the resource handle from another task.
  3. Inheriting them from parent tasks.

An application can open as many resource files as it needs for its processing. It can also open resource files currently opened by another task within MicroStation. Although an application does not necessarily need to keep track of the resource file handles after opening the files, the handle is required for applications to load a resource from a specific file and to close or add resources to a file. In most cases, an application will simply call mdlResource_openFile upon entry to main function and mdlResource_closeFile prior to exiting the application as shown below:

#include <mdl.h>
#include <rscdefs.h>
main(int argc, char *argv[])
{
RscFileHandle rscHandle;
...
// Open the application resource file for READ access. If error
// issue an error message and exit
if (mdlResource_openFile(&rscHandle, NULL, FALSE))
{
mdlOutput_errorU("Unable to open resource file");
}
...
// Close the resource file before we exit
}

For most applications, no additional mdlResource_... function calls are needed to perform any resource references, as this is handled by the various subsystem managers.In cases where the application needs to update resource information in a file, it must open the file for Read / Write access by passing RSC_READWRITE as the last parameter to mdlResource_openFile.

The mdlResource_createFile function allows the user to create new resource files.This function is useful to applications which need to maintain application specific user preferences or other information in a separate file. Remember that this function does not open the file; mdlResource_openFile must be called after this function to place resources into the file.

Loading and querying resources

When an application wants to load a resource from a resource file into memory for use, it uses one of the Resource Manager load functions. These functions provide differing levels of access to the resource information in a resource file. On occasion, it may be necessary to retrieve information about resources and resource files. The mdlResource_query... functions provide this capability. An additional query function is also provided to return information about resources already loaded by the application program.

Loading Resources

Typically, an application doesn't care where a resource is found (i.e., which file it came from) since all of the resources specific to the application are typically placed in their own resource files and any other resources it uses it expects to inherit from its parents. This being the case, an application will typically use the mdlResource_load and mdlResource_loadWString functions specifying NULL as the resource file handle. This has the effect of causing the MicroStation Resource Manager to start looking for the specified resource in the application's resource files and then resource files in the order of most recently opened first until it locates the resource requested. Once the resource is found, it is loaded into memory and the address of the resource is returned to the application. If the resource is not found, NULL is returned to the application. This is shown graphically in the diagram below.

MDL_Programmer's_Guide-04-07-1.jpg

It is important to remember that resources loaded into memory with the mdlResource_load function must be freed using mdlResource_free when the application is done with the resource. If the requested resource was not previously loaded by the Resource Manager, mdlResource_load will load the requested resource into memory allocated by the Resource Manager as it is read from the file and return the address of the resource to the application program. This action is performed only once. If the resource was already loaded, the Resource Manager will simply return the address of the loaded resource to the application.

The mdlResource_loadWString function is a specialized version of the mdlResource_load function which allows the application to extract a single string out of a message list resource without loading the message list resource and extracting the string itself. Since only the string from the message list is returned, the application does not need to free the resource from memory.

The other function which can be used to load resources into memory is the mdlResource_directLoad function. This function does not perform the resource load operation, but instead gives the application program information about the resource so that the application can perform its own resource file loading. The first three parameters of this function are the same as those for the mdlResource_load function. A fourth parameter is passed to this function which is a pointer to a structure into which the function returns the necessary information for the application to read the resource. This structure is defined in rscdefs.h and shown below.

typedef struct rscdirectaccess
{
RscFileHandle rfHandle; // resource file handle
FILE *filerP; // resource file pointer from fopen
unsigned long filePos; // position of resource in the file
unsigned long rscSize; // size of the resource

Once the application has this information, it can read the resource file itself instead of relying on the Resource Manager to read the resource.This gives the application complete control of the resource and the memory it occupies.The application does not have to be concerned about more of the resource being read than it needs or keep the resource file open after the resource has been read.The application does need to allocate the memory into which the resource is read.

Querying Resource Information

Four functions are provided for retrieving information about resources and resource files. These functions provide a tiered query structure in which an application can query:

This information can be useful for applications which may need to perform lookups and or processing of multiple resources and files. A sample section of code below shows the use of these functions. This function locates all resources of a specified class in a specified resource file and returns information about both the resource file (the file handle) and the resource located. It returns information about one resource at a time.

int findResourceInfo
(
char *rscFile, // Name of file resource we are using
ULong class, // Type of resource we are looking for
RscFileHandle *rscHandle, // Resource file containing resources
Long *rscId, // Resource ID of the one we found
ULong *rscSize, // Size of the resource we found
void *resource // The resource we found
)
{
static int rscIndex = -1;
static int rscCount = 0;
static ULong lastClass = 0L;
ULong *classes;
int i, numClasses;
// If we have a left over resource - free it now
if (resource)
mdlResource_free(resource);
// If don't have any info yet then get initial info
//from the resource file
if ((rscId == 0L) || (class != lastClass))
{
lastClass = class;
if (*rscHandle) // Close previous rsrc file if open
mdlResource_fileClose(*rscHandle);
*rscHandle = 0;
// Get number of resource classes in file
if (mdlResource_queryFile(&numClasses, rscFile,
return(ERROR);
if (!(classes = malloc(sizeof(ULong) * numClasses)))
return(ERROR);
// Now step through classes looking for the one we want
for (i = 0; i < numClasses; i++)
if (classes[i] == class)
break;
if (i >= numClasses)
return(ERROR);
// Now open the rsrc file & initialize the processing info
if (mdlResource_openFile(rscHandle, rscFile, FALSE))
return(ERROR);
rscIndex = -1;
if (mdlResource_queryClass(&rscCount, *rscHandle, class,
{
mdlResource_closeFile(*rscHandle);
*rscHandle = 0;
return(ERROR);
}
}
// If we are here, we have an open rsrc file and the number of
// resources in the rsrc file for the class we're looking for
*rscId = 0L;
*rscSize = 0L;
if (++rscIndex >= rscCount)
{
// We are done with the current resource file - clean up
mdlResource_closeFile(*rscHandle);
*rscHandle = 0;
rscIndex = -1;
rscCount = 0;
}
else
{
// Not done with the current rsrc file - get next resource
if (mdlResource_queryClass(rscId, *rscHandle, class,
RSC_QRY_ID, &rscIndex))
return(ERROR);
// Load found resource into memory
if (!(resource = mdlResource_load(*rscHandle, class, *rscId)))
return (ERROR);
// Get resource size information
if (mdlResource_query(rscSize, resource, RSC_QRY_SIZE))
return (ERROR);
}
return (SUCCESS);
}

Copyright © 2017 Bentley Systems, Incorporated. All rights reserved.