Technote 1123Start Manager Extension Table MechanismVersion 1.0 |
CONTENTSIntroductionMonitoring System Extension Loading and Execution Controlling System Extension Loading and Execution Extension Table Manager Reference Summary of the Extension Table Manager Acknowledgments |
The Start Manager was revised in Mac OS 8.1 to add a mechanism for monitoring and controlling the loading of system extensions during system startup. This Technote describes how the Start Manager was changed, and shows how a program can monitor or take control of the system extension loading process. |
Prior to Mac OS 8.1, system extensions were loaded and executed
from three folders in order: the Extensions folder, Control Panels
folder, and the System Folder. The system extensions in each folder
were loaded and executed in the order they were found on the disk. On
an HFS volume (also known as Mac OS Standard) item names are stored
using ASCII characters. Items are stored in the catalog file in
RelString
order, i.e., in the order the names would be
in if sorted by the RelString
function. Because of this,
the File Manager's GetFInfo
routine returns files in
RelString
order.
With the introduction of Mac OS 8.1, a new bootable disk format, HFS Plus (also known as Mac OS Extended), was introduced. On HFS Plus volumes item names are stored using Unicode, rather than ASCII characters. Items are stored in the catalog file in a different order than they would be on an HFS volume. Details on the sorting order for HFS Plus volumes can be found in the HFS Plus Volume Format documentation.
Note: |
On systems using the Roman script system, files on HFS Plus
volumes are returned by GetFInfo
in a similar, but not exactly the
same, order as RelString
. However, on systems running non-Roman
script systems, GetFInfo
may return files in a radically different
order.
Note: |
To prevent problems for our users, and to ensure that system
extensions load and execute in the same order regardless of the
volume format and script system used, the system extension mechanism
was revised to be table driven. The Start Manager builds a single
table of system extensions, sorted using RelString
, from
the system extensions found in each folder. Then, each system
extension is loaded and executed, in order, from the table. The
result is that system extensions are loaded and executed in the same
order regardless of which type of volume the system is booting from
and what script system the system is running.
The Start Manager was revised to allow other programs access to the system extension loading mechanism. Programs can either monitor or control the system extension loading and execution process.
A program can install an ExtensionNotificationProc
to
monitor the system extension loading process. Each
ExtensionNotificationProc
is called before the first
system extension is loaded and executed, both before and after each
system extension is loaded and executed, and after the last system
extension is loaded and executed. When called, an extension
notification routine can perform some action such as drawing an icon,
playing a sound, displaying the system extension's name, or saving
the system extension's name in a file to help debug system extension
crashes or document system extension loading order. An
ExtensionNotificationProc
cannot change the order that
system extensions load and execute. Any number of
ExtensionNotificationProcs
can be installed.
A program can install an ExtensionTableHandlerProc
to
control the system extension loading process. The
ExtensionTableHandlerProc
is called before the first
system extension is loaded and executed, both before and after each
system extension is loaded and executed, and after the last system
extension is loaded and executed. Unlike an
ExtensionNotificationProc
, the
ExtensionTableHandlerProc
owns the extension table and
has complete control over the order that system extensions load and
execute. A program that installs an
ExtensionTableHandlerProc
can also prevent some system
extensions from loading and load system extensions from other than
the default folders. Only one ExtensionTableHandlerProc
can be installed.
If no ExtensionTableHandlerProc
is installed, the
Start Manager uses its own default extension table handler. This
default extension table handler mimics the behavior of the File
Manager under previous versions of Mac OS (i.e., if the contents of a
folder used to build the extension table changes, then the extension
table is rebuilt and execution is resumed where it would have if the
Start Manager were calling GetFInfo
).
Note: |
The extension table is a relocatable block in the system heap
containing an ExtensionTable
structure. An
ExtensionTable
consists of an
ExtensionTableHeader
followed by an array of
ExtensionElement
s. The ExtensionTableHeader
contains the version field which indicates the version of both the
ExtensionTable
and the ExtensionElement
records, an index into the ExtensionElement
s which
indicates which system extension is currently loading and executing,
the size of an ExtensionElement
, and the number of
ExtensionElement
s in the table. Each
ExtensionElement
in the ExtensionTable
contains information used to identify which system extensions will be
loaded and executed by the Start Manager.
Each installed ExtensionNotificationProc
will be
passed a copy of the ExtensionElement
for the system
extension which is currently being loaded and executed.
The ExtensionTableHandlerProc
controlling the system
extension loading process will be passed the
ExtensionTable
each time it is called. This handler can
control the loading of system extensions by modifying the
ExtensionTable
.
The Start Manager installs the APIs for installing and removing
ExtensionTableHandlerProc
and
ExtensionNotificationProc
s early in the boot process
(after MacsBug has loaded but before before MacsBug
dcmdSecondaryINIT
time).
Before system extensions are to be loaded and executed, the Start Manager creates an extension table.
Before the first system extension is loaded and executed, the
ExtensionTableHandlerProc
and each
ExtensionNotificationProc
will be called with the
extNotificationBeforeFirst
message indicating that the
system extension loading process is about to begin. The
ExtensionTableHandlerProc
is always called with the
extNotificationBeforeFirst
message before any
ExtensionNotificationProc
.
The Start Manager then loads and executes each system extension in
order from the extension table. Before each system extension is
loaded and executed, the ExtensionTableHandlerProc
and
all ExtensionNotificationProc
s are called with the
extNotificationBeforeCurrent
message. After each system
extension is loaded and executed, all
ExtensionNotificationProc
s and the
ExtensionTableHandlerProc
are called with the
extNotificationAfterCurrent
message. The
ExtensionTableHandlerProc
is always called with the
extNotificationBeforeCurrent
message before any
ExtensionNotificationProc
s, and the
ExtensionTableHandlerProc
is always called with the
extNotificationAfterCurrent
message after any
ExtensionNotificationProc
s.
After all system extensions have been loaded all
ExtensionNotificationProc
s and the
ExtensionTableHandlerProc
are called with the
extNotificationAfterLast message indicating that the system extension
loading process is complete. The
ExtensionTableHandlerProc
is always called with the
extNotificationAfterLast
message after the last
ExtensionNotificationProc
.
In all cases, the relative order in which
ExtensionNotificationProc
s are called is not
defined.
An INIT, or a program executed before system extensions are
loaded, can monitor the system extension loading process by calling
InstallExtensionNotificationProc
to install an
ExtensionNotificationProc
. Once installed, this handler
will be called:
An ExtensionNotificationProc
receives an
ExtensionElementPtr
which points to a copy of the
ExtensionElement
for the system extension currently
being loaded.
Note: |
There can be any number of ExtensionNotificationProc
s
installed.
An INIT, or a program executed before system extensions are
loaded, can take control of the system extension loading process by
calling InstallExtensionTableHandlerProc
to install a
ExtensionTableHandlerProc
.
InstallExtensionTableHandlerProc
returns the default
ExtensionTable
created by the Start Manager.
There can only be one ExtensionTableHandlerProc
installed.
While it is installed, the ExtensionTableHandlerProc
is responsible for all changes to the ExtensionTable
,
except for incrementing extElementIndex
field between
system extensions. After an ExtensionTableHandlerProc
is
installed, the system's default extension table handler no longer
manages the ExtensionTable
.
Once installed, the ExtensionTableHandlerProc
will be
called:
Unlike ExtensionNotificationProcs
, the
ExtensionTableHandlerProc
receives a handle to the
ExtensionTable
used by the Start Manager -- not a
copy.
Note: |
The extElementIndex
field in the
ExtensionTable
is always incremented to the next
ExtensionElement
immediately after the
ExtensionTableHandlerProc
is called with the
extNotificationAfterCurrent
message.
WARNING: |
This section discusses the techniques you can use to monitor or control the system extension loading and execution process.
Gestalt
)You should call Gestalt
with the gestaltExtensionTableVersion
selector to
determine the version of ExtensionTable
currently
installed before installing any handlers for the extension table
mechanism.
enum { gestaltExtensionTableVersion = FOUR_CHAR_CODE('etbl') /* ExtensionTable version */ };
The current (Mac OS 8.1) ExtensionTable
version is
1.0.0.
enum { kExtensionTableVersion = 0x00000100 /* current ExtensionTable version (1.0.0) */ };
If gestaltExtensionTableVersion
is not defined, it
indicates that there is no extension table mechanism present and that
the associated extension table routines will be undefined.
When the major version number of
kExtensionTableVersion
and the value returned by
gestaltExtensionTableVersion
are different, it indicates
that the extension table mechanism has radically changed and code
that doesn't know about the new major version must not attempt to use
the extension table mechanism.
Changes to the minor version number of
kExtensionTableVersion
indicate that the definition of
the ExtensionElement structure has been extended, but the fields
defined for previous minor versions of
kExtensionTableVersion
have not changed.
An ExtensionTable
is an
ExtensionTableHeader
followed by an array of
ExtensionElements
. This structure is built by the
extension table mechanism when it scans for system extensions to be
loaded and executed at boot time.
struct ExtensionTable { ExtensionTableHeader extTableHeader; /* the ExtensionTableHeader */ ExtensionElement extElements[1]; /* one element for each extension to load */ }; typedef struct ExtensionTable ExtensionTable; typedef ExtensionTable * ExtensionTablePtr; typedef ExtensionTablePtr * ExtensionTableHandle;
An ExtensionTableHandle
containing the current
ExtensionTable
will be passed as a parameter to the
installed ExtensionTableHandlerProc
when it is
called.
An ExtensionTable
begins with an
ExtensionTableHeader
.
struct ExtensionTableHeader { UInt32 extTableHeaderSize; UInt32 extTableVersion; UInt32 extElementIndex; UInt32 extElementSize; UInt32 extElementCount; }; typedef struct ExtensionTableHeader ExtensionTableHeader;
|
The size of |
|
The current |
|
The current index into
|
|
The size of the |
|
The number of |
The ExtensionTableHandlerProc
should check the minor
version of the extTableVersion
field. If it has changed
since the ExtensionTableHandlerProc
was written, it
indicates that the value of extElementSize
will be
larger. If the ExtensionTableHandlerProc
is only moving
and deleting elements in the table it could continue to run. However,
if it wants to create new elements, it should remove itself because it
will not know how to create the new fields in the
ExtensionElement
s.
This structure is used internally by the Start Manager, and is
passed to the installed ExtensionTableHandlerProc
each
time it is called.
The ExtensionElement
structure is used to hold
information about each system extension that the Start Manager will
load and execute.
struct ExtensionElement { Str31 fileName; /* The file name */ long parentDirID; /* the file's parent directory ID */ /* everything after ioNamePtr in the HParamBlockRec.fileParam variant */ short ioVRefNum; /* always the real volume reference number*/ /* (not a drive, default, or working dirID) */ short ioFRefNum; SInt8 ioFVersNum; SInt8 filler1; short ioFDirIndex; /* always 0 in table */ SInt8 ioFlAttrib; SInt8 ioFlVersNum; FInfo ioFlFndrInfo; long ioDirID; unsigned short ioFlStBlk; long ioFlLgLen; long ioFlPyLen; unsigned short ioFlRStBlk; long ioFlRLgLen; long ioFlRPyLen; unsigned long ioFlCrDat; unsigned long ioFlMdDat; }; typedef struct ExtensionElement ExtensionElement; typedef ExtensionElement * ExtensionElementPtr;
The first two elements identify the individual file, while the
rest of the elements are copied directly from the
fileParam
variant of the
HParamBlockRec
.
An ExtensionElement
is created for each system
extension found by the Start Manager in the Extensions folder,
Control Panels folder, and System Folder. These
ExtensionElements
are collected into a
ExtensionTable
.
An ExtensionElementPtr
is passed as a parameter to
each installed ExtensionNotificationProc
when it is
called. The ExtensionElement
it points to will contain a
copy of the ExtensionElement
for the system extension
that is currently being loaded and executed.
When an ExtensionNotificationProc
or
ExtensionTableHandlerProc
is called, it will be passed a
message parameter containing one of the following values.
enum { extNotificationBeforeFirst = 0, /* Before any system extensions have loaded */ extNotificationAfterLast = 1, /* After all system extensions have loaded */ extNotificationBeforeCurrent = 2, /* Before system extension at */ /* extElementIndex is loaded */ extNotificationAfterCurrent = 3 /* After system extension at */ /* extElementIndex is loaded */ };
pascal void MyExtensionNotificationProc( UInt32 message, void *reserved, ExtensionElementPtr extElement );
message
input
One of the 4 defined
ExtensionNotification
message codes
reserved
Reserved for future use
extElement
input
Copy of the
ExtensionElement
for the system extension currently being loaded and executed
Note: |
An ExtensionNotificationProc
receives an
ExtensionElementPtr
which points to a copy of the
ExtensionElement
for the system extension currently
being loaded.
Note: |
There can be any number of ExtensionNotificationProcs
installed.
Note: |
pascal void MyExtensionTableHandlerProc( UInt32 message, void *reserved, ExtensionTableHandle extTableHandle );
message
input
One of the 4 defined
ExtensionNotification
message codes
reserved
Reserved for future use
extTableHandle
input
ExtensionTableHandle
containing all system extensions to be loaded
An ExtensionTableHandlerProc
receives a handle to the
ExtensionTable
created at startup by the Start Manager.
When an ExtensionTableHandlerProc
is installed, the
system's default handler no longer manages the
ExtensionTable
. While it is installed, the
ExtensionTableHandlerProc
is responsible for all changes to the
ExtensionTable
, except for incrementing
extElementIndex
between system extensions.
Note: |
The extElementIndex
field is always incremented to
point to the next system extension to be loaded immediately after the
ExtensionTableHandlerProc
is called with the
extNotificationAfterCurrent
message.
WARNING: |
The installed ExtensionTableHandlerProc
is always the
first handler called with extNotificationBeforeFirst
and
extNotificationBeforeCurrent
messages and the last
handler called with extNotificationAfterLast
and
extNotificationAfterCurrent
messages.
There can only be one ExtensionTableHandlerProc
installed.
OSErr InstallExtensionNotificationProc( ExtensionNotificationUPP extNotificationProc )
Parameters:
extNotificationProc
input
The
ExtensionNotificationUPP
to install
Results:
noErr
0
The
ExtensionNotificationUPP
was installed
paramErr
-50
This
ExtensionNotificationUPP
has already been installed
memFullErr
-108
Not enough memory to install the
ExtensionNotificationUPP
Installs an ExtensionNotificationUPP
.
Multiple ExtensionNotificationProcs
may be
installed.
OSErr RemoveExtensionNotificationProc (ExtensionNotificationUPP extNotificationProc)
Parameters:
extNotificationProc
input
The
ExtensionNotificationUPP
to remove
Results:
noErr
0
The
ExtensionNotificationUPP
was installed
paramErr
-50
This
ExtensionNotificationUPP
was not found, orRemoveExtensionNotificationProc
was called from within aExtensionNotificationProc
Removes an ExtensionNotificationUPP
.
Note: |
OSErr InstallExtensionTableHandlerProc( ExtensionTableHandlerUPP extMgrProc, ExtensionTableHandle * extTable)
Parameters:
|
input |
The |
|
input |
A pointer to an |
Results:
noErr
0
The
ExtensionTableHandlerUPP
was installed
paramErr
-50
Another
ExtensionTableHandlerUPP
has already been installed
memFullErr
-108
Not enough memory to install the
ExtensionTableHandlerUPP
Installs an ExtensionTableHandlerUPP
.
There can only be one ExtensionTableHandlerProc
installed.
OSErr RemoveExtensionTableHandlerProc( ExtensionTableHandlerUPP extMgrProc )
Parameters:
extMgrProc
input
The
ExtensionTableHandlerUPP
to remove
Results:
noErr
0
The
ExtensionTableHandlerUPP
was removed
paramErr
-50
This
ExtensionTableHandlerUPP
was not installed,
or theExtensionTable
no longer matches
the originalExtensionTable
.
Remove an ExtensionTableHandlerUPP
. Control is passed
back to the default handler.
Note: |
Note: |
enum { gestaltExtensionTableVersion = FOUR_CHAR_CODE('etbl') /* ExtensionTable version */ }; enum { kExtensionTableVersion = 0x00000100 /* current ExtensionTable version (1.0.0) */ }; /* ExtensionNotification message codes */ enum { extNotificationBeforeFirst = 0, /* Before any system extensions have loaded */ extNotificationAfterLast = 1, /* After all system extensions have loaded */ extNotificationBeforeCurrent = 2, /* Before system extension at */ /* extElementIndex is loaded */ extNotificationAfterCurrent = 3 /* After system extension at */ /* extElementIndex is loaded */ };
struct ExtensionElement { Str31 fileName; /* The file name */ long parentDirID; /* the file's parent directory ID */ /* and everything after ioNamePtr */ /* in the HParamBlockRec.fileParam variant */ short ioVRefNum; /* always the real volume reference number */ /* (not a drive, default, or working dirID) */ short ioFRefNum; SInt8 ioFVersNum; SInt8 filler1; short ioFDirIndex; /* always 0 in table */ SInt8 ioFlAttrib; SInt8 ioFlVersNum; FInfo ioFlFndrInfo; long ioDirID; unsigned short ioFlStBlk; long ioFlLgLen; long ioFlPyLen; unsigned short ioFlRStBlk; long ioFlRLgLen; long ioFlRPyLen; unsigned long ioFlCrDat; unsigned long ioFlMdDat; }; typedef struct ExtensionElement ExtensionElement; typedef ExtensionElement * ExtensionElementPtr; struct ExtensionTableHeader { UInt32 extTableHeaderSize; /* size of ExtensionTable header ( equal to */ /* offsetof(ExtensionTable, extElements[0])) */ UInt32 extTableVersion; /* current ExtensionTable version (same as */ /* returned by gestaltExtensionTableVersion) */ UInt32 extElementIndex; /* current index into ExtensionElement records */ /* (zero-based) */ UInt32 extElementSize; /* size of ExtensionElement */ UInt32 extElementCount; /* number of ExtensionElement records */ /* in table (1-based) */ }; typedef struct ExtensionTableHeader ExtensionTableHeader; struct ExtensionTable { ExtensionTableHeader extTableHeader; /* the ExtensionTableHeader */ ExtensionElement extElements[1]; /* 1 element per system ext. to load */ }; typedef struct ExtensionTable ExtensionTable; typedef ExtensionTable * ExtensionTablePtr; typedef ExtensionTablePtr * ExtensionTableHandle;
OSErr InstallExtensionNotificationProc( ExtensionNotificationUPP extNotificationProc) OSErr RemoveExtensionNotificationProc( ExtensionNotificationUPP extNotificationProc) OSErr InstallExtensionTableHandlerProc( ExtensionTableHandlerUPP extMgrProc, ExtensionTableHandle * extTable) OSErr RemoveExtensionTableHandlerProc( ExtensionTableHandlerUPP extMgrProc )
noErr 0 The ExtensionNotificationUPP was removed. paramErr -50 An error in the parameters prevented the normal execution of the routine. memFullErr -108 Not enough memory to install the ExtensionTableHandlerUPP.
Special thanks to: Dave Evans, Rich Kubota and Quinn