When a client makes calls to a queued component, it interacts with the recorder provided by COM+. No actual calls to the real object occur. So, at the time of the call, the client has no way to receive output from the method, nor can it tell whether the call succeeded or failed. Consequently, when you design an interface to be supported by a COM+ queued component, you must avoid any outgoing parameters on any interface method.
Specifically, do not use any [out]
,
[in,out]
, or [retval]
IDL
attributes on your method parameters. When you import a component
into the Component Services Explorer, COM+ inspects
the interfaces supported by that component, and if it detects an
output attribute, COM+ disables the queuing option for that
interface.
If you develop your COM+ component using Visual Basic 6.0, you do not
have direct access to your component IDL. Normally, this lack of
access would not be a problem. However, Visual Basic, by default,
treats method parameters as [in,out]
parameters.
If you expect your component to be accessed as a queued component,
you have to explicitly use the Visual Basic ByVal
attribute on your method parameters.
In the next version of Visual Basic, Visual Basic.NET, all parameters are, by default, passed in by value instead of by reference. See Chapter 10 for more information.
A different kind of a parameter returned from a method is its return
value. You should avoid using custom
HRESULT
codes to indicate particular failure
cases. The client only receives the HRESULT
from
the recorder, indicating the success or failure of recording the
call. When your object executes, its HRESULT
codes
are delivered to the player, which does not understand your custom
semantics. COM+ does not require you to stick to the standard
HRESULT
codes, but there is no point in not doing
so.
Another restriction on queued component interfaces is that the client cannot pass in a pointer to another COM object. The reason is obvious—when the actual call takes place later, there is no guarantee that the object passed in as a parameter is still around.
Implementing a queued component implies more than just a few method parameters restrictions and clicked checkboxes on the Component Services Explorer. It really means a change in your design patterns and programming model.
The only way to pass in COM
objects as a method parameter to a queued object
is if the object you pass in supports the interface
IPersistStream
. IPersistStream
is
a standard interface used for object serialization, defined in the
early days of OLE2 and COM. Objects that support
IPersistStream
can serialize their state into a
COM+ provided stream and reconstruct their state out of such a
stream.
Whenever you pass a COM object as a method parameter, COM+ queries it
for IPersistStream
. If the object supports it,
COM+ calls IPersistStream::Save( )
, passing in a
pointer to an IStream
object. The input object
saves its state to the stream. The recorder stores the saved state
information in the message sent to the queued component application
queue. When the player retrieves the message, it creates a stream
object from the message and calls IPersistStream::Load( )
to initialize the object to the state it was in when the
call was made. It then invokes the call on the component, passing in
the input object as parameter.
When you design an interface used by a queued component, you can use
a new IDL extension, an interface
attribute called
QUEUEABLE
, to denote it as an interface used by
a queued component. The
mtxattr.h
header file defines this extension.
Example 8-1 shows the IShipment
interface definition again, this time using the
QUEUEABLE
attribute.
Example 8-1. Using the IDL QUEUEABLE attribute to denote an interface as queued-components compatible
#include "mtxattr.h" // For QUEUEABLE
[
object,
uuid(97184D0F-F7EF-413A-8C6D-C1745018B2E9),
dual,
pointer_default(unique),
QUEUEABLE
]
interface IShipment: IDispatch
{
[id(1)] HRESULT ShipOrder([in]DWORD dwOrderNumber);
};
This attribute autoconfigures the interface as
Queued
when you import a component that supports
the interface into the Component Services Explorer. This
autoconfiguration saves you the trouble of doing it yourself. The
attribute has no semantic meaning for the MIDL compiler; it will not
stop you from defining [out]
parameters on an
interface marked QUEUEABLE
. Only COM+ examines
this
attribute.