Important: The information in this document is obsolete and should not be used for new development.
Using Shadow Libraries
In some cases you might want to prepare import libraries on an "on-call" basis the same way you would with plug-ins. For example, if you only occasionally use routines frommooLib
in your application, you may not want to take up excess memory whenmooLib
is not required. In such cases, you should create a shadow library. A shadow library is essentially a small library whose only purpose is to prepare an import library when a symbol from that library is required.For example, suppose you have a simple header file with this function:
StatusType FunctionOne (ParamOneAType param1A, ParamOneBType param1B);
Listing 3-5 shows how to access these functions through a simple shadow library.
Listing 3-5 Sample code found in a shadow library
/* Function pointers used internally by the shadows. */ typedef StatusType (* FunctionOnePtr) (PramOneAType param1A, ParamOneBType param1B); /* The initial version of the function pointers. */ static StatusType PrepareAndCallF1 (ParamOneAType param1A, ParamOneBType param1B); static FunctionOnePtr gFunctionOne = PrepareAndCallF1; /* The initial version of the function pointer, which does setup first, and then */ /* calls through to the actual function. */ static StatusType PrepareAndCallF1 (ParamOneAType param1A, ParamOneBType param1B) { OSErr err = Setup (); if (err == noErr) err = (*gFunctionOne) (param1A, param1B); return err; } /* The shadow implememtation of FunctionOne, which calls through the */ /* function pointer, which itself could point to the setup version */ /* (first time) or to the actual routine (second time or later). */ StatusType FunctionOne (ParamOneAType param1A, ParamOneBType param1B) { return (*gFunctionOne) (param1A, param1B); } static OSErr Setup (void) { CFragConnectionID connID; OSErr err = GetSharedLibrary ("\pRealImplementation", kCompiledCFragArch, kReferenceCFrag, &connID, NULL, NULL); if (err == noErr) { FunctionOnePtr p1; err = FindSymbol (connID, "\pFunctionOne", (Ptr *) & p1, NULL); if (err == noErr) gFunctionOne = p1; } return err; }This example just uses local pointers to go to the "right" function. The first time through, these pointers take you to routines that call the Code Fragment Manager to prepare the real library. Subsequent times they take you to the real routines. This implementation requires no changes to clients (for example, you can change the import library without recompiling or relinking the clients).Note that this example works only if all functions in the library return some sort of success/failure indication. This could be through an explicit status value, a null/nonnull pointer, and so on. Also, this example is not preemptive thread safe, and it does not have sophisticated error checking. If you are writing code to prepare a shadow library, you should anticipate errors such as the following:
Also, if your shadow library may be released at some point, you should include code in the library's termination routine to release any libraries it has prepared and to perform any other necessary cleanup.
- The initialization function in the library fails.
- The Code Fragment Manager cannot find a compatible library.
- The Code Fragment Manager cannot find the required symbols in the library.