MIT Information Systems

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 $