Macintosh Development |
[Home]
[About Us]
[People]
[Information Systems]
[Kerberos for Macintosh]
[Applications]
[Miscellaneous Documentation]
ShlibResourcesLib API |
ShlibResourcesLib API
by convention, all macros end with _.
Initialization and termination
OSErr Shlib_InitializeResources (
ShlibContext* ioContext,
CFragInitBlock* inInitBlock);
OSErr Shlib_InitializeResources (
ShlibContext* ioContext,
CFBundleRef inBundleID);
Shlib_InitializeResources_(inInitBlock)
The Shlib_InitializeResources()
function and the
Shlib_InitializeResources_()
macro initialize
ShlibResourcesLib's global structures.
You should always call Shlib_InitializeResources_()
from shared library's initialization routine. For a CFM shared library
initializer, you should pass in the CFragInitBlock*
that
the initializer received from CFM loader. It is safe to call
Shlib_InitializeResources_()
before calling
__initialize()
, and this should be done if you have global
objects whose construction requires access to resources. Normally,
however, you should call Shlib_InitializeResources_()
immediately after calling __initialize()
. For a Mach-o
framework initializer, you should pass your library's bundle identifier
into inBundleID
.
OSErr Shlib_TerminateResources (
ShlibContext* ioContext);
Shlib_TerminateResources_()
The Shlib_TerminateResources()
function and the
Shlib_TerminateResources_()
macro terminate
ShlibResourcesLib library.
You should always call Shlib_TerminateResources_()
from shared library's CFM termination routine. It is safe to call
Shlib_TerminateResources_()
after
__terminate()
, but this should be done only if you have
global objects whose destruction requires access to the resource fork
(which is not such a good idea in general). Otherwise, call
Shlib_TerminateResources_()
immediately before calling
__terminate()
.
Resource access API
OSErr Shlib_ResFileBegin ( ShlibContext* ioContext); Shlib_ResFileBegin_() OSErr Shlib_ResFileEnd ( ShlibContext* ioContext); Shlib_ResFileEnd_()
The Shlib_ResFileBegin()
function and the
Shlib_ResFileBegin_()
macro save the current
resource fork, open the shared library resource fork,
and change the current resource fork to the shared
library resource fork.
The Shlib_ResFileEnd()
function and the
Shlib_ResFileEnd_()
macro close the shared library
resource fork and restore the current resource
fork to its state before call to Shlib_ResFileBegin()
.
All four of them return the the result of
UseResFile()
.
Note that it is possible for Shlib_ResFileBegin()
to fail (for example,
under low memory conditions). To check for this, call Shlib_ResError()
immediately
after calling Shlib_ResFileBegin()
. If Shlib_ResFileBegin()
fails, do not call
Shlib_ResFileEnd()
It is an error to call Shlib_ResFileEnd()
before
calling Shlib_ResFileBegin()
. It is an error to make two
calls to Shlib_ResFileBegin()
without a call to
Shlib_ResFileEnd()
between them. It is an error to make
two calls to Shlib_ResFileEnd()
without a call to
Shlib_ResFileBegin()
between them (however, the C++ API
allows nesting; see below).
You should always call Shlib_ResFileEnd()
before
leaving your shared library, if you called
Shlib_ResFileBegin()
; otherwise you will have changed
the current resource fork for your caller, which will therefore
probably get confused.
Your resource accesses should be bracketed with calls to these functions, for example:
Shlib_ResFileBegin_ ();
Alert (...);
Alert (...);
Shlib_ResFileEnd_ ();
Likewise, if you want to use a resource fork different from the
shared library resource fork, you should call
Shlib_ResFileBegin_()
before opening the resource fork,
and Shlib_ResFileEnd_()
after closing it. If you need to
keep the resource fork open across several calls to your shared
library, open the resource fork (between calls to
Shlib_ResFileBegin_()
and
Shlib_ResFileEnd_()
) and store its reference number in a
variable in the shared library. Then use
Shlib_ResFileBegin_()
, UseResFile()
and
Shlib_ResFileEnd_()
to use the resource fork.
C++ additions to the low-level API
In addition to the low-level API described above, you can use the
StShlibResFile
class to set the current resource fork to
the shared library resource fork and restore it back to its original
state at the end of the current scope. For example:
{
StShlibResFile resFile;
// From here till the end of the block,
// current resource fork is the shared library
// resource fork
}
// Here, resource fork is restored to what it was before resFile declaration
You can use the toolbox to change to other resource files within
the scope of resFile
. At the end of the scope, the
current resource fork is always reset to what it was before the
declaration of the resFile
.
Uses of StShlibResFile
can be nested (unlike calls to
Shlib_ResFileBegin()
and
Shlib_ResFileEnd()
). However, only first use of
StShlibResFile
will change the current resource fork.
Therefore, if you change the current resource fork in your code after
the first use of StShlibResFile
,
StShlibResFile
will not change it back to the shared
library resource fork for you:
{
StShlibResFile outerResFile;
// From here till the end of the block,
// current resource fork is the shared library
// resource fork
UseResFile (fooResFile)
// Here current resource fork is fooResFile
{
StShlibResFile innerResFile;
// From here till the end of the block,
// current resource fork is fooResFile
// _not_ shared library resource file
}
// Here, resource fork is still fooResFile
}
// Here, resource fork is restored to what it was before resFile declaration
The reason for this behavior is that is makes extra uses of
StShlibResFile
cheap, and optimizes for the common case
where a function in a shared library needs access to resources, but
it can be reached via several call paths, some of which would already
have used the shared library resource fork.
Resource file tracking API
With shared libraries, users should be able to move the shared library file without affecting its functionality for already running applications. For shared libraries that use resources, this creates a problem because a FSSpec for that file cannot be cached, because moving the file invalidates the FSSpec.
The solution is to open such resource files for reading as data (as opposed as resource files), which doesn't load them into the resource chain. Then the open file reference can be used to recover the FSSpec even if the file moves. However, this means that a shared library file will be open multiple times from every process if there are multiple shared libraries residing in it, each using the resource fork.
To avoid open file starvation (limit in MacOS 8.x and older is 324 open files), the resource file tracking API provides a way of tracking resource files while they are moved on disk, without opening each file more than once.
OSErr Shlib_MemorizeFSSpec ( const FSSpec* inFileSpec, ShlibFileRef* outFileRef);
ShlibMemorizeFSSpec takes an FSSpec and returns a ShlibFileRef. The ShlibFileRef can later be used to recover the FSSpec for that file, whether the file has been moved or not
OSErr Shlib_RecoverFSSpec ( ShlibFileRef inFileRef, FSSpec* outFileSpec);
ShlibRecoverFSSpec takes a ShlibFileRec and returns the current FSSpec of the file.
OSErr Shlib_ForgetFSSpec ( ShlibFileRef inFileRef);
Shlib_ForgerFSSpec invalidates a ShlibFileRef and frees memory and other resources (such as open file references) associated with it.
You should use this API when you have a resource file you need to access repeatedly, regardless of its location, but you cannot keep it loaded in the rsource chain all the time (for example, a shared library resource file). Use Shlib_MemorizeFSSpec when you first open the file, and Shlib_REcoverFSSpec on subsequent accesses. Use Shlib_ForgetFSSpec when you no longer need to track the file.
Questions or comments? Send mail to macdev@mit.edu
Last updated on $Date: 2003/11/19 20:49:24 $
Last modified by $Author: smcguire $