Aug 98 Tips
Volume Number: 14 (1998)
Issue Number: 8
Column Tag: Tips & Tidbits
August 1998 Tips
by Steve Sisak, email@example.com
Gotcha - Calling GetResource()
If you call Get1Resource(), expecting to get a resource from the topmost resource file, you can be unpleasantly surprised. With the introduction of the "Fonts" folder in System 7.1, a patch was made to the resource manager so that all the files in the fonts folder will appear to be part of the System file, even though they are not.
Most of the time this is not a problem, since most people don't care if a resource is in the System file or in a file in the fonts folder (or in the enabler, or in ROM).
However, if you absolutely need to know the file where a resource is loading from, you can use HomeResFile(). It will return the refNum of the resource file the resource came from.
Marshall Clow, Adobe Systems
Determining if a Resource File was Actually Opened
When you use any of the Resource Manager calls for opening a resource file, and the resource file is already open by the Resource Manager with that access, it will not open the file again. Instead, it returns the refNum of the already-open reference, and also does the equivalent of a UseResFile() on that refNum.
This means you have to be careful if your code is capable of opening and closing arbitrary resource files - if the Resource Manager didn't actually open the file for you (for example if you were to open your own application, or the System file, or a suitcase in the Fonts folder), then you must not close it with CloseResFile().
So how do you tell if the resource file was actually opened for you or not?
It's easy: if the resource file was opened, then its resource map will be added to the top of the in-memory chain of resource maps (pointed to by the "TopMapHndl" low-memory global). If not, then the chain remains unchanged.
The following sequence illustrates the idea:
SInt16 TheResFile, PreviousResFile;
PreviousResFile = CurResFile();
PreviousTop = LMGetTopMapHndl();
TheResFile = FSpOpenResFile(ResFileSpec, Permissions);
/* checking for errors omitted */
ReallyOpened = LMGetTopMapHndl() != PreviousTop;
/* do your processing on the resources, then when finished, restore things as they were: */
Lawrence D'Oliveiro, Hamilton, New Zealand
Serial Port Tidbits Comments
Thanks for the informative article bringing together a lot of previously hard to find information. I spent many hours digging around (and cursing!) trying to find that same info.
I had written a similar routine to your FindPortInfo() routine, and after checking mine, I initially thought there might be a bug in yours. I finally realized that your code was in fact right, but there is a subtlety which might not be apparent to readers.
In the line:
while ((crm = CRMSearch(crm)) != nil)
a key point is that you are reassigning to crm the result of the search.
In my code I was using a temporary variable to pass to CRMSearch(), as in
while ((foundCRM = CRMSearch(tempCRM)) != nil)
This means that in my code, after the EqualString() check, I need to insert:
tempCRM->crmDeviceID = foundCRM->crmDeviceID;
to avoid a potential infinite loop.
Your code (and the code in the CTB book) avoids this by using the same variable in the assignment, but that also hides this subtle point CRMSearch() starts looking from the device ID passed to it in the crmDeviceID field of the CRMRecPtr passed to it.
One other thing I'd like to mention is that instead of your IsDriverOpen() routine, you could call the Connection Resource Manager routine CRMIsDriverOpen(), described in the Communications Toolbox 1.1 Engineering Notes (not in the original CTB book - the 1.1 notes are another hard-to-find source...)
Jim Wintermyre, E-mu Systems, Inc.
Ed Note: The fact that CRMSearch() looks at the deviceID and deviceType passed in and returns the device of the same type with the next higher ID. This is a subtlety worth noting. Also, the CTB 1.1 Engineering Notes are an important resource I forgot to mention in the original article.