Important: The information in this document is obsolete and should not be used for new development.
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 theCurResFile
function early in your initialization procedure. (TheCurResFile
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 sameFSSpec
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), theFSpCreateResFile
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. TheFSpCreateResFile
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 theResError
function returns an appropriate result code. If the data fork of the file specified by theFSSpec
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 theFSpOpenResFile
function. TheFSpOpenResFile
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 callsExitToShell
.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
If the user is working with document A and SurfWriter uses the
- document B (the current resource file)
- document A
- the SurfWriter application
- the System file
UseResFile
procedure to set the current resource file to document A, the new search order is
If the user opens another document, document C, and SurfWriter opens its resource fork, the new search order becomes
- document A (the current resource file)
- the SurfWriter application
- the System file
- document C (the current resource file)
- document B
- document A
- the SurfWriter application
- 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 useCurResFile
andUseResFile
. To get the file reference number for the current resource file, use theCurResFile
function. You can then use theUseResFile
procedure to set the current resource file to the desired file, use other Resource Manager routines to retrieve any desired resources, and then useUseResFile
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
andUseResFile
to get and play the appropriate reward sound for a given document. All reward sounds share the same resource ID,kProductiveWriter
. The application-defined procedureMyGetAndPlayRewardSoundResource
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, theMyGetAndPlayRewardSoundResource
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;TheMyGetAndPlayRewardSoundResource
procedure saves the reference number of the current resource file and then calls the application-defined routineMyHasDocumentRewardSound
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 therefNum
parameter. The procedure then uses theGet1Resource
function to get, from the current resource file, a handle to the resource of type'snd '
with the ID specified bykProductiveWriter
.If the document doesn't have a specified reward sound,
MyGetAndPlayRewardSoundResource
usesUseResFile
to set the current resource file to the SurfWriter Preferences file's resource fork andGetResource
to search the entire resource chain from that point. IfGetResource
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
orGetResource
is successful (that is, if it does not return a handle whose value isNIL
),MyGetAndPlayRewardSoundResource
plays the appropriate reward sound, then usesReleaseResource
to release the memory occupied by the sound resource. Finally, the procedure usesUseResFile
to restore the current resource file to its previous setting.