Important: The information in this document is obsolete and should not be used for new development.
Writing Resources
After opening a resource fork (as described in "Creating and Opening a Resource Fork" beginning on page 1-19), you can write resources to it. You can write resources only to the current resource file. To ensure that the current resource file is set to the appropriate resource fork, you can useCurResFileto save the file reference number of the
current resource file, thenUseResFileto set the current resource file to the desired resource fork.To specify data for a new resource, you usually use the
AddResourceprocedure, which creates a new entry for the resource in the resource map in memory and sets the entry's location to refer to the resource's data. Note thatAddResourcechanges only the resource map in memory; it doesn't change anything on disk. Use theUpdateResFileorWriteResourceprocedure to write the resource to disk. TheAddResourceprocedure always adds the resource to the resource map in memory that corresponds to the current resource file. For this reason, you usually need to set the current resource file to the desired file before callingAddResource.If you change a resource that is referenced through the resource map in memory, you use the
ChangedResourceprocedure to set theresChangedattribute of that resource's entry. You should then immediately call theUpdateResFileorWriteResourceprocedure to write the changed resource data to disk. Note that although theUpdateResFileprocedure writes only those resources that have been added or changed to disk, it also writes the entire resource map to disk (overwriting its previous contents). TheWriteResourceprocedure writes only the resource data of a single resource to disk; it does not update the resource's entry in the resource map on disk.The
ChangedResourceprocedure reserves enough disk space to contain the changed resource. It does this every time it's called, but the actual writing of the resource does not take place until a call toWriteResourceorUpdateResFile. Thus, if you callChangedResourceseveral times on a large resource before the resource is actually written, you may unexpectedly run out of disk space, because many times the amount of space actually needed is reserved. When the resource is actually written, the file's end-of-file (EOF) is set correctly, and the next call toChangedResourcewill work as expected.
To ensure that the Resource Manager does not purge a purgeable resource while your application is in the process of changing it, use the Memory Manager procedures
- IMPORTANT
- If your application frequently changes the contents of resources (especially large resources), you should call
WriteResourceorUpdateResFileimmediately after callingChangedResource.
HGetState,HNoPurge, andHSetState. First callHGetStateandHNoPurge, then change the resource as necessary. To make a change to a resource permanent, use theChangedResourceandWriteResource(orUpdateResFile) procedures; then callHSetStatewhen you're finished. (See Listing 1-2 on page 1-16 for an example of this technique.) However, most applications do not make resources purgeable and therefore don't need to take this precaution.Here's an example of a situation in which an application might need to write a resource. As previously described, the SurfWriter application always saves the last position of a document window when the user saves the document, storing this information in a resource that it has defined for this purpose. SurfWriter defines a resource with resource type
rWinStateand resource IDkLastWinStateIDto store the window state (its position and state, that is, either the user or the standard state). SurfWriter's window state resource has this format, defined by a record of typeMyWindowState:
TYPE MyWindowState = RECORD userStateRect: Rect; {user state rectangle} zoomState: Boolean; {window state: TRUE = standard; } { FALSE = user} END; MyWindowStatePtr = ^MyWindowState; MyWindowStateHnd = ^MyWindowStatePtr;Listing 1-11 shows SurfWriter's application-defined routine for saving the last position of a window in a window state resource in a document's resource fork.Listing 1-11 Saving a resource to a resource fork
PROCEDURE MySaveWindowPosition (myWindow: WindowPtr; myResFileRefNum: Integer); VAR lastWindowState: MyWindowState; myStateHandle: MyWindowStateHnd; curResRefNum: Integer; BEGIN {set user state provisionally and determine whether window is zoomed} lastWindowState.userStateRect := WindowPeek(myWindow)^.contRgn^^.rgnBBox; lastWindowState.zoomState := EqualRect(lastWindowState.userStateRect, MyGetWindowStdState(myWindow)); {if window is in standard state, then set the window's user state from } { the userStateRect field in the state data record} IF lastWindowState.zoomState THEN {window was in standard state} lastWindowState.userStateRect := MyGetWindowUserState(myWindow); curResRefNum := CurResFile; {save the refNum of current resource file} UseResFile(myResFileRefNum); {set the current resource file} myStateHandle := MyWindowStateHnd(Get1Resource(rWinState, kLastWinStateID)); IF myStateHandle <> NIL THEN {a state data resource already exists} BEGIN {update it} myStateHandle^^ := lastWindowState; ChangedResource(Handle(myStateHandle)); IF ResError <> noErr THEN DoError; END ELSE {no state data has yet been saved} BEGIN {add state data resource} myStateHandle := MyWindowStateHnd(NewHandle(SizeOf(MyWindowState))); IF myStateHandle <> NIL THEN BEGIN myStateHandle^^ := lastWindowState; AddResource(Handle(myStateHandle), rWinState, kLastWinStateID, 'last window state'); END; END; IF myStateHandle <> NIL THEN BEGIN UpdateResFile(myResFileRefNum); ReleaseResource(Handle(myStateHandle)); END; UseResFile(curResRefNum); END;TheMySaveWindowPositionprocedure first sets theuserStateRectfield of the window state record to the bounds of the current content region of the window. It also sets thezoomStatefield of the record to a Boolean value that indicates whether the window is currently in the user state or standard state. If the window is in the standard state, the procedure sets theuserStateRectfield of the window state record to the user state of the window. (SurfWriter always saves the user state and the last state of the window. When it opens a document, it sets the user state to its previous state, verifies that this position is still valid, then calculates the window's standard state.)The
MySaveWindowPositionprocedure then saves the file reference number of the current resource file and sets the current resource file to the document displayed in
the current window. The procedure then uses theGet1Resourcefunction to determine whether the resource file of the document already contains a window state resource. If so, the procedure changes the resource data, then callsChangedResourceto set theresChangedattribute of the resource's entry of the resource map in memory. If the resource doesn't yet exist, the procedure simply adds the new resource using theAddResourceprocedure.Note that when a Resource Manager routine returns a handle to a resource, it returns the resource using the
Handledata type. You usually define a data type (such asMyWindowState) to access the resource's data. If you also define a handle to your defined data type (such asMyWindowStateHnd), you need to coerce the returned handle to the appropriate type, as shown in this line from Listing 1-11:
myStateHandle := MyWindowStateHnd(Get1Resource(rWinState, kLastWinStateID));If you use this method, you also need to coerce your defined handle back to a handle of typeHandlewhen you use other Resource Manager routines, as shown in this line from Listing 1-11:
AddResource(Handle(myStateHandle), rWinState, kLastWinStateID, 'last window state');AfterMySaveWindowPositionchanges or adds the resource (affecting only the resource map and resource data in memory), theMySaveWindowPositionprocedure makes the change permanent by callingUpdateResFileand specifying the file reference number of the resource fork to update on disk. TheUpdateResFileprocedure writes the entire resource map in memory to disk and updates the resource data of any resource whoseresChangedattribute is set in the resource map in memory. (If you want to update only the resource that was just changed or added, you can useWriteResourceinstead ofUpdateResFile.)
When done with the resource,
- Note
- Listing 1-11 assumes the window state resource is not purgeable. If it were,
MySaveWindowPositionwould need to callHGetStateandHNoPurgebefore changing the resource.
MySaveWindowPositionusesReleaseResource, which releases the memory allocated to the resource's data (and at the same time sets the master pointer of the resource's handle in the resource map in memory toNIL). Then MySaveWindowPosition restores the current resource file to its previous setting.
 
  
  
 