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 useCurResFile
to save the file reference number of the
current resource file, thenUseResFile
to set the current resource file to the desired resource fork.To specify data for a new resource, you usually use the
AddResource
procedure, 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 thatAddResource
changes only the resource map in memory; it doesn't change anything on disk. Use theUpdateResFile
orWriteResource
procedure to write the resource to disk. TheAddResource
procedure 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
ChangedResource
procedure to set theresChanged
attribute of that resource's entry. You should then immediately call theUpdateResFile
orWriteResource
procedure to write the changed resource data to disk. Note that although theUpdateResFile
procedure 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). TheWriteResource
procedure 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
ChangedResource
procedure 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 toWriteResource
orUpdateResFile
. Thus, if you callChangedResource
several 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 toChangedResource
will 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
WriteResource
orUpdateResFile
immediately after callingChangedResource
.HGetState
,HNoPurge
, andHSetState
. First callHGetState
andHNoPurge
, then change the resource as necessary. To make a change to a resource permanent, use theChangedResource
andWriteResource
(orUpdateResFile
) procedures; then callHSetState
when 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
rWinState
and resource IDkLastWinStateID
to 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;TheMySaveWindowPosition
procedure first sets theuserStateRect
field of the window state record to the bounds of the current content region of the window. It also sets thezoomState
field 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 theuserStateRect
field 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
MySaveWindowPosition
procedure 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 theGet1Resource
function to determine whether the resource file of the document already contains a window state resource. If so, the procedure changes the resource data, then callsChangedResource
to set theresChanged
attribute 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 theAddResource
procedure.Note that when a Resource Manager routine returns a handle to a resource, it returns the resource using the
Handle
data 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 typeHandle
when you use other Resource Manager routines, as shown in this line from Listing 1-11:
AddResource(Handle(myStateHandle), rWinState, kLastWinStateID, 'last window state');AfterMySaveWindowPosition
changes or adds the resource (affecting only the resource map and resource data in memory), theMySaveWindowPosition
procedure makes the change permanent by callingUpdateResFile
and specifying the file reference number of the resource fork to update on disk. TheUpdateResFile
procedure writes the entire resource map in memory to disk and updates the resource data of any resource whoseresChanged
attribute is set in the resource map in memory. (If you want to update only the resource that was just changed or added, you can useWriteResource
instead ofUpdateResFile
.)
When done with the resource,
- Note
- Listing 1-11 assumes the window state resource is not purgeable. If it were,
MySaveWindowPosition
would need to callHGetState
andHNoPurge
before changing the resource.MySaveWindowPosition
usesReleaseResource
, 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.