September 93 - MANAGING COMPONENT REGISTRATION
MANAGING COMPONENT REGISTRATION
GARY WOODCOCK
One of the many design problems a component developer may face is how to register
interdependent components in a predetermined fashion so that any given component is
registered before the components that depend on it. This article and the sample code
that accompanies it show you how to do just that.
The Component Manager is an effective mechanism for providing extended functionality
to the Macintosh platform. Although a single component can perform impressive tasks,
often it's a hierarchy of components, cooperating with one another, that provides the
most powerful capabilities. An example of such a hierarchy is found in QuickTime
movie playback using the movie controller component (see Figure 1). This component
uses the services of many other components, all of which cooperate together, to make
interaction with QuickTime movies very simple yet very powerful.
There are distinct advantages to partitioning functionality in this manner. First, by
creating components that perform simpler processing, you increase the likelihood that
you can leverage the investment you've made in your code by using it in more than one
place. Second, it's easier to debug smaller components than a gigantic
everything-and-the-kitchen-sink component. Finally, a component that provides
very elementary functionality is easier to override or update (via component
replacement or capture) than a large, complex component.
This situation -- a component depending on the presence of several lower-level
components to perform its function -- is very commonplace. In such cases, it's
important to take steps to ensure that supporting components are available when your
component needs them. There are two obvious choices for when to go looking for the
components you depend on: when your component is being registered (in its register
routine), or when your component is first opened (in its open routine). Most
software-dependent components don't need to worry much about managing component
registration. Generally such a component should just auto-register, and then check
for any required components in the open routine; if the required components aren't
available, your open routine can return an error. The caller of your component can
then handle the error in whatever way is most appropriate. There is a case, however,
where checking at registration time might be necessary; that's what this article is
about.
Figure 1 The Movie Controller Component Hierarchy
DO I REALLY NEED TO WORRY ABOUT THIS?
One potential problem occurs in situations where the Component Manager's
registration list is used to build some user interface element, such as a pop-up menu
or a list. In this case, the general assumption is that because a component's name is
displayed in a user interface element, a user can select it and it will do whatever it's
supposed to do -- after all, if the component couldn't perform its function, it wouldn't
be displayed as an option for the user, right? Well, that depends.
Let's look at an example. The SuperOps company builds the WhizBang video digitizer
card and supplies two software components with it -- the WhizBang video digitizer
component and the WhizBang sequence-grabber panel component (which is used to
control features specific to the WhizBang hardware). The component files are named
WhizBang Video Digitizer and WhizBang Panel. In its register routine, the WhizBang
video digitizer component checks for its hardware and registers with the Component
Manager only if the hardware is present (this is normal behavior for components that
encapsulate hardware functionality). The WhizBang sequence-grabber panel
component checks for the availability of the WhizBang video digitizer component when
it receives either an open message or a "panel can run" message -- it doesn't get a
register message, and therefore it always registers successfully with the Component
Manager.
Now let's say I've got a Macintosh Quadra 950 with multiple sound and video digitizers
installed (I can dream, can't I?), one of which is the WhizBang card. I remove the
WhizBang card from my computer, but I leave the two WhizBang components installed.
I then start up my Macintosh Quadra and run my favorite movie capture application. I
display the sequence-grabber video settings dialog box, and I see a dimmed item in the
panel pop-up menu -- "WhizBang panel." The dimmed name indicates one of two
things: another application has the WhizBang video digitizer open, so it's not available,
or the WhizBang video digitizer component isn't registered at all, so the panel can't
run.
In this case, we already know that the WhizBang card isn't installed, so there's no way
this panel canever be enabled, given the current hardware configuration. Rather than
confuse users by displaying the panel name in the pop-up menu (even if it is
dimmed), it would be nicer if it weren't displayed atall. To do that, we need to ensure
the following order of events at startup: the video digitizer component must attempt to
register first, and then the panel component must attempt to register (this implies
that the panel component must implement a register routine), checking for the
presence of the video digitizer component before it does so. Further, this sequence of
events must not be influenced by the alphabetic order of the component filenames.
Guess what? We can realize this goal by managing component registration.
This article and the sample code on this issue's CD demonstrate various ways of
managing component registration. We start with the easiest, most obvious approach
and work our way up to a more sophisticated solution, pointing out the pros and cons of
each along the way. If you just want the "answer" without any fanfare, skip ahead to
the section "Mo' Better: Use a Loader Component to Manage Registration.
I assume that you're familiar with the Component Manager and that you know
something about how components are written. For more information on these topics,
seeInside Macintosh: More Macintosh Toolbox and "Techniques for Writing and
Debugging Components" indevelop Issue 12.
THE SYSTEM VERSION AND THE COMPONENT MANAGER
The Component Manager behaves slightly differently depending on the version of
system software it's running under and how the Component Manager was installed. It's
important to know about these subtleties in order to understand how to work with the
Component Manager to install your components properly.
In system software version 6.0.7, the Component Manager is installed as part of an
INIT (usually the QuickTime INIT). During the INIT installation, the Component
Manager examines the contents of the System Folder and its subfolders for files of type
'thng'; in each 'thng' file, it looks for resources of type 'thng', which it then uses to
register the corresponding components. The important point here is that the
Component Manager is not available until after the INIT has been installed.
Like system software version 6.0.7, versions 7.0 and 7.0.1 pick up the Component
Manager via an INIT, and so again the Component Manager isn't around until after the
INIT has been installed. The main difference in System 7 is that in addition to
searching the System Folder and its subfolders for component files, the Component
Manager will also examine the contents of any subfolders that are in the Extensions
folder.
Examples of INITs in system software versions 7.0 and 7.0.1 that install the
Component Manager are QuickTime, AppleScript, and Macintosh Easy Open. Note that
your component can't assume that just because the Component Manager is installed,
QuickTime is installed -- always use the Gestalt selectors to determine what
functionality is available.
The Component Manager is actually part of System 7.1 and, as a consequence, is
available before the INIT process is started.
METHODS FOR MANAGING COMPONENT REGISTRATION
Now that we have a good idea of when the Component Manager is installed and where it's
searching for components, let's see what we can do to make sure that our components
get registered in the order we want them to be registered.
We'll use some simple components to illustrate the various methods we might use to
manage component registration. In the sample code provided on the CD are three
components -- Moe, Larry, and Curly -- that together establish a functional
component hierarchy (see Figure 2). The hierarchy is such that Moe doesn't depend on
any other components, Larry depends on Moe, and Curly depends on both Larry and
Moe. To enforce these dependencies, we use register routines in Larry and Curly to
make sure that the components they need are present before they actually allow
themselves to be registered with the Component Manager. To let us know when each of