Important: The information in this document is obsolete and should not be used for new development.
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 theOpenComponent
(orOpenDefaultComponent
) 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 theSetComponentInstanceStorage
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:
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
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.
the component parameters record, or use subroutines and theCallComponentFunction
andCallComponentFunctionWithStorage
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 theSetComponentInstanceStorage
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 theCloseComponent
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:
Listing 6-7 shows the subroutine that handles the close request for the
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.
drawing component (as defined in Listing 6-5 on page 6-16). TheOvalClose
function closes the open connection. The drawing component uses theCallComponentFunctionWithStorage
function to call theOvalClose
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 theOvalClose
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 aNIL
handle in thestorage
parameter. For example, you can receive aNIL
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 theComponentFunctionImplemented
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:
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
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.
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 theGetComponentVersion
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
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.
what
- The Component Manager sets this field to
kComponentVersionSelect
.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 thecomponentFlags
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 toFALSE
.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
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.
what
- The Component Manager sets this field to
kComponentRegisterSelect
.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 thecomponentWantsUnregister
flag in thecomponentRegisterFlags
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
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).
what
- The Component Manager sets this field to
kComponentUnregisterSelect
.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
- capture a component and target an instance of it
- capture a component without targeting any instance of it
- target a component instance without capturing the component
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 callsCaptureComponent
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. TheComponentSetTarget
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
, andDoSubtract
. If OldMath'sDoMultiply
function calls its ownDoAdd
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 usesCallComponentFunctionWithStorage
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'sOvalDraw
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'sOvalErase
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'sOvalClick
function. This function determines whether the given point is within the oval. If so, the function returns 1; otherwise, it returns 0. Because theOvalClick
function returns information other than error information as its function result,OvalClick
sets any error information usingSetComponentInstanceError
.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'sOvalMoveTo
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 theSetComponentInstanceError
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.