A Resource Programming Example

In the simplest case, an application can create a resource and add it to a resource file simply by defining the resource as a structure in the application's local memory, initializing it, and finally adding it using mdlResource_add. This method (demonstrated below) does not demonstrate how to handle variable sized arrays, which must be buffered before being added to a resource file.

The following function also shows the incoming resource being updated to reflect the date last accessed via the time function and then being rewritten to the resource file.

/*-----------------------------------------------------------------+
| name initApplicationDefaults |
| |
| Initializes our application data. |
| |
| author BSI 4/91 |
+-----------------------------------------------------------------
Private void initApplicationDefaults
(
void
)
{
OurSettings *prefsDataP;
int prefsRscSize;
if ((prefsDataP = mdlResource_load(rscHandle, RTYPE_SprinklerDefaults,
RSCID_SprinklerDefaults)) == NULL)
{
// resource does not exist, load defaults manually and then
// write the preferences to the file
prefsData.sprinklerSettings.shape = 0;
prefsData.sprinklerSettings.sweep = 360;
prefsData.sprinklerSettings.spray = 0;
prefsData.activePipeType = PIPE_MAINLINE;
prefsData.pipeSettingsP = &mainlineSettings;
prefsData.mainlineSettings.diameter = 3;
prefsData.mainlineSettings.color = 7;
prefsData.mainlineSectionLength = 100.0 * tcb->uorpersub;
prefsData.lateralSettings.diameter = 1;
prefsData.lateralSettings.color = 10;
prefsData.pumpSettings.maxFlowRate = 200;
prefsData.pumpSettings.goldPlated = FALSE;
prefsData.lastAccessed = prefsData.created = time(NULL);
mdlResource_add(rscHandle, RTYPE_OurSettingsPrefs,
RSCID_SettingsPrefs, &prefsData,
sizeof(OurSettings), NULL);
}
else
{
// load settings from resource
mdlResource_query(&prefsRscSize, prefsDataP, RSC_QRY_SIZE);
mempcy(&prefsData, prefsDataP, prefsRscSize);
// Update access time and write back to prefs file
prefsDataP->lastAccessed = time(NULL);
mdlResource_write(prefsDataP);
// ALWAYS remember to free the resource....
mdlResource_free(prefsDataP);
}
mdlDialog_synonymsSynch(NULL, SYNONYMID_SprinklerSettings, NULL);
prefsData.simulationSettings.currFlowRate = 50;
prefsData.simulationSettings.wettedColor = 11; // YELLOW
}

Working with resources containing variable sized arrays means that the application is required to know where in the resource structure it is at all times, or needs to calculate the proper position using mdlDialog_fixResourceAddress as described above.Once you know how to traverse a structure and how the structure is put together, modifying and creating the structure becomes relatively straightforward.

The key areas to be concerned about when doing this are:

  1. Once mdlDialog_fixResourceAddress is required, it must continue to be used from that point forward.
  2. Remember that variable sized arrays are stored as a long length N followed by N instances of the array entry.Note that variable sized character arrays are always NULL terminated.This means that every variable sized character array has a length of 1 plus the number of characters in the array - an empty array has a length of 1 and a single entry set to 0.
  3. When creating new resources, allocate a memory area that will be large enough to contain the whole resource structure.
  4. When resizing resources, do the same as above, copy the resource into the new area, resize the resource, and then copy the data back into the resized resource.

The following sample function performs both the modification and creation of a text item.

-----------------------------------------------------------------+
| |
| name updateAndCreateTextRsc |
| |
| This function will update a text resource which was passed in |
| and also create a new text resource |
| |
| author BSI 10/92 |
| |
| typedef struct ditem_textrsc |
| { |
| ULong commandNumber; |
| ULong commandSource; |
| long synonymsId; |
| ULong helpInfo; |
| ULong helpSource; |
| long itemHookId; |
| long itemHookArg; |
| byte maxSize; // max # of chars in field // |
| char formatToDisplay[16]; // format string to convert |
| from internal // |
| char formatToInternal[16]; // convert to internal from |
| display str // |
| char minimum[16]; // minimum value // |
| char maximum[16]; // maximum value // |
| ULong mask; // only used with integers // |
| UShort attributes; // other attributes // |
| #if defined (resource) |
| char label[]; |
| char accessStr[]; |
| #else |
| long labelLength; |
| char label[1]; |
| #endif |
| |
+------------------------------------------------------------
Public void updateAndCreateTextRsc
(
long rscId, // => resource id
void *rsrcP // => Resource loaded from tempFileH
)
{
long baseRscSize, itemRscSize;
void *rscP;
DItem_TextRsc *nrsrcP = rsrcP;
DItem_TextRsc *newTextRscP;
void *tmpRscP, *auxInfoP;
long sAuxInfo;
if (rsrcP)
{
// Before doing anything else, modify the resource - since
//we may be changing the size of the resource as well as
//modifying information within it, we must locate all variable
//information, copy out what we need and also calculate the
//size of the new resource.
// First lets get past the label to the access string
tmpRscP = mdlDialog_fixResourceAddress((char *) rsrcP,
(char *) nrsrcP->label +
nrsrcP->labelLength, sizeof(long));
// Get the length of the access string and save the string
sAuxInfo = *((long *) tmpRscP) + sizeof(long);
auxInfoP = malloc((int) sAuxInfo);
memcpy(auxInfoP, tmpRscP, (int) sAuxInfo);
// Now determine the new size of the resource. First get the
// size of everything up to the access string loc, then the
// then the whole resource.
baseRscSize = (long) (mdlDialog_fixResourceAddress((char *) rsrcP,
(char *) nrsrcP->label + strlen(dialogP->text) + 1,
sizeof(long)) - rsrcP);
itemRscSize = (long) mdlDialog_fixResourceAddress(NULL,
(char *) (baseRscSize + sAuxInfo), sizeof(long));
// Now resize the resource and modify the info.
nrsrcP = mdlResource_resize(rsrcP, itemRscSize);
// If couldn't resize the resource, error
if (!nrsrcP)
{
sprintf(dialogP->text, "Error on resize (temp): %d",
mdlDialog_openAlert(dialogP->text);
}
// Assign the new information to the resource
nrsrcP->attributes = dialogP->itemAttributes & 0x0ffff;
nrsrcP->mask = dialogP->mask;
nrsrcP->maxSize = dialogP->textAttrs.maxSize & 0x0ff;
newdiRP->itemArg = dialogP->itemArg;
strcpy(nrsrcP->formatToDisplay, dialogP->textAttrs.ftd);
strcpy(nrsrcP->formatToInternal, dialogP->textAttrs.fti);
if (!dialogP->textAttrs.max[0])
{
if (dialogP->textAttrs.min[0])
strcpy(dialogP->textAttrs.max,
dialogP->textAttrs.min);
}
else
{
if (!dialogP->textAttrs.min[0])
strcpy(dialogP->textAttrs.min,
dialogP->textAttrs.max);
}
strcpy(nrsrcP->minimum, dialogP->textAttrs.min);
strcpy(nrsrcP->maximum, dialogP->textAttrs.max);
// Copy new label into the resource
nrsrcP->labelLength = strlen(dialogP->text) + 1;
if (strlen(dialogP->text))
strcpy(nrsrcP->label, dialogP->text);
else
nrsrcP->label[0] = '\0';
// Address the access string and copy that information back
// into the resource
rscP = (void *) mdlDialog_fixResourceAddress((char *) nrsrcP,
(char *) nrsrcP->label + nrsrcP->labelLength,
sizeof(long));
memcpy(rscP, auxInfoP, sAuxInfo);
free(auxInfoP);
// Now write the modified resource into memory
// To address Resource Manager bug, close & reopen rsc file
mdlResource_closeFile(dialogP->tempFileH);
mdlResource_openFile(&dialogP->tempFileH,
tempRscFileName, TRUE);
// Reload the resource
nrsrcP = mdlResource_load(dialogP->tempFileH,
RTYPE_Text, rscId);
}
// Now create a new text resource with no access string and the same
// same label as the one we just updated append with "-New"
// We first need to determine the size of our new rsc by going to the
// label location, adding in the len of the existing label and the
// length of the extension. Then we need to add in the length of the
// NULL access string to get the full resource size
baseRscSize =
(long) (mdlDialog_fixResourceAddress((char *) nrsrcP,
(char *) nrsrcP->label + nrsrcP->labelLen + strlen("-New"),
sizeof(long)) - nrsrcP);
itemRscSize = (long) mdlDialog_fixResourceAddress(NULL,
(char *) (baseRscSize + sizeof(long) + 1,
sizeof(long));
// Now malloc the resource, initialize it, and add it to the
the resource file
if (newTextRscP = malloc(itemRscSize))
{
memset(newTextRscP, 0, itemRscSize);
newTextRscP->attributes = TEXTATTR_NOCONCAT;
newTextRscP->mask = NOMASK;
newTextRscP->maxSize = 45;
newdiRP->itemArg = NOARG;
strcpy(newTextRscP->formatToDisplay, "%s");
strcpy(newTextRscP->formatToInternal, "%s");
// Copy new label into the resource
newTextRscP->labelLength = nrsrcP->labelLen + strlen("-New");
strcpy(newTextRscP->label, nrsrcP->label);
strcat(newTextRscP->label, "-New");
// Address the access string and indicate that a NULL
// string is enclosed - no access string
((char *) newTextRscP,
(char *) newTextRscP->label +
newTextRscP->labelLength, sizeof(long));
(long *) rscP = 1L;
// Now add the resource to the file
mdlResource_add(dialogP->tempFileH, RTYPE_Text, rscId + 100,
newTextRscP, itemRscSize, NULL);
}
}

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