Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: More Macintosh Toolbox /
Chapter 6 - Component Manager / Creating Components


Handling Requests for Service

Whenever an application requests services from your component, the Component Manager calls your component and passes two parameters: the application's parameters in a component parameters record and a handle to the memory associated with the current connection. The component parameters record also contains information identifying the nature of the request.

There are two classes of requests: requests that are defined by the Component Manager and requests that are defined by your component. The Component Manager defines seven request codes: open, close, can do, version, register, unregister, and target. All components must support open, close, can do, and version requests. The register, unregister, and target requests are optional. Apple reserves all negative request codes for definition by the Component Manager. You are free to assign request codes greater than or equal to 0 to the functions supported by a component whose interface you have defined. (However, request codes between 0 and 256 are reserved for definition by components of a given type and a given type-subtype. Request codes greater than 256 are available for requests that are unique to your component.)

You can refer to the standard request codes with these constants.

CONST kComponentOpenSelect       = -1; {open request}
      kComponentCloseSelect      = -2; {close request}
      kComponentCanDoSelect      = -3; {can do request}
      kComponentVersionSelect    = -4; {version request}
      kComponentRegisterSelect   = -5; {register request}
      kComponentTargetSelect     = -6; {target request}
      kComponentUnregisterSelect = -7; {unregister request}
The following sections discuss what your component must do when it receives these Component Manager requests.

Responding to the Open Request

The Component Manager issues an open request to your component whenever an application or any other client tries to open a connection to your component by calling the OpenComponent (or OpenDefaultComponent) function. The open request allows your component to establish the environment to support the new connection. Your component must support this request.

Your component should perform the necessary processing to establish the new connection. At a minimum, you must allocate the memory for any global data for
the connection. Be sure to allocate this memory in the current heap zone, not in the system heap. You should call the SetComponentInstanceStorage procedure to inform the Component Manager that you have allocated memory. The Component Manager stores a handle to the memory and provides that handle to your component as a parameter in subsequent requests.

You may also want to open and read data from your component's resource file--if you do so, use the OpenComponentResFile function to open the file and be sure to close the resource file before returning.

If your component uses the services of other components, open connections to them when you receive the open request.

Once you have successfully set up the connection, set your component's function result to 0 and return to the Component Manager.

You can also refuse the connection. If you cannot successfully establish the environment for a connection (for example, there is insufficient memory to support the connection, or required hardware is unavailable), you can refuse the connection by setting the component's function result to a nonzero value. You can also use the open request as an opportunity to restrict the number of connections your component can support.

If your application is registered globally, you should also set the A5 world for your component in response to the open request. You can do this using the SetComponentInstanceA5 procedure. (See page 6-66 for information on this procedure.)

The Component Manager sets these fields in the component parameters record that it provides to your component on an open request:

Field Description
what
The Component Manager sets this field to kComponentOpenSelect.
params
The first entry in this array contains the component instance that identifies the new connection.
Listing 6-6 shows the subroutine that handles the open request for the drawing component. Note that your component can directly access the parameters from
the component parameters record, or use subroutines and the CallComponentFunction and CallComponentFunctionWithStorage functions to extract the parameters for you (see Listing 6-5 on page 6-16). The code in this chapter takes the second approach.

The OvalOpen function allocates memory to hold global data for this instance of the component. It calls the SetComponentInstanceStorage function so that the Component Manager can associate the allocated memory with this instance of
the component. The Component Manager passes a handle to this memory in subsequent calls to this instance of the component.

Listing 6-6 Responding to an open request

FUNCTION OvalOpen (self: ComponentInstance): ComponentResult; 
VAR
   myGlobals: GlobalsHandle;
BEGIN
   {allocate storage}
   myGlobals := 
            GlobalsHandle(NewHandleClear(sizeof(GlobalsRecord)));
   IF myGlobals = NIL THEN 
      OvalOpen := MemError
   ELSE 
   BEGIN
      myGlobals^^.self := self;
      myGlobals^^.boundsRgn := NewRgn;
      SetComponentInstanceStorage(myGlobals^^.self,
                                  Handle(myGlobals));
      {if your component is registered globally, set }
      { its A5 world before returning}
      OvalOpen := noErr;
   END;
END;

Responding to the Close Request

The Component Manager issues a close request to your component when a client application closes its connection to your component by calling the CloseComponent function. Your component should dispose of the memory associated with the connection. Your component must support this request. Your component should also close any files or connections to other components that it no longer needs.

The Component Manager sets these fields in the component parameters record that it provides to your component on a close request:

Field Description
what
The Component Manager sets this field to kComponentCloseSelect.
params
The first entry in this array contains the component instance that identifies the open connection.
Listing 6-7 shows the subroutine that handles the close request for the
drawing component (as defined in Listing 6-5 on page 6-16). The OvalClose
function closes the open connection. The drawing component uses the CallComponentFunctionWithStorage function to call the OvalClose function (see Listing 6-5). Because of this, in addition to the parameters specified in the component parameters record, the Component Manager also passes to the OvalClose function a handle to the memory associated with the component instance.

Listing 6-7 Responding to a close request

FUNCTION OvalClose (globals: GlobalsHandle; 
                    self: ComponentInstance): ComponentResult;
BEGIN
   IF globals <> NIL THEN 
   BEGIN
      DisposeRgn(globals^^.boundsRgn);
      DisposeHandle(Handle(globals));
   END;
   OvalClose := noErr;
END;
IMPORTANT
When responding to a close request, you should always test the handle passed to your component against NIL because it is possible for your close request to be called with a NIL handle in the storage parameter. For example, you can receive a NIL handle if your component returns a nonzero function result in response to an open request.

Responding to the Can Do Request

The Component Manager issues a can do request to your component when an application calls the ComponentFunctionImplemented function to determine whether your component supports a given request code. Your component must support this request.

Set your component's function result to 1 if you support the request code; otherwise, set your function result to 0.

The Component Manager sets these fields in the component parameters record that it provides to your component on a can do request:

Field Description
what
The Component Manager sets this field to kComponentCanDoSelect.
params
The first entry in this array contains the request code as an integer value.
Listing 6-8 shows the subroutine that handles the can do request for the drawing component (as defined in Listing 6-5 on page 6-16). The OvalCanDo function examines the specified request code and compares it with the request codes that it supports. It returns a function result of 1 if it supports the request code; otherwise, it returns 0.

Listing 6-8 Responding to the can do request

FUNCTION OvalCanDo (selector: Integer): ComponentResult;  
BEGIN
   IF ((selector >= kComponentVersionSelect) AND 
      (selector <= kDrawerMoveSelect)) THEN
      OvalCanDo := 1                {valid request}
   ELSE
      OvalCanDo := 0;               {invalid request}
END;

Responding to the Version Request

The Component Manager issues a version request to your component when an application calls the GetComponentVersion function to retrieve your component's version number. Your component must support this request.

In response to a version request, your component should return its version number as its function result. Use the high-order 16 bits to represent the major version and the low-order 16 bits to represent the minor version. The major version should represent the component specification level; the minor version should represent your implementation's version number.

If the Component Manager supports automatic version control (a feature available
in version 3 and above of the manager), it automatically resolves conflicts between different versions of the same component. For more information on this feature, see the next section, "Responding to the Register Request."

The Component Manager sets only the what field in the component parameters record that it provides to your component on a version request:

Field description

what
The Component Manager sets this field to kComponentVersionSelect.
Listing 6-5 on page 6-16 shows how the drawing component handles the version request. It simply returns its version number as its function result.

Responding to the Register Request

The Component Manager may issue a register request when your component is registered. This request gives your component an opportunity to determine whether it can operate in the current environment. For example, your component might use the register request to verify that a specific piece of hardware is available on the computer. This is an optional request--your component is not required to support it.

The Component Manager issues this request only if you have set the cmpWantsRegisterMessage flag to 1 in the componentFlags field of your component's component description record (see "Data Structures for Components" beginning on page 6-50 for more information about the component description record).

Your component should not normally allocate memory in response to the register request. The register request is provided so that your application can determine whether it should be registered and made available to any clients. Once a client attempts to connect to your component, your component receives an open request, at which time it can allocate any required memory. Because your component might not be opened during a particular session, following this guideline allows other applications to make use of memory that isn't currently needed by your component.

If you want the Component Manager to provide automatic version control (a feature available in version 3 and above of the manager), your component can specify the componentDoAutoVersion flag in the optional extension to the component resource. If you specify this flag, the Component Manager registers your component only if there is no later version available. If an older version is already registered, the Component Manager unregisters it. If a newer version of the same component is registered after yours, the Component Manager automatically unregisters your component. You can use this automatic version control feature to make sure that the most recent version of your component is registered, regardless of the number of versions that are installed.

Set your function result to TRUE to indicate that you do not want your component to be registered; otherwise, set the function result to FALSE.

The Component Manager sets only the what field in the component parameters record that it provides to your component on a register request:

Field description

what
The Component Manager sets this field to kComponentRegisterSelect.
If you request that your component receive a register request, the Component Manager actually sends your component a series of three requests: an open request, then the register request, followed by a close request.

For more information about the process the Component Manager uses to register components, see "Registering a Component" on page 6-29.

Responding to the Unregister Request

The unregister request is supported only in version 3 and above of the Component Manager. If your component specifies the componentWantsUnregister flag in the componentRegisterFlags field of the optional extension to the component resource, the Component Manager may issue an unregister request when your component is unregistered. This request gives your component an opportunity to perform any clean-up operations, such as resetting the hardware. This is an optional request--your component is not required to support it.

Return any error information as your component's function result.

The Component Manager sets only the what field in the component parameters record that it provides to your component on an unregister request:

Field description

what
The Component Manager sets this field to kComponentUnregisterSelect.
If you have specified that your component should not receive a register request, then your component does not receive an unregister request if it has not been opened. However, if a client opens and closes your component, and then later the Component Manager unregisters your component, the Component Manager does send your component an unregister request (in a series of three requests: open, unregister, close).

If you have specified that your component should receive a register request, when your component is registered the Component Manager sends your component a series of three requests: an open request, then the register request, followed by a close request. In this situation, even if your component is not opened by a client, the Component Manager sends your component an unregister request when it unregisters your component.

For more information about the componentWantsUnregister flag, see "Resources" beginning on page 6-77.

Responding to the Target Request

The Component Manager issues a target request to inform an instance of your component that it has been targeted by another component. The component that targets another component instance may also choose to first capture the component, but it is not necessary to do so. Thus, a component can choose to

To first capture another component, the capturing component calls the CaptureComponent function. When a component is captured, the Component Manager removes it from the list of available components. This makes the captured component available only to the capturing component and to any clients currently connected to it. Typically, a component captures another component when it wants to override one or more functions of the other component.

After calling the CaptureComponent function, the capturing component can choose to target a particular instance of the component. However, a component can capture another component without targeting it.

A component uses the ComponentSetTarget function to send a target request to a specific component instance. After receiving a target request, whenever the targeted component instance would call itself (that is, call any of its defined functions), instead it should always call the component that targeted it.

For example, a component called NewMath might first capture a component called OldMath. NewMath does this by using FindNextComponent to get a component identifier for OldMath. NewMath then calls CaptureComponent to remove OldMath from the list of available components. At this point, no other clients can access OldMath, except for those clients previously connected to it.

NewMath might then call ComponentSetTarget to target a particular component instance of OldMath. The ComponentSetTarget function sends a target request to the specified component instance. When OldMath receives a target request, it saves the component instance of the component that targeted it. When OldMath receives a request, it processes it as usual. However, whenever OldMath calls one of its defined functions: in its defined API, it calls NewMath instead. (Suppose OldMath provides request codes for these functions: DoMultiply, DoAdd, DoDivide, and DoSubtract. If OldMath's DoMultiply function calls its own DoAdd function, then OldMath calls NewMath to perform the addition.)

The target request is an optional request--your component is not required to support it.

The Component Manager sets these fields in the component parameters record that it provides to your component on a target request:

Field Description
what
The Component Manager sets this field to kComponentTargetSelect.
params
The first entry in this array contains the component instance that identifies the component issuing the target request.

Responding to Component-Specific Requests

When your component receives a component-specific request, it should handle the request as appropriate. For example, the drawing component responds to five component-specific requests: setup, draw, erase, click, and move to. See Listing 6-5 on page 6-16 for the code that defines the drawing component's entry point. The drawing component uses CallComponentFunctionWithStorage to extract the parameters and call the appropriate subroutine.

Listing 6-9 shows the drawing component's OvalSetup function. This function sets up the data structures that must be in place before drawing the oval.

Listing 6-9 Responding to the setup request

FUNCTION OvalSetup (globals: GlobalsHandle; 
                    boundsRect: Rect): ComponentResult;
VAR
   ignoreErr: ComponentResult;
BEGIN
   globals^^.bounds := boundsRect;
   OpenRgn;
   ignoreErr := OvalDraw(globals);
   CloseRgn(globals^^.boundsRgn);
   OvalSetup := noErr;
END;
Listing 6-10 shows the drawing component's OvalDraw function. This function draws an oval in the previously allocated region.

Listing 6-10 Responding to the draw request

FUNCTION OvalDraw (globals: GlobalsHandle): ComponentResult;
BEGIN
   FrameOval(globals^^.bounds);
   OvalDraw := noErr;
END;
Listing 6-11 shows the drawing component's OvalErase function. This function erases an oval.

Listing 6-11 Responding to the erase request

FUNCTION OvalErase (globals: GlobalsHandle): ComponentResult;
BEGIN
   EraseOval(globals^^.bounds);
   OvalErase := noErr;
END;
Listing 6-12 shows the drawing component's OvalClick function. This function determines whether the given point is within the oval. If so, the function returns 1; otherwise, it returns 0. Because the OvalClick function returns information other than error information as its function result, OvalClick sets any error information using SetComponentInstanceError.

Listing 6-12 Responding to the click request

FUNCTION OvalClick (globals: GlobalsHandle; p: Point)
                    : ComponentResult;
BEGIN
   IF PtInRgn(p, globals^^.boundsRgn) THEN
      OvalClick := 1
   ELSE
      OvalClick := 0;
   SetComponentInstanceError(globals^^.self, noErr);
END;
Listing 6-13 shows the drawing component's OvalMoveTo function. This function moves the oval's coordinates to the specified location. Note that this function does not erase or draw the oval; the calling application is responsible for issuing the appropriate requests. For example, the calling application can issue requests to draw, erase, move to, and draw--to draw the oval in one location, then erase the oval, move it to a new location, and finally draw the oval in its new location.

Listing 6-13 Responding to the move to request

FUNCTION OvalMoveTo (globals: GlobalsHandle; x, y: Integer)
                     : ComponentResult;
VAR
   r: Rect;
BEGIN
   r := globals^^.bounds;
   x := x - (r.right + r.left) DIV 2;
   y := y - (r.bottom + r.top) DIV 2;
   OffsetRect(globals^^.bounds, x, y);
   OffsetRgn(globals^^.boundsRgn, x, y);
   OvalMoveTo := noErr;
END;

Reporting an Error Code

The Component Manager maintains error state information for all currently active connections. In general, your component returns error information in its function result; a nonzero function result indicates an error occurred, and a function result of 0 indicates the request was successful. However, some requests require that your component return other information as its function result. In these cases, your component can use the SetComponentInstanceError procedure to report its latest error state to the Component Manager. You can also use this procedure at any time during your component's execution to report an error.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
6 JUL 1996