API Reference | developer.brewmp.com API Reference | developer.brewmp.com


API Reference


Brew Release
Brew MP 1.0.2
See Also

This structure represents an object argument to IRemoteObject_Invoke(). The piqi member holds an interface pointer, and the iid member holds an interface ID that describes the type of the interface to which piqi points. This structure is used by "stubs" (clients of Invoke) to send object reference to, or receive an object reference from, "skeletons" (which implement IRemoteSkel and are called in response to an IRemoteObject_Invoke call).
When RemoteObjArg is specified as an input argument, the following rules apply:
- Both members, piqi and iid, are inputs. It is expected that the
implementation of IRemoteObject will cast this pointer value to the type named by the IID, so a mismatch between the values in iid and piqi can result in memory corruption or an invalid pointer dereference.
- A NULL value may be provided for piqi. In this case, the value of iid
is ignored.
When RemoteObjArg is specified as an output argument, the following rules apply:
- The iid member is an input value, and piqi is an output. The stub must
assign iid prior to calling Invoke to identify the expected type of interface. On exit from Invoke, the resulting piqi value, if not NULL, will point to an interface of the type described by IID. The stub is expected to cast piqi to the interface named by the IID.
- Resulting piqi values may be NULL whether Invoke() succeeds or not,
depending on the actions of the target object, so the stub must always guard against dereferencing a NULL piqi.
- A non-NULL output value must be treated as a new counted reference.
The stub must release the reference or transfer that responsiblity to someone else.
- When Invoke returns an error code (any value other than AEE_SUCCESS)
all output object pointers will be NULL.
- The stub does not need to initialize piqi before calling Invoke.
The stub must initialize iid to a valid interface IID.
The following rules apply in all cases:
The value of iid provided by the stub is not delivered to the skeleton. It is used only to identify the type of the piqi pointer being provided or received by the stub.
Since Invoke does not automatically convey type information with the interface, it is up to the stub and skeleton to be in agreement on the type of the interface being passed. This agreement can be based on context and convention, such as static typing of parameters in IDL. The type can also be established at run time by passing IIDs in the data portion of an Invoke call.
When the stub and skeleton are not in agreement on the type of an object reference, undefined behavior results. When the stub and skeleton reside in the same protection domain, this undefined behavior can include memory corruption or invalid pointer dereferences, resulting in a "crash".
Transports that cross protection boundaries must protect skeletons from misbehaving stubs and vice versa. When a stub presents mismatched iid and piqi values, the resulting crash (if any) will occur in the stub's domain. When a skeleton and a stub in different domains are not in agreement on the interface type -- e.g. the stub provides IFoo but the skeleton asks for IBar -- the result is garbled communication, not a crash in either domain.

"Wrapped" Object References

Ordinarily, object references are supplied to Invoke using a C/C++ type specific to a particular interface. For example, to pass a reference to a signal object, a caller would set iid to AEEIID_ISignal and set piqi to a pointer of type "ISignal*".
Internally, transports deal with wrapped representations of object references in order to facilitate remoting. A wrapped representation is an instance of one of the transport interfaces (IRemoteObject, IRemoteSkel, IRemoteRef) that forwards requests to the intended interface or otherwise refers to it. For example, there is just one IRemoteObject type, but different instances of IRemoteObject can forward requests to different wrapped interfaces. Each wrapped interface defines its own protocol that must be "spoken" over IRemoteObject_Invoke. Normally the transport layer handles wrapping and unwrapping, but clients can request the wrapped form of an interface for output objects, and similarly provide the wrapped form for input objects.
In order to support this, Invoke treats the following IIDs, termed "transport IIDs", specially:

When a caller specifies a transport IID for an input parameter, this identifies the *wrapped* interface as the reference to be passed as an input. It will not result in the transport interface itself (e.g. IRemoteObject) being remoted. The transport interface is merely the form in which the caller is presenting the object reference. Likewise for output objects, specifying a transport IID is a way to request a wrapped representation of whatever object reference was provided by the skeleton.
The form of the object reference (wrapped versus unwrapped) does not affect the data being communicated. Across a remote boundary, callers and callees cannot tell which form was used by the other side.
Even when a wrapped form is used, the object reference still has an associated type (the protocol spoken) and stubs and skeletons must be in agreement on that type. For example, if a skeleton expects an object argument of type ISignal, the stub can provide an ISignal, or an IRemoteObject that forwards to an ISignal. If the stub provides an IRemoteObject that forwards to some other interface, communications with that object will be garbled or the object marshaling may fail.
When using a wrapped object reference, iid identifies the type of the interface to which piqi points (one of IRemoteObject, IRemoteSkel, or IRemoteRef), not the type of the wrapped interface.
  •    typedef struct {
          IQI*  piqi;
          AEEIID            iid;
       } RemoteObjArg;