Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: More Macintosh Toolbox /
Chapter 1 - Resource Manager / Using the Resource Manager


Opening a Resource Fork

When your application opens a file's resource fork or data fork, the File Manager returns a file reference number. You use a file reference number in File Manager routines (and
in a few Resource Manager routines) to identify a unique access path to an open fork of a specific file. Even though the file reference number of the data fork and the resource fork usually match, you should use the file reference number of a file's resource fork in Resource Manager routines; don't assume that it has the same value as the file reference number for the same file's data fork.

Opening an Application's Resource Fork

Because system software automatically opens your application's resource fork when the user opens your application, you do not need to open it explicitly. However, you should save your application's file reference number. You can do this by calling the CurResFile function early in your initialization procedure. (The CurResFile function returns the file reference number of the current resource file.) Listing 1-5 shows the part of SurfWriter's initialization procedure that gets the file reference number of the application's resource fork.

Listing 1-5 Getting the file reference number for your application's resource fork

PROCEDURE MyInitialize;
BEGIN
   MaxApplZone;         {extend heap zone to limit}
   MoreMasters;         {get 64 more master pointers}
   MoreMasters;         {get 64 more master pointers}
   InitGraf(@thePort);  {initialize QuickDraw}
   InitFonts;           {initialize Font Manager}
   InitWindows;         {initialize Window Manager}
   TEInit;              {initialize TextEdit}
   InitDialogs(Nil);    {initialize Dialog Manager}
   InitCursor;          {set cursor to arrow}
   {get the file ref num of this app's resource file }
   { and save it in a global variable}
   gAppsResourceFork := CurResFile;
   {do other initialization}
END;
SurfWriter uses an application-defined global variable (gAppsResourceFork) to refer to its resource fork in subsequent calls to Resource Manager routines.

Creating and Opening a Resource Fork

To save resources in the resource fork of a file, you must first create the resource fork (if it doesn't already exist in a form that can be used by the Resource Manager) and obtain a file reference number for it. After creating a new resource fork, you must open it before writing any resources to it. You'll usually want to save the file reference number of any resource fork that your application opens.

To create a resource fork, use the FSpCreateResFile procedure. This procedure requires four parameters: a file-system specification record (identifying the name and location of the file), the signature of the application creating the file, the file type of the file, and the script code for the file.

A file system specification record is a standard format for identifying a file or directory. The file system specification record for files and directories is available in System 7 and later versions of system software and is defined by the FSSpec data type.

TYPE FSSpec = {file system specification}
   RECORD   
      vRefNum: Integer;    {volume reference number}
      parID:   LongInt;    {directory ID of parent directory}
      name:    Str63;      {filename or directory name}
   END;
Certain File Manager routines--those that open a file's data fork--also take a file system specification record as a parameter. You can use the same FSSpec record in Resource Manager routines that create or open the file's resource fork.

If the file specified by the FSSpec record doesn't already exist (that is, if the file has neither a data fork nor a resource fork), the FSpCreateResFile procedure creates a resource file--that is, a resource fork, including a resource map. In this case, the file has a zero-length data fork. The FSpCreateResFile procedure also sets the creator, type, and script code fields of the file's catalog information record to the specified values.

If the file specified by the FSSpec record already exists and includes a resource fork with a resource map, FSpCreateResFile does nothing, and the ResError function returns an appropriate result code. If the data fork of the file specified by the FSSpec record already exists but the file has a zero-length resource fork, FSpCreateResFile creates an empty resource fork and resource map for the file; it also changes the creator, type, and script code fields of the catalog information record of the file to the specified values.

Listing 1-6 shows a function that creates a new resource fork, including a resource map.

Listing 1-6 Creating an empty resource fork

FUNCTION MyCreateResourceFork (myFSSpec: FSSpec): OSErr;
BEGIN
   FSpCreateResFile(myFSSpec, gAppSignature, 'TEXT',
                    smSystemScript);
   MyCreateResourceFork := ResError;
END; 
After creating a resource fork, you can open it using the FSpOpenResFile function. The FSpOpenResFile function returns a file reference number that you can use to change or limit the Resource Manager's search order or to close a resource fork.

After opening a resource fork, you can write resources to it using the routines described in "Writing Resources" beginning on page 1-30. (You can also write to a resource fork using File Manager routines; in general, you should use the Resource Manager.) When you are finished using a resource fork that your application has specifically opened, you should close it using the CloseResFile procedure. The Resource Manager automatically closes any resource forks opened by your application that are still open when your application calls ExitToShell.

Listing 1-7 shows a routine that uses the application-defined function MyCreateResourceFork (shown in Listing 1-6) to create a new resource fork, opens the resource fork, writes resources to it, then closes the resource fork when it is finished.

Listing 1-7 Creating and opening a resource fork

FUNCTION MyCreateAndOpenResourceFork (myFSSpec: FSSpec): OSErr;
VAR
   myErr:      OSErr;
   myRefNum:   Integer;
BEGIN
                                 {create a resource file}
   myErr := MyCreateResourceFork(myFSSpec);
   IF myErr = noErr THEN         {open the resource file}
      myRefNum := FSpOpenResFile(myFSSpec, fsRdWrPerm);
   IF ResError = noErr THEN      {write to the resource file}
      myErr := MyWriteResourcesToFile(myRefNum);
   CloseResFile(myRefNum);       {close the resource file}
   MyCreateAndOpenResourceFork := myErr;
END;
Note that when you open a resource fork, the Resource Manager resets the search path so that the file whose resource fork you just opened becomes the current resource file. For example, suppose the SurfWriter application file is open, and the user opens document A, then document B. SurfWriter opens the resource forks of both documents. In this case, the search order is

  1. document B (the current resource file)
  2. document A
  3. the SurfWriter application
  4. the System file

If the user is working with document A and SurfWriter uses the UseResFile procedure to set the current resource file to document A, the new search order is

  1. document A (the current resource file)
  2. the SurfWriter application
  3. the System file

If the user opens another document, document C, and SurfWriter opens its resource fork, the new search order becomes

  1. document C (the current resource file)
  2. document B
  3. document A
  4. the SurfWriter application
  5. the System file

Specifying the Current Resource File

When you request a resource, the Resource Manager follows the search order described in "Search Path for Resources" on page 1-8. To change the starting point of the search or to restrict the search to the resource fork of a specific file, you can use CurResFile and UseResFile. To get the file reference number for the current resource file, use the CurResFile function. You can then use the UseResFile procedure to set the current resource file to the desired file, use other Resource Manager routines to retrieve any desired resources, and then use UseResFile again to restore the current resource file to its previous setting.

For example, the SurfWriter application allows users to specify or record either a special reward sound that applies only to a specific document or a general reward sound that can apply to any document. SurfWriter stores a document-specific reward sound resource in the document and the general reward sound resource in either the SurfWriter Preferences file (if the reward sound is user-defined) or in the application file. If several documents are open and SurfWriter needs to play a document-specific reward sound, SurfWriter attempts to get the sound from that document without searching the resource forks of any other documents that might be open. If the document doesn't have the specified reward sound, SurfWriter searches for the sound in the resource fork of the preferences file and, if necessary, of the application file and System file.

Listing 1-8 shows how the SurfWriter application uses CurResFile and UseResFile to get and play the appropriate reward sound for a given document. All reward sounds share the same resource ID, kProductiveWriter. The application-defined procedure MyGetAndPlayRewardSoundResource first checks whether the reward sound setting for the document specifies a sound stored in that document or a general reward sound stored in the preferences file or elsewhere. If the document has a reward sound, the procedure sets the current resource file to that document, searches just that document's resource fork for the sound, and plays the sound. If the document doesn't have a reward sound, the MyGetAndPlayRewardSoundResource procedure sets the current resource file to SurfWriter Preferences, searches the entire resource chain from that point on for the sound, and plays the sound. This scheme ensures that SurfWriter always plays the correct reward sound, even if different reward sound resources in different documents share the same resource ID.

Listing 1-8 Saving and restoring the current resource file

PROCEDURE MyGetAndPlayRewardSoundResource (refNum: Integer);
VAR
   myHndl:        Handle;
   prevResFile:   Integer;
BEGIN
   prevResFile := CurResFile; {save the current resource file}
   IF MyHasDocumentRewardSound(refNum) THEN
   BEGIN
      {first set the current resource file to a specific document}
      UseResFile(refNum);
      {get reward sound from the document using Get1Resource }
      { to limit search to current resource file and avoid }
      { searching the resource forks of any other open documents}
      myHndl := Get1Resource('snd ', kProductiveWriter);
   END
   ELSE
   BEGIN
      {set current resource file to SurfWriter Preferences}
      UseResFile(gSurfPrefsResourceFork);
      {get reward sound resource using GetResource to search }
      { entire resource chain starting with preferences file}
      myHndl := GetResource('snd ', kProductiveWriter);
   END;
   IF myHndl <> NIL THEN
   BEGIN
      MyPlayThisSound(myHndl);
      ReleaseResource(myHndl);
   END;
   UseResFile(prevResFile);{restore the current resource }
                           { file to its previous setting}
END;
The MyGetAndPlayRewardSoundResource procedure saves the reference number of the current resource file and then calls the application-defined routine MyHasDocumentRewardSound to check whether the document has a reward sound associated with it. If so, MyGetAndPlayRewardSoundResource sets the current resource file to the value specified by the refNum parameter. The procedure then uses the Get1Resource function to get, from the current resource file, a handle to the resource of type 'snd ' with the ID specified by kProductiveWriter.

If the document doesn't have a specified reward sound, MyGetAndPlayRewardSoundResource uses UseResFile to set the current resource file to the SurfWriter Preferences file's resource fork and GetResource to search the entire resource chain from that point. If GetResource locates a resource with the specified resource ID in the SurfWriter Preferences file, it returns a handle to that resource; if not, it continues to search until it finds the specified resource or reaches the end of the resource chain. This ensures that the procedure won't get a user-defined resource with the same resource ID in some other SurfWriter document that is currently open instead of the general reward sound saved in SurfWriter Preferences or in SurfWriter itself.

If the call to Get1Resource or GetResource is successful (that is, if it does not return a handle whose value is NIL), MyGetAndPlayRewardSoundResource plays the appropriate reward sound, then uses ReleaseResource to release the memory occupied by the sound resource. Finally, the procedure uses UseResFile to restore the current resource file to its previous setting.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
6 JUL 1996