1 | /*
|
---|
2 | File: CFMLateImport.h
|
---|
3 |
|
---|
4 | Contains: Interface to CFM late import library.
|
---|
5 |
|
---|
6 | Written by: Quinn
|
---|
7 |
|
---|
8 | Copyright: Copyright © 1999 by Apple Computer, Inc., all rights reserved.
|
---|
9 |
|
---|
10 | You may incorporate this Apple sample source code into your program(s) without
|
---|
11 | restriction. This Apple sample source code has been provided "AS IS" and the
|
---|
12 | responsibility for its operation is yours. You are not permitted to redistribute
|
---|
13 | this Apple sample source code as "Apple sample source code" after having made
|
---|
14 | changes. If you're going to re-distribute the source, we require that you make
|
---|
15 | it clear in the source that the code was descended from Apple sample source
|
---|
16 | code, but that you've made changes.
|
---|
17 |
|
---|
18 | Change History (most recent first):
|
---|
19 |
|
---|
20 | <6> 21/9/01 Quinn Changes for CWPro7 Mach-O build.
|
---|
21 | <5> 19/9/01 Quinn Change comments to reflect the fact that an unpacked data
|
---|
22 | section is no longer required.
|
---|
23 | <4> 19/9/01 Quinn Simplified API and implementation after a suggestion by Eric
|
---|
24 | Grant. You no longer have to CFM export a dummy function; you
|
---|
25 | can just pass in the address of your fragment's init routine.
|
---|
26 | <3> 16/11/00 Quinn Allow symbol finding via a callback and use that to implement
|
---|
27 | CFBundle support.
|
---|
28 | <2> 18/10/99 Quinn Renamed CFMLateImport to CFMLateImportLibrary to allow for
|
---|
29 | possible future API expansion.
|
---|
30 | <1> 15/6/99 Quinn First checked in.
|
---|
31 | */
|
---|
32 |
|
---|
33 | #pragma once
|
---|
34 |
|
---|
35 | /////////////////////////////////////////////////////////////////
|
---|
36 |
|
---|
37 | // MoreIsBetter Setup
|
---|
38 |
|
---|
39 | //#include "MoreSetup.h"
|
---|
40 |
|
---|
41 | // Mac OS Interfaces
|
---|
42 |
|
---|
43 | #if ! MORE_FRAMEWORK_INCLUDES
|
---|
44 | #include <MacTypes.h>
|
---|
45 | #include <CodeFragments.h>
|
---|
46 | #include <Devices.h>
|
---|
47 | #include <CFBundle.h>
|
---|
48 | #endif
|
---|
49 |
|
---|
50 | /////////////////////////////////////////////////////////////////
|
---|
51 |
|
---|
52 | #ifdef __cplusplus
|
---|
53 | extern "C" {
|
---|
54 | #endif
|
---|
55 |
|
---|
56 | /* FAQ
|
---|
57 | ---
|
---|
58 |
|
---|
59 | Q: What does this library do?
|
---|
60 | A: It allows you to resolve a weak linked library at runtime,
|
---|
61 | by supply a CFM connection to the library that should substitute
|
---|
62 | for the weak linked one.
|
---|
63 |
|
---|
64 | Q: Does the substituted library have to have the same name as the
|
---|
65 | weak linked library.
|
---|
66 | A: No.
|
---|
67 |
|
---|
68 | Q: What's this useful for?
|
---|
69 | A: The most obvious example of where this is useful is when
|
---|
70 | you rely on shared libraries that the user might delete
|
---|
71 | or move. To can find the shared library (possibly even
|
---|
72 | using CatSearch), call GetDiskFragment to open a connection
|
---|
73 | to it, late import it using this library, and then the
|
---|
74 | rest of your code can continue to use the shared library
|
---|
75 | as if nothing had happened. No more defining thousands
|
---|
76 | of stub routines which call through routine pointers.
|
---|
77 |
|
---|
78 | There are, however, numerous less obvious uses. You can
|
---|
79 | use this code to make a 'self repairing' application. If
|
---|
80 | the user removes your shared library from the Extensions
|
---|
81 | folder, the startup code for your application can offer
|
---|
82 | tor re-install it. If the user agrees, you can then
|
---|
83 | re-install your shared library, late import it, and then
|
---|
84 | continue running your application if nothing happened.
|
---|
85 |
|
---|
86 | You can even use this code to free yourself from the
|
---|
87 | Extensions folder entirely. Say you have a suite of
|
---|
88 | applications that currently installs a dozen shared
|
---|
89 | libraries in the Extensions folder. You can move those
|
---|
90 | libraries to another folder entirely and each application's
|
---|
91 | startup code can track down the library (using an alias
|
---|
92 | in the Preferences file) and late import it.
|
---|
93 |
|
---|
94 | An even cooler use is to provide easy abstraction layers.
|
---|
95 | Say you have a network code for both the MacTCP
|
---|
96 | API and the Open Transport API. Typically, you would be
|
---|
97 | force to do this by having an abstraction layer where every
|
---|
98 | routine contains a switch between MacTCP and OT. Your
|
---|
99 | OpenSocket routine might look like:
|
---|
100 |
|
---|
101 | static int OpenSocket(void)
|
---|
102 | {
|
---|
103 | if (gOTAvailable) {
|
---|
104 | return OpenSocketOT();
|
---|
105 | } else {
|
---|
106 | return OpenSocketMacTCP();
|
---|
107 | }
|
---|
108 | }
|
---|
109 |
|
---|
110 | With this code, you can avoid that entirely. Simply
|
---|
111 | weak link to a shared library that you know is never
|
---|
112 | going to be implemented ("crea;MySocketsDummy") and then,
|
---|
113 | at runtime, decide whether the system has MacTCP or OT
|
---|
114 | and late import the relevant real implementation
|
---|
115 | ("crea;MySocketsMacTCP" or "crea;MySocketsOT").
|
---|
116 | One benefit of this approach is that only the MacTCP or
|
---|
117 | the OT code is resident in memory on any given system.
|
---|
118 | */
|
---|
119 |
|
---|
120 | typedef pascal OSStatus (*CFMLateImportLookupProc)(ConstStr255Param symName, CFragSymbolClass symClass,
|
---|
121 | void **symAddr, void *refCon);
|
---|
122 | // CFMLateImportLookupProc defines a callback for CFMLateImportCore.
|
---|
123 | // The routine is expected to look up the address of the symbol named
|
---|
124 | // symName and return it in *symAddr. The symbol should be of class
|
---|
125 | // symClass, although the callback decides whether a class mismatch is
|
---|
126 | // an error. refCon is an application defined value that was originally
|
---|
127 | // passed in to CFMLateImportCore.
|
---|
128 | //
|
---|
129 | // If this routine returns an error, a symbol address of 0 is assumed.
|
---|
130 | // If the symbol is marked as a weak import, the CFMLateImportCore will
|
---|
131 | // continue, otherwise the CFMLateImportCore routine will fail with the
|
---|
132 | // error.
|
---|
133 |
|
---|
134 | extern pascal OSStatus CFMLateImportCore(const CFragSystem7DiskFlatLocator *fragToFixLocator,
|
---|
135 | CFragConnectionID fragToFixConnID,
|
---|
136 | CFragInitFunction fragToFixInitRoutine,
|
---|
137 | ConstStr255Param weakLinkedLibraryName,
|
---|
138 | CFMLateImportLookupProc lookup,
|
---|
139 | void *refCon);
|
---|
140 | // This routine will link you, at runtime, to some library
|
---|
141 | // that you were weak linked to and wasn't present when your
|
---|
142 | // fragment was prepared. As well as the obvious functionality
|
---|
143 | // of being able to resolve weak links after prepare time,
|
---|
144 | // this functionality can be put to a number of less obvious uses,
|
---|
145 | // some of which are discussed at the top of this header file.
|
---|
146 | //
|
---|
147 | // To call this routine, you need a number of pieces of information:
|
---|
148 | //
|
---|
149 | // 1. fragToFixLocator, fragToFixConnID: The location of your own
|
---|
150 | // code fragment on disk and the CFM connection ID to your own
|
---|
151 | // code fragment. Typically you get this information from your
|
---|
152 | // fragment's CFM init routine. You must ensure that
|
---|
153 | // fragToFixLocator->fileSpec points to an FSSpec of the
|
---|
154 | // file which holds your code fragment.
|
---|
155 | //
|
---|
156 | // IMPORTANT:
|
---|
157 | // The fact that you pass in a CFragSystem7DiskFlatLocator as the
|
---|
158 | // fragToFixLocator implies that the fragment to be fixed up must
|
---|
159 | // be in the data fork of a file. The code could be modified
|
---|
160 | // to remove this requirement, but on disk code fragments are the most
|
---|
161 | // common case.
|
---|
162 | //
|
---|
163 | // IMPORTANT:
|
---|
164 | // The fragment to fix may have a packed data section. Packing the
|
---|
165 | // data section will reduce the size of your fragment on disk, but it
|
---|
166 | // will significantly increase the memory needed by this routine
|
---|
167 | // (it increases memory usage by the sum of the sizes of the packed
|
---|
168 | // and unpacked data section). See below for instructions on how to
|
---|
169 | // create an unpacked data section.
|
---|
170 | //
|
---|
171 | // 2. fragToFixInitRoutine: A pointer to your own code fragment's
|
---|
172 | // fragment initialiser routine. You necessarily have one of these
|
---|
173 | // because you need it to get values for the fragToFixLocator and
|
---|
174 | // fragToFixConnID parameters. Just pass its address in as a parameter
|
---|
175 | // as well.
|
---|
176 | //
|
---|
177 | // 3. weakLinkedLibraryName: The name of the weak linked library which
|
---|
178 | // failed to link. You must have weak linked to this library.
|
---|
179 | // It is oxymoric for you to pass a strong linked library here,
|
---|
180 | // because your code would not have prepared if a strong linked
|
---|
181 | // library failed to prepare, and so you couldn't supply a valid
|
---|
182 | /// fragToFix.
|
---|
183 | //
|
---|
184 | // 4. lookup, refCon: A pointer to a callback function that the
|
---|
185 | // routine calls to look up the address of a symbol, and a refCon
|
---|
186 | // for that callback routine.
|
---|
187 | //
|
---|
188 | // Note:
|
---|
189 | // The fragToFixLocator and fragToFixInitRoutine parameters
|
---|
190 | // are artifacts of the way in which this functionality is implemented.
|
---|
191 | // In an ideal world, where CFM exported decent introspection APIs
|
---|
192 | // to third party developers, these parameters would not be necessary.
|
---|
193 | // If you're using this code inside Apple, you probably should investigate
|
---|
194 | // using the CFM private APIs for getting at the information these
|
---|
195 | // parameters are needed for. See the comments inside the implementation
|
---|
196 | // for more details.
|
---|
197 | //
|
---|
198 | // Note:
|
---|
199 | // The extra memory taken when you use a packed data section is also an
|
---|
200 | // artifact of my workaround for the lack of CFM introspection APIs. In
|
---|
201 | // my opinion it's better to use an unpacked data section and consume more
|
---|
202 | // space on disk while saving memory. In CodeWarrior you can switch to an
|
---|
203 | // unpacked data section by checking the "Expand Uninitialized Data"
|
---|
204 | // checkbox in the "PPC PEF" settings panel. In MPW, specified the
|
---|
205 | // "-packdata off" option to PPCLink.
|
---|
206 | //
|
---|
207 | // When the routine returns, any symbols that you imported from the
|
---|
208 | // library named weakLinkedLibraryName will be resolved to the address
|
---|
209 | // of the symbol provided by the "lookup" callback routine.
|
---|
210 | //
|
---|
211 | // It is possible for an unresolved import to remain unresolved after
|
---|
212 | // this routine returns. If the symbol import is marked as weak (as
|
---|
213 | // opposed to the library, which *must* be marked as weak) and the symbol
|
---|
214 | // is not found by the "lookup" callback, the routine will simple skip
|
---|
215 | // that symbol. If the symbol isn't marked as weak, the routine will fail
|
---|
216 | // in that case.
|
---|
217 | //
|
---|
218 | // Most of the possible error results are co-opted CFM errors. These
|
---|
219 | // include:
|
---|
220 | //
|
---|
221 | // cfragFragmentFormatErr -- The fragment to fix is is an unknown format.
|
---|
222 | // cfragNoSectionErr -- Could not find the loader section in the fragment to fix.
|
---|
223 | // cfragNoLibraryErr -- The fragment to fix is not weak linked to weakLinkedLibraryName.
|
---|
224 | // cfragFragmentUsageErr -- The fragment to fix doesn't have a data section.
|
---|
225 | // -- The fragment to fix is strong linked to weakLinkedLibraryName.
|
---|
226 | // -- The fragment doesn't have an init routine.
|
---|
227 | // cfragFragmentCorruptErr -- Encountered an undefined relocation opcode.
|
---|
228 | // unimpErr -- Encountered an unimplement relocation opcode. The
|
---|
229 | // relocation engine only implements a subset of the CFM
|
---|
230 | // relocation opcodes, the subset most commonly used by
|
---|
231 | // MPW and CodeWarrior PEF containers. If you encounter
|
---|
232 | // this error, you'll probably have to add the weird
|
---|
233 | // relocation opcode to the engine, which shouldn't be
|
---|
234 | // be too hard.
|
---|
235 | // memFullErr -- It's likely that this error is triggered by the memory
|
---|
236 | // needed to unpack your data section. Either make your
|
---|
237 | // data section smaller, or unpack it (see above).
|
---|
238 | // errors returned by FindSymbol
|
---|
239 | // errors returned by Memory Manager
|
---|
240 | //
|
---|
241 | // The routine needs enough memory to hold the loader section of the fragment
|
---|
242 | // to fix in memory. It allocates that memory using NewPtr and dispsoses of
|
---|
243 | // it before it returns. You may want to change the memory allocator, which
|
---|
244 | // is very simple.
|
---|
245 |
|
---|
246 | extern pascal OSStatus CFMLateImportLibrary(const CFragSystem7DiskFlatLocator *fragToFixLocator,
|
---|
247 | CFragConnectionID fragToFixConnID,
|
---|
248 | CFragInitFunction fragToFixInitRoutine,
|
---|
249 | ConstStr255Param weakLinkedLibraryName,
|
---|
250 | CFragConnectionID connIDToImport);
|
---|
251 | // A wrapper around CFMLateImportCore that looks up symbols by calling
|
---|
252 | // FindSymbol on a connection to a CFM library (connIDToImport).
|
---|
253 | // You can get this connection ID through any standard CFM API, for example
|
---|
254 | // GetSharedLibrary, GetDiskFragment, or GetMemFragment.
|
---|
255 | //
|
---|
256 | // IMPORTANT:
|
---|
257 | // The fragment name for connIDToImport *does not* have to match
|
---|
258 | // weakLinkedLibraryName. This is part of the power of this library.
|
---|
259 |
|
---|
260 | extern pascal OSStatus CFMLateImportBundle(const CFragSystem7DiskFlatLocator *fragToFixLocator,
|
---|
261 | CFragConnectionID fragToFixConnID,
|
---|
262 | CFragInitFunction fragToFixInitRoutine,
|
---|
263 | ConstStr255Param weakLinkedLibraryName,
|
---|
264 | CFBundleRef bundleToImport);
|
---|
265 | // A wrapper around CFMLateImportCore that looks up symbols by calling
|
---|
266 | // CFBundleGetFunctionPointerForName on a reference to a Core Foundation
|
---|
267 | // bundle (bundleToImport). You can get this reference through any
|
---|
268 | // Core Foundation bundle API, for example CFBundleCreate.
|
---|
269 |
|
---|
270 | #ifdef __cplusplus
|
---|
271 | }
|
---|
272 | #endif
|
---|