Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1145 lines
68 KiB

// This file is not used, but is retained so we can look and see what was here originally.
/* Yes this file actually compiles!
CallObjects:A Suite of Interfaces forManipulatingCall Frames asObjects
Copyright (C) 1995-1999 Microsoft Corporation. All rights reserved.
Robert Atkinson
05 February, 1999
This interface suite is an architecture for talking to an engine by which variousmanipulations can be performed on call
frames, including marshalling, persistence, stack walking, and the like.
*/
import "oaidl.idl";
interface ICallInterceptor;
interface ICallUnmarshal;
interface ICallFrame;
interface ICallFrameEvents;
interface ICallFrameWalker;
interface IMarshallingManager;
interface IInterfaceRelated;
/* Introduction
The central interface throughwhichmanipulations of call frames (a.k.a. "activation records,"a..ka. "stack frames")is
performed is ICallFrame. Once you get your hands on an ICallFrame instance, you can manipulate the underlying stack frame in
severaldifferentways.Succinctlyput,ICallFrame provides theprimitive,basicbuildingblocksoutofwhich larger
functionality such asmarshalling, call frame persistence, interface-pointer swizzling, and the like can be constructed. It
would be conceivable, for example, to construct a generic implementation of interface proxies and stubs that operated by
dispatching operations to an appropriate ICallFrame instance. Alternately, an infrastructure thatwished to build up method
invocations into a queue to dispatch them at a later time could also be built out of the same primitives.
Instances of ICallFramenever exist in an unbound state; rather, they are always attached to some activation record.
Accordingly, they are not created directly with CoCreateInstance. Instead, clients get their hands on an instance of IClalFrame in
one of two ways.
In the first instantiation technique, you create what is known as an interceptorimplementation of a given interface. Upon
receipt of a call, the interceptor's implementation of the interface manufactures an appropriate ICallFrameobject and then
delivers an ::OnCall notification to an instance ofICallFrameEventspreviously registeredwiththe interceptor using the
ICallInterceptor interface.
The second technique by which instances of ICallFrame are obtained is that of unmarshalling themarshalled form of an
incoming call. The incoming call comes in in the form of a bag 'o bytes in a buffer, but semantically tagged as belonging to a
certain interface (a certain IID) and a certain method number therein. An instance of the appropriate unmarshalling class is
created, and interface ICallUnmarshal can be used to turn the byte stream back into an activation record.
Creation of interceptors and unmarshallers is carried out in the same manner. Indeed, ICallInterceptorand ICallUnmarshalare
usually both supported by the same object instance. To create an interceptor for a given interface or find its unmarshaller,
instantiate the proxy-stub class for the object using CoCreateInstance (rather than the usual mechanism which uses IPsFactory-
Buffer). Ask for the interface IInterfaceRelated, and set the appropriate IID. Then, query for ICallInterceptor or ICallUnmarshal and
party on.
*/
/* ICallFrame
ICallFrame is the workhorse interface through which manipulation of call frames is performed. An ICallFrameinstance never
exits freely in an unbound state; rather an ICallFrame instance is always bound to some particular actual invocation, and so has
an associated method number, a stack frame that can be walked, and so on. If the bound-to stack frame lies in user space, the
call frame is a user mode call frame; this affects the behaviour of certain methods such as, e.g., ICallFrame::Copy,where only
user space data may be copied from a user mode call frame.
An instance of ICallFrame canperform various interesting transformations on a call frame (a.k.a. stack frame, activation
record). For example, the call can be marshalled, or it can bepersisted. The call frame can be walked, looking for various
referenced data that might be of interest.
An appropriate ICallFrame could serve as the internal engine by which a COM interface proxy orinterface stub functioned.
The interface proxy or stub would contain generic logic to drive the marshalling process, calling upon services in ICallFrame
to actually carry out the interface-specific work. Different customers could use the same pieces to, say, persist a call frame
instead of marshalling it. */
[uuid(D573B4B0-894E-11d2-B8B6-00C04FB9618A), object, pointer_default(unique), local]
interface ICallFrame : IUnknown
{
/* Bookkeeping */
typedef struct
{
ULONG iMethod; /* the method number within to which this information applies */
BOOL fHasInValues; /* Are there any in-values (other than the receiver) */
BOOL fHasInOutValues; /* Are there any in-out values */
BOOL fHasOutValues; /* Are there any out-values other than an HRESULT or void return value */
BOOL fDerivesFromIDispatch; /* whether this interface in question derived from IDispatch or not. */
LONG cInInterfacesMax; /* If >= 0, is an absolute upper bound on the number in-interfaces; if < 0, the
method may have an unbounded number of in-interfaces. Of course, if == 0,
there are definitely no in-interfaces. */
LONG cInOutInterfacesMax; /* If >= 0, is an absolute upper bound on the number in-out-interfaces; if <
0, the method may have an unbounded number of in-out-interfaces Of course,
if == 0, there are definitely no in-out-interfaces. */
LONG cOutInterfacesMax; /* If >= 0, is an absolute upper bound on the number out-interfaces; if < 0,
the method may have an unbounded number of out-interfaces Of course, if
== 0, there are definitely no out-interfaces. */
LONG cTopLevelInInterfaces; /* The number of parameters which are simply [in] interface pointers, and so
are passed in the actual stack frame itself (this, of course, can never be
unbounded).*/
IID iid; /* the interface on which this is a call */
ULONG cMethod; /* the total number of methods in that interface */
ULONG cParams; /* the number of parameters in this method, NOT counting the receiver */
} CALLFRAMEINFO;
typedef struct
{
BOOLEAN fIn; /* is this an in parameter */
BOOLEAN fOut; /* is this an out parameter */
ULONG stackOffset; /* offset in bytes from stack location of the frame to start of param */
ULONG cbParam; /* size occupied by parameter on the stack */
} CALLFRAMEPARAMINFO;
HRESULT GetInfo /*
Return miscellaneous information about the call frame. The information returned is a static analysis of the method, not a dynamic one,
in that it is based on an analysis of the method signature only, not the actual current contents of the call frame. For example, the static
analysis might indicate that this method has the potential of having an in-interface, but because of, say, a union switch, a given call
might not actually have any such interfaces.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[out] CALLFRAMEINFO* pInfo /* place at which interesting information about this call frame is returned */
);
HRESULT GetIIDAndMethod /*
Faster form of GetInfo that just returns the IID and /or the method number.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[out] IID* pIID, /* optional */
[out] ULONG* piMethod /* optional */
);
HRESULT GetNames /*
Return a string representation of the method or interface name of this call, if such is available. If a requested name is not available,
then a NULL string is returned.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[out] LPWSTR* pwszInterface, /* OPTIONAL: the place to return the interface name */
[out] LPWSTR* pwszMethod /* OPTIONAL: the place to return the method name */
);
PVOID GetStackLocation /*
Return the stack location onto which this call frame is bound. Notice that this method is not HRESULT-returning; the return value is
rather the requested stack location. */
(
);
void SetStackLocation /*
Set the stack location onto which this call frame is bound. This method is rarely used. Note that the stack frame provided must
conform to the same IID and method number as that for which the call frame was initially created. */
(
[in] PVOID pvStack /* The stack location for the frame. */
);
void SetReturnValue /*
Set the return value stored within this call frame. */
(
[in] HRESULT hr /* The new return value. */
);
HRESULT GetReturnValue /*
Get the return value stored within this call frame. Note: the return value of this method is the requested return value stored in this call
frame. It is not the success or failure of the request to retrieve said return value. */
(
);
HRESULT GetParamInfo /*
Return miscellaneous information a particular parameter in this invocation.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] ULONG iparam, /* zero-origin parameter number */
[out] CALLFRAMEPARAMINFO* pInfo /* place at which interesting information about this call frame is returned */
);
HRESULT SetParam /*
Set the value of a particular parameter in this frame, if possible, given the data types involved.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] ULONG iparam, /* zero-origin parameter number */
[in] VARIANT* pvar /* the new value for this parameter */
);
HRESULT GetParam /*
Return the value of a particular parameter in this frame, if possible, given the data types involved.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] ULONG iparam, /* zero-origin parameter number */
[out] VARIANT* pvar /* the current value of this parameter */
);
/* Copying& Freeing */
typedef enum /* flags used in ::Copy. Use exactly one value. */
{
CALLFRAME_COPY_NESTED = 1, /* Client guarantees that he will only use the copied call frame in a manner where its lifetime
is properly nested in the lifetime of its parent frame. When this flag is used, very significant
optimizations can be made and memory allocations avoided by cleverly sharing actual
parameter data.
Indeed, with this flag specified to a Copy operation, only the i nterface pointer s transitively
reachable in the source frames are guaranteed to be deep copied and thus in the copy be
stored in memory separate from that in which they are stored in the source frames; other
data types may actually in the copied frame share memory with the source if the Copy
operation is intelligent enough to do so
A consequence is that whichever of these three CALLFRAME_COPY flags are passed to
ICallFrame::Copy, the interface pointers see by optionally provided interface walkers (see
the method specification) may always be modified if desired without consequence of
disturbing the interface pointers residing in the parent frame. However, if
CALL_FRAME_COPY_NESTED is used, then the same cannot be said of any other type
data types. .*/
CALLFRAME_COPY_INDEPENDENT = 2, /* Client requests that the copied call frame have a lifetime which is wholly independent
from its parent */
CALLFRAME_COPY_NONLOCAL = 3, /* Only significant when executing a frame copy operation in kernel mode. Requests that not
only should the lifetime of the copied frame data be independent of its parent, but that the
actual copied data should reside in the opposite memory space from that of the parent data:
if the parent frame is a user mode frame, the copied frame will be a kernel mode frame, and
visa versa */
} CALLFRAME_COPY;
HRESULT Copy /*
Create a deep copy of this call frame. A deep copy of a call frame copies the frame and all of the data that is reachable therefrom. It
can be roughly conceptualized asmarshalling the frame, then immediately unmarshalling it; however, in practice it willbe
significantly more efficient than actually carrying out these two steps. A copy of a call frame can only be made of the in-values in the
'before-call' state of the frame; once the frame has been invoked, and thus contains out-values, it cannot be copied.
As data is copied, interface pointers in the copied data can be noted. If an ICallFrameWalkerimplementation is provided in the
optional pWalker parameter, then pWalker->OnWalkInterface will be called for each interface pointer that is copied, just after the copy
of the interface pointer value is made. The call frame implementation itself simply copies interface pointers as binary values.
Specifically, no reference count adjustments of any form are performed. If some other behaviour is desired, the pWalker parameter
must be used.
Recall that a "user mode" call frame is one whose underlying stack pointer resides in user mode. In the process of copying a user-
mode call frame, kernel mode implementations of the Copy operation ensures that only user-mode addresses are used in the data
transitively reachable from the frame. Should an illegal non-user mode address be provided, an HRESULT derived from the error
ERROR_INVALID_ADDRESS is returned.
The copyControl parameter controls how much if any the data within the copied frame can be shared with data in the parent frame.
See the CALLFRAME_COPY enumeration for details.
The successfully copied frame is returned to the caller through *ppFrame. The frame so returned has a (normal) indefinite lifetime.
The caller is explicitly responsible for calling Free on the frame copy in order to clean up the copied data. This must always be done,
or memory leakage will occur; the call frame does not clean up the copied data automatically by itself.
Return value Meaning
S_OK All is well
HRESULT_FROM_WIN32(ERROR_INVALID_ADDRESS) An attempt was made to copy from a user mode stack frame data which itself did not lie in
user space.
CALLFRAME_E_ALREADYINVOKED An invocation has already been made from this frame.
E_UNEXPECTED An unexpected error occurred. */
(
[in] CALLFRAME_COPY copyControl, /* Controls how much the child frame can share data with the parent frame */
[in] ICallFrameWalker* pWalker, /* Optional. If provided, then OnWalkInterface is called for each copied
interface pointer after the copy has been made. If a walker is not provided,
then the any interface pointers encountered are AddRef'd. For kernel mode
clients copying user mode frames, this is unlikely to be reasonable: such
clients should almost certainly provide a walker to handle things safely. */
[out] ICallFrame** ppFrame /* place at which new frame is returned */
);
HRESULT Free /*
First, optionally propagate the out-values of the frame to another destination frame, which is often a parent from which this frame was
originally copied. This propagation is logically a deep copy, but if the source and destination frames are either both user mode or both
kernel mode frames, then much actual allocation and deallocation can be avoided by simply transferring ownership of data from
source to destination frames.
If there are any [in,out] parameters in the destination frame, then the propagation first requires that the existing values that reside in
those [in,out] parameters be freed. For interface pointers found therein, the freeing action can be controlled by providing a callback
object in pWalkerDestFree.
Once [in,out] parameters in the destination frame are freed, the propagation of out-values is (logically) carried out. If pWalkerCopy is
provided, then it is called on each interface pointer contained in the propagated out-values.
Second, optionally free some or all of the remaining data accessible from the source frame. Whether in, in-out, and / or out parameters
are to be freed are indicated by the particular flags that may be indicated in the flags parameter, see the enumeration CALL-
FRAME_FLAGS for details.
Third, optionally, initialize out-parameters to appropriate NULL states, including the return value.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] ICallFrame* pframeArgsDest, /* Optional. If present, is the stack pointer of the call frame to which the
out-values should be copied before freeing is carried out. */
[in] ICallFrameWalker* pWalkerDestFree, /* Optional. Ignored unless pframeArgsDest is also non-NULL. Indicates
a callback object which should be notified as interface pointers residing
in in-out parameters of pframeArgsDest need be freed. If absent, then
such interface pointers are simply Release()ed. */
[in] ICallFrameWalker* pWalkerCopy, /* Optional. Ignored unless pframeArgsDest is also non-NULL. Indicates
a call back object which should be notified as interfaces are copied
during call frame copying. If absent, then interface pointers are
AddRef()d as the copy is made. */
[in] DWORD freeFlags, /* flags drawn from the enumeration CALLFRAME_FREE */
[in] ICallFrameWalker* pWalkerFree, /* Optional. If specified, then a call back will be made for each interface
pointer encountered as freeing is carried out. If absent, then interface
pointers encountered during freeing are Release()d.
Note: when freeing a frame and specifying a pframeArgsDest which is in
the same memory spa ce as that of the receiver frame, then o nl y
pWalkerCopy is called on each interface pointer, not both pWalkerCopy
and pWalkerFree as one might perhaps expect.
Note to kernel mode users: If caller of Free is in kernel mode worried
about the possibility of user mode malicious guy then he should either a)
always provide a walker to deal with the callbacks, or b) make sure by
the way that the frame got created in the first place that there aren't any
user mode objects lying around. */
[in] DWORD nullFlags /* Values drawn from the enumeration CALFRAME_NULL_FLAGS. If
any bits are set herein, then once any freeing has been carried out, then
out-values and-or in-out values which are pointers are to be set to NULL.
If no bits are set, then this NULLing need not be carried out after the
freeing, though it is legal for the implementation to NULL the freed
pointers anyway.
Note that it is legal to NULL the out values without first having freed
them. This is commonly done on the client side in the situation where the
server was not actually invoked so no unmarshalling of return values was
attempted. */
);
enum CALLFRAME_FREE /* a bitfield enumeration: use one or more values in ::Free */
{
CALLFRAME_FREE_NONE = 0,
CALLFRAME_FREE_IN = 1, /* If TRUE, then in-values are to be freed. This includes both the data referenced
therefrom an any top level pointer (should there be one).
If FALSE, in-values are to be left alone.
In a marshalling situation, this is typically set to TRUE on the s erve r side after clialng the
object in order to free the in-parameters that were allocated by the system during
unmarshalling of the in-values */
CALLFRAME_FREE_INOUT = 2, /* If TRUE, then the data referenced in in-out-values is to be freed. The top-level pointer,
which is the actual parameter value, is not, however freed. But see also
CALLFRAME_FREE_TOP_INOUT below.
If FALSE, then in-out-values are not freed; existing contents thereof are ignored.
On the server side, this is typically used post-call, as in CALLFRAME_FREE_IN. On the
client side, this is used in the situation where the sever was not actually invoked (and so
unmarshalling of return values was not attempted) and in the situation where there was a
failure during unmarshalling of the return values. */
CALLFRAME_FREE_OUT = 4, /* If TRUE, then data referenced in out-values is to be freed. The top-level pointer, which
is the actual parameter value, is not, however, freed.
If FALSE, then out-values are not freed; existing contents thereof are ignored.
On the server side, this is, again, used post call as in CALLFRAME_FREE_IN. On the
client side, this is typically only use in the even of a failure during unmarshalling of return
values. */
CALLFRAME_FREE_TOP_INOUT = 8, /* If TRUE, then for [in,out] parameters, the top level pointer, which is the actual
parameter value, is to be freed. */
CALLFRAME_FREE_TOP_OUT = 16, /* If TRUE, then for [out] parameters, the top level pointer, which is the actual parameter
value, is to be freed. */
CALLFRAME_FREE_ALL = 31, /* Combination of all freeing flags */
};
enum CALLFRAME_NULL /* a bitfield enumeration: use one or more values in ::Free */
{
CALLFRAME_NULL_NONE = 0, /* no values are to be NULLed */
CALLFRAME_NULL_INOUT = 2, /* in-out values are to be NULLed */
CALLFRAME_NULL_OUT = 4, /* out-values are to be NULLed */
CALLFRAME_NULL_ALL = 6, /* combination of the above two flags */
};
HRESULT FreeParam/*
Free just a particular parameter in this frame. This method provides a proper subset of the effect that can be carried out by
ICallFrame::Free. Specifically, ICallFrame::Free provides out-valuepropagation behaviour,which this method does not, and
ICallFrame::Free acts on all the parameters in the method, whereas this method only acts on a particular method.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] ULONG iparam, /* the parameter number to be freed */
[in] DWORD freeFlags, /* as in ICallFrame::Free */
[in] ICallFrameWalker* pWalkerFree, /* as in ICallFrame::Free. */
[in] DWORD nullFlags /* as in ICallFrame::Free. */
);
/*Walking */
HRESULT WalkFrame /*
Walk this call frame, looking for interface pointers transitively reachable from the arguments of the frame.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] DWORD walkWhat, /* Values taken from CALLFRAME_WALK, indicating what combination of
[in], [in,out], or [out] parameters are to be walked */
[in] ICallFrameWalker* pWalker /* The call back through which we notify of interface pointers we have found.
*/
);
enum CALLFRAME_WALK /* a bitfield enumeration: use one or more values in ::WalkFrame */
{
CALLFRAME_WALK_IN = 1, /* in values are to be walked */
CALLFRAME_WALK_INOUT = 2, /* in-out values are to be walked */
CALLFRAME_WALK_OUT = 4, /* out-values are to be walked */
};
/*Marshalling */
/* CALLFRAME_MARSHALCONTEXT
A structure used to pass about information about the context in which marshalling is to be carried out. */
typedef struct
{
BOOLEAN fIn; /* Whether we are to marshal the in-values or the out-values. In a
marshalling situation, the in-values are marshalled on the client side,
and the out-values are marshalled on the server side. */
DWORD dwDestContext; /* … */
LPVOID pvDestContext; /* … */
IMarshallingManager* mshlmgr; /* Engine responsible for marshalling object interfaces */
GUID guidTransferSyntax; /* The transfer syntax with which the marshalling should occur. */
} CALLFRAME_MARSHALCONTEXT;
HRESULT GetMarshalSizeMax /*
Return a reasonable upper limit on the amount of buffer size that would be needed were::Marshalto be called. Typically, a
marshalling engine (such as an interface proxy) calls ::GetMarshalSizeMaxto learn how big of a buffer is need, talks to some other
party (such as the channel) to allocate the buffer, then calls ::Marshal toactually carry out the marshalling.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] CALLFRAME_MARSHALCONTEXT* pmshlContext, /* Context information about how we'd go about marshalling */
[in] MSHLFLAGS mshlflags, /* As in the IMarshal interface */
[out] ULONG* pcbBufferNeeded /* Size of the buffer that will be needed */
);
HRESULT Marshal /*
Ask call frame to turn itself and its transitively-reachable data into a flat buffer.
The act of marshalling a call frame never disturbs the frame. When marshalling in-values, after a call to ::Marshal, whether successful
or not, the in-versions of in-out values are still present, and out-only values are still undefined. When marshalling out-values, after a
call to ::Marshal, whether successful or not, the out-parameters are still present and valid.
If this function fails (returns an error), then it is a no-op (or may as well be assumed to be, as nothing further can be done by the caller
to clean up). Resources such as memory transiently allocated during the attempted marshalling have been freed, and so on.
The act of marshalling interfaces warrants special attention. Non-interface data which is marshalled is simply flattened in place into
the output buffer in a standard way. Interface pointers are marshalled by asking the providedIMarshallingManager*to do the
marshalling; should none be provided, CoMarshalInterface is used. Different marshalling behaviour, 'marshlialng' vs. 'persisting', can
be achieved by using different IMarshallingManager* engines to carry out themarshalling operation. See the description of
IMarshallingManager for further information.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] CALLFRAME_MARSHALCONTEXT* pmshlContext, /* Context information about how we'd go about marshalling */
[in] MSHLFLAGS mshlflags, /* As in the IMarshal interface */
[in,size_is(cbBuffer)] PVOID pBuffer, /* Buffer into which we should put the marshalled data */
[in] ULONG cbBuffer, /* The size of the buffer in bytes */
[out] ULONG* pcbBufferUsed, /* Optional. Size of the buffer that was actually used */
[out] RPCOLEDATAREP* pdataRep, /* Optional. If provided, then through here is returned the NDR
data representation with which the data was marshalled. For
Win32 machines, this is always 0X00000010L, which is 'little
endian, ASCII characters, IEEE floats. See also IRpcChannel-
Buffer::GetBuffer */
[out] ULONG* prpcFlags /* Optional. If provided, then through here is returned RPC flags
associated with the call. See also IRpcChannelBuffer::-
GetBuffer */
);
HRESULT Unmarshal /*
Unmarshal a packet of data containing the previously marshalled out-vuales of a call into this already-extiisng activation record.
As a side effect of the unmarshalling, the in-versions of any in-out values are freed (interface pointers are released) in order that they
may be replaced with their out-versions.
On exit, all the in-out-values and out-values will always be set to reasonable values, either (a) an in-version of an in-out-value, (b) an
out-value successfully unmarshalled from the returned data, or (c) a value explicitly initialized to NULL. On failure return, the caller
will typically want to call ::Free in order to clean up those values which are not in fact NULL.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in,size_is(cbBuffer)] PVOID pBuffer, /* Buffer containing the marshalled out-values */
[in] ULONG cbBuffer, /* The size of the buffer in bytes */
[in] RPCOLEDATAREP dataRep, /* The data representation with which the data was marshalled
*/
[in] CALLFRAME_MARSHALCONTEXT* pcontext, /* Manager etc responsible for unmarshalling interface
references */
[out] ULONG* pcbUnmarshalled /* Optional. Is the number of bytes that were successfully
unmarshalled. This parameter is returned even in error
situations */
);
HRESULT ReleaseMarshalData /*
Release resources that may be being held by interface pointers residing in a packet of marshalled data. This method finds all interface
pointers in the packet, and, in effect, calls CoReleaseMarshalData on each one.
Logically speaking, ReleaseMarshalData must alwaysbe ultimately called exactly once to clean up the resources held in the
marshalled buffer, though typically (in the MRSHLFLAGS_NORMALcase) this is done as a side effect of the act of unmarshalling and
so need not be carried out explicitly.
This method can function correctly on both marshalled in-parameters and marshalled out-parameters.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in,size_is(cbBuffer)] PVOID pBuffer, /* Buffer containing the marshalled out-values */
[in] ULONG cbBuffer, /* The size of the buffer in bytes */
[in] ULONG ibFirstRelease, /* The first byte in the buffer which is to actually be released; a
value of zero implies interface pointers in the whole buffer are to
be released. The idea is that marshalled interface pointers prior
to the indicated byte are assumed to have already been released
by some other mechanism */
[in] RPCOLEDATAREP dataRep, /* The data representation with which the data was marshalled
*/
[in] CALLFRAME_MARSHALCONTEXT* pcontext /* Manager etc responsible for unmarshalling interface
references */
);
/* Invocation */
HRESULT Invoke /*
Apply this activation record to an object. In a marshalling situation, typically this is carried out on the server side, and is the means by
which the work of the actual object is accomplished.
Generally speaking, carrying out the invocation involves allocating a new stack frame, shallow-copying down the data in the original
frame, then calling the appropriate method in the indicated object. The object invoked may then chose to modify out-parameters
which are reachable from the copied frame, according to the appropriate semantics of the invocation. When the invocation returns
from the object, the call frame automatically captures the return value à la ICallFrame::SetReturnValue.
Return value Meaning
S_OK All is well
CALLFRAME_E_ALREADYINVOKED An invocation has already been made from this frame.
E_UNEXPECTED An unexpected error occurred. */
(
[in] void* pvReceiver, /* The interface on which the invocation is to occur. Caller is responsible for ensuring that
this interface is in fact of the appropriate IID; the ::Invoke implementation will simply do a
cast and assume that that is the case. */
... /* This is a VARARGS function. Additional parameters, if any, are used to fill unbound
values in the activation record other than the receiver, if any should be present. At present,
no known methods require this. */
);
};
/* ICallIndirect
ICallIndirect is an interface by which an invocation can be caused to be carried out on an object with an i ndirec t reference to the
invocation's arguments, rather than the traditional direct call. A given instance of ICallIndirect supports indirect invocations for
just one IID.
The actual detailed semantics of how to carry out an indirect call are independent of the ICallIndirect interface itself; they are
instead specific to the implementation of the interface. For example, implementations of ICallIndirect found in call interceptors
(see below) carry out the call by constructing and appropriate IaCllFrame instance and then invoking IClalFrameEvents::OnCall in
the registered sink. Other implementations might do some appropriate munging of the invocation's arguments, then forward
thecallon tosomeactualspecificobject,presumablyonepreviously registeredwith theICallIndirectusingsome
implementation-specific means.
*/
[uuid(D573B4B1-894E-11d2-B8B6-00C04FB9618A), object, pointer_default(unique), local]
interface ICallIndirect : IUnknown
{
HRESULT CallIndirect /*
Invoke one of the methods in the interface that this interceptor intercepts, but with an indirect reference to the arguments of the
invocation.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[out] HRESULT* phrReturn, /* the value returned from the invocation of the method */
[in] ULONG iMethod, /* the method number which should be invoked */
[in] void* pvArgs, /* pointer to the stack frame with which to make the invocation. Details of the exact
representation of this stack frame are processor-architecture specific */
[out] ULONG* cbArgs /* on exit, the number of bytes which should be popped from the stack in order to clear the
stack of the arguments to this invocation */
);
HRESULT GetMethodInfo /*
Return miscellaneous information about the a method in this interface. The information returned is a static analysis of the method, not
a dynamic one, in that it is based on an analysis of the method signature only, not the actual current contents of the call frame. For
example, the static analysis might indicate that this method has the potential of having an in-interface, but because of, say, a union
switch, a given call might not actually have any such interfaces.
This method is equivalent to the GetInfo and GetNames methods in ICallFrame, but avoids the need to actually make any invocation to
get the information.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] ULONG iMethod, /* the method number which should be considered */
[out] CALLFRAMEINFO* pInfo, /* place at which interesting information about said method is returned */
[out] LPWSTR* pwszMethod /* OPTIONAL: the place to return the method name, if available */
);
HRESULT GetStackSize /*
Return the number of bytes which should be popped from the stack in order to return from an invocation of the indicated method.
This is equivalent to the value returned via the cbArgs parameter to CallIndirect, but avoids the need to actually make any invocation
to get the information.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] ULONG iMethod, /* the method number which should be considered */
[out] ULONG* cbArgs /* on exit, the number of bytes which should be popped from the stack in order to clear the stack
of the arguments to an invocation of this method number */
);
HRESULT GetIID /*
Return the (most derived) interface id supported by this ICallIndirect implementation.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[out] IID* piid, /* Optional: the interface in question */
[out] BOOL* pfDerivesFromIDispatch, /* Optional: whether said interface ultimately derives frrom IDispatch */
[out] ULONG* pcMethod, /* Optional: the number of methods in that interface */
[out] LPWSTR* pwszInterface /* OPTIONAL: the place to return the interface name, if available */
);
};
/* ICallInterceptor
ICallInterceptor thecentral interfacesupportedby interface interceptors.This interfacesupports theregistrationand
unregistration of sinks wishing to be notified of calls made directly on the interface in the normal way. In addition, this
interface provides ameans bywhich an invocation can be caused to be carried outwith an indirect reference to the
invocation's arguments.
All implementations of ICallInterceptor also implement the interface that they intercept.
Notice that the ICallInterceptor interface derives from ICallIndirect.
*/
[uuid(60C7CA75-896D-11d2-B8B6-00C04FB9618A), object, pointer_default(unique), local]
interface ICallInterceptor : ICallIndirect
{
HRESULT RegisterSink /*
Register a sink for receiving notifications of method calls. Only a single sink may be registered with an interceptor at any given time.
Registering a sink of NULL is legal, and causes the interceptor to release any previously registered sink that it might be holding on to.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] ICallFrameEvents* psink
);
HRESULT GetRegisteredSink /*
Return the presently registered event sink, if any.
Return value Meaning
S_OK All is well; the registered sink, if any, is returned.
CO_E_OBJNOTREG There is no sink presently registered with this interceptor.
E_UNEXPECTED An unexpected error occurred. */
(
[out] ICallFrameEvents** ppsink
);
};
/* ICallFrameEvents
ICallFrameEvents is the interface on which method call notifications are delivered.
*/
[uuid(FD5E0843-FC91-11d0-97D7-00C04FB9618A), object, pointer_default(unique), local]
interface ICallFrameEvents : IUnknown
{
HRESULT OnCall /*
Informs the sink of the receipt of a method call on the interceptor. The sink is provided with an ICallFrame instance which is bound to
the intercepted incoming method invocation. Through that sink the call frame can be manipulated in various ways.
On return from OnCall, the interceptor assumes that by some means the out-values of the method have been appropriately initialized
as needed, if any; the interceptor does not itself manipulate the call frame further in any way. Typically, the OnCall implementation
will have set the out-values by somemeans, either by invoking the call frame on an object, successfully unmarshalling some
previously marshaled out-values, or NULLing them with ICallFrame::Free.
The return value should also have been appropriately set during the call in a similar manner. See also ICallFrame::SetReturnValue.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] ICallFrame* pFrame /* A call frame bound to the just-received invocation */
);
};
/*ICallUnmarshal
ICallUnmarshal is typically used on the server (receiving) side of a remote invocation. An appropriate instance of ICallUnmarshal
can be used to transform back into an call frame a method invocation previously marshalled by a call to IClalFrame::Marshal on
the client (sending) side. Once such a reconstituted call frame is obtained, the call can be (e.g.) carried out on an actual object
using ICallFrame::Invoke.
ICallUnmarshal is typically implemented by the interceptor for a given interface.
*/
[uuid(5333B003-2E42-11d2-B89D-00C04FB9618A), object, pointer_default(unique), local]
interface ICallUnmarshal : IUnknown
{
HRESULT Unmarshal /*
Turn a marshalled packet of data back into an activation record in preparation to being able to actually carry out an invocation or
other manipulation of the activation record. It must always be the case that the packet of data passed here toICallUnmar-
shal::Unmarshal contains the in-values of a call; see also ICallFrame::Unmarshal which deals with out-values.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] ULONG iMethod, /* The method number which is to be unmarshalled. A value of 0xFFFFFFFF
indicates that the caller instead expects the method number to be determined
from the data to be unmarshalled. Which of these two is appropriate depends
on the protocol used to transfer the marshalling packet from client to server. */
[in,size_is(cbBuffer)]
PVOID pBuffer, /* Buffer from which the activation record is to be reconstituted */
[in] ULONG cbBuffer, /* Size of the buffer in bytes */
[in] BOOL fForceBufferCopy, /* If true, then during the unmarshal process the engine will copy and retain
the passed-in buffer so long as it needs it. If false, however, then caller
promises that the buffer passed in will remain valid for at least as long as the
ICallFrame returned herefrom is still alive */
[in] RPCOLEDATAREP dataRep, /* The data representation with which the data was marshalled */
[in] CALLFRAME_MARSHALCONTEXT *
pcontext, /* Manager etc responsible for unmarshalling interface references */
[out] ULONG* pcbUnmarshalled, /* Optional. Is the number of bytes that were successfully unmarshalled. This
parameter is returned even in error situations. */
[out] ICallFrame** ppFrame /* A call frame bound to the just-unmarshalled invocation */
);
HRESULT ReleaseMarshalData /*
Release resources that may be being held by interface pointers residing in a packet of marshalled data. This method finds all interface
pointers in the packet, and, in effect, calls CoReleaseMarshalData on each one.
Logically speaking, ReleaseMarshalData must alwaysbe ultimately called exactly once to clean up the resources held in the
marshalled buffer, though typically (in the MRSHLFLAGS_NORMALcase) this is done as a side effect of the act of unmarshalling and
so need not be carried out explicitly.
This method can function correctly on both marshalled in-parameters and marshalled out-parameters.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] ULONG iMethod, /* the method number whose data is to be released */
[in,size_is(cbBuffer)] PVOID pBuffer, /* Buffer containing the marshalled out-values */
[in] ULONG cbBuffer, /* The size of the buffer in bytes */
[in] ULONG ibFirstRelease, /* The first byte in the buffer which is to actually be released; a
value of zero implies interface pointers in the whole buffer are to
be released. The idea is that marshalled interface pointers prior
to the indicated byte are assumed to have already been released
by some other mechanism */
[in] RPCOLEDATAREP dataRep, /* The data representation with which the data was marshalled
*/
[in] CALLFRAME_MARSHALCONTEXT* pcontext /* Manager etc responsible for unmarshalling interface
references */
);
};
/* ICallFrameWalker
ICallFrameWalker is the callback interface used to walk a stack frame, looking for interesting values. See ICallFrame::WalkFrame.
*/
[uuid(08B23919-392D-11d2-B8A4-00C04FB9618A), object, pointer_default(unique), local]
interface ICallFrameWalker : IUnknown
{
HRESULT OnWalkInterface /*
The walker has discovered an interface in the call frame. We are informed of its IID and its location; we can manipulate the interface,
and we may replace it if desired, being careful to get the reference counting right.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] REFIID iid, /* the IID of the interface that has been found */
[in] PVOID* ppvInterface, /* Buffer from which the activation record is to be reconstituted */
[in] BOOL fIn, /* is this an interface inside an in- or in-out-parameter? */
[in] BOOL fOut /* is this an interface inside an out- or in-out-parameter? */
);
};
/* IMarshalSomeone
IMarshalSomeone is an interface by which a client can request that some implicitly-specified object be marshalled.
The functionality in the interface is similar to that of IMarshal. However, the data returned by IMarshalSomone::Marshal is a full
OBJREF, just as would be returned by CoMarshalInterface. This contrasts with IMarshal, wherein IMarshal::Marshal returns just
the custom-marshalling-data part of an object reference.
*/
[uuid(174F4929-53EC-11d2-B8AC-00C04FB9618A), object, pointer_default(unique), local]
interface IMarshalSomeone : IUnknown
{
HRESULT GetMarshalSizeMax /*
Similar to IMarshal::GetMarshalSizeMax.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] REFIID iid,
[in] void* pv,
[in] DWORD dwDestContext,
[in,unique] void* pvDestContext,
[in] DWORD mshlflags,
[out] DWORD* pSize
);
HRESULT MarshalInterface /*
Similar to IMarshal::MarshalInterface.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in,unique] IStream* pstm,
[in] REFIID iid,
[in] void* pv,
[in] DWORD dwDestContext,
[in,unique] void* pvDestContext,
[in] DWORD mshlflags
);
HRESULT UnmarshalInterface /*
Similar to IMarshal::UnmarshalInterface.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in,unique] IStream* pstm,
[in] REFIID iid,
[out] void** ppv
);
HRESULT ReleaseMarshalData /*
Similar to IMarshal::ReleaseMarshalData.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in,unique] IStream* pstm
);
};
/* IMarshallingManager
IMarshallingManager instances are used as themechanismbywhich call frames actually carry out themarshalling and
unmarshalling of an interface pointer.
*/
[uuid(F6EBEB2B-C8DE-11d1-B88E-00C04FB9618A), object, pointer_default(unique), local]
interface IMarshallingManager : IUnknown
{
HRESULT GetMarshallerFor /*
Return an IMarshal instance that can then be used to marshal the indicated interface on this object. Typically, the marshaller returned
is implemented by the marshalling manager itself. Internally, it usually refers to either the object's IMarshal implementation, if it
custom marshals itself, or a marshalling-manager-provided 'standard' IMarshal implementation.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] REFIID iidToMarshal, /* the IID of the interface to be marshalled */
[in] PVOID pvInterface, /* the interface iid on the object which is to be marshalled */
[out] IMarshalSomeone** ppMarshal /* a marshaller appropriate for this object */
);
HRESULT GetStandardMarshallerFor /*
Similar to GetMarshallerFor, but is guaranteed to never reference the object's IMarshal implementation, but rather always use the
marshalling-manager-provided 'standard' IMarshal implementation. In this respect, this method is similar to the CoGetStnadadrMar-
shal API.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] REFIID iidToMarshal, /* the IID of the interface to be marshalled */
[in] PVOID pvInterface, /* the interface iid on the object which is to be marshalled */
[in] LPUNKNOWN punkOuter, /* controlling unknown for the marshaller */
[in] REFIID iid, /* iid sought on the returned marshaller */
[out] void** ppv /* place at which marshaller is to be returned */
);
HRESULT GetUnmarshaller /*
Return an IMarshal instance whose UnmarshalInterface can be used to unmarshal an interface pointer that was marshalled previously
with a the IMarshal returned from a call to GetMarshallerFor or GetStandardMarshallerFor.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] REFIID iidHint, /* The iid for which unmarshalling is required. May legally be
IID_NULL, in which case the iid in question must be determined from the
later unmarshalled data; this is common. */
[out] IMarshalSomeone** ppMarshal /* place at which the unmarshaller is to be returned */
);
};
/* IInterfaceRelated
This interface is used to provide an IID parameter required in some initialization contexts.
*/
[uuid(D1FB5A79-7706-11d1-ADBA-00C04FC2ADC0), object, pointer_default(unique), local]
interface IInterfaceRelated : IUnknown
{
HRESULT SetIID /*
Set the required IID parameter.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] REFIID iid
);
HRESULT GetIID /*
Return the underlying IID.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[out] IID* piid
);
};
/* Error Codes
We define some new error codes intended for use with the interfaces defined here.
*/
cpp_quote("#define CALLFRAME_E_ALREADYINVOKED _HRESULT_TYPEDEF_( 0x8004d090 )") /* An invocation has already been made on this call frame
*/
cpp_quote("#define CALLFRAME_E_COULDNTMAKECALL _HRESULT_TYPEDEF_( 0x8004d091 )") /*A requested invocation could not be carried out */
/* APIs
This architecture also defines some new top-level APIs.
*/
[uuid(15B51D8B-9BF6-11d1-B888-00C04FB9618A), local] interface ICallFrameAPIs {
HRESULT __stdcall CoGetInterceptor /*
Instantiate the appropriate interceptor for the indicated interface which is to be intercepted and return the newly created interceptor.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] REFIID iidIntercepted, /* the interface for which an interceptor is sought */
[in] IUnknown* punkOuter, /* controlling unknown, if any, with which the interceptor is to be
aggregated */
[in] REFIID iid, /* the IID desired on the interceptor */
[out] void** ppv /* place at which the interceptor is returned */
);
HRESULT __stdcall CoGetInterceptorFromTypeInfo /*
Instantiate the appropriate interceptor for the indicated interface which is to be intercepted and return the newly created interceptor.
The meta data for this interface is to be extracted from the provided typeinfo.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] REFIID iidIntercepted, /* the interface for which an interceptor is sought */
[in] IUnknown* punkOuter, /* controlling unknown, if any, with which the interceptor is to be
aggregated */
[in] ITypeInfo* typeInfo, /* an ITypeInfo describing iidIntercepted */
[in] REFIID iid, /* the IID desired on the interceptor */
[out] void** ppv /* place at which the interceptor is returned */
);
HRESULT __stdcall CoGetInterceptorForOle32 /*
Instantiate the appropriate interceptor for the indicated interface which is to be intercepted and return the newly created interceptor.
Return value Meaning
S_OK All is well
E_UNEXPECTED An unexpected error occurred. */
(
[in] REFIID iidIntercepted, /* the interface for which an interceptor is sought */
[in] IUnknown* punkOuter, /* controlling unknown, if any, with which the interceptor is to be
aggregated */
[in] REFIID iid, /* the IID desired on the interceptor */
[out] void** ppv /* place at which the interceptor is returned */
);
};
#if 0
RevisionHistory
1997-07-15 First draft for limited review.
1997-11-10 Added ICallIndirect; rearrange ICallInterceptor. Add pvDatumAux to ICallFrameWalker::OnWalkData.
1997-11-25 Significant minor edits and clarifications. Changed the way that return values are returned via a call frame.
Reordered the presentation of some of the interfaces. Made compilable.
1997-12-17 Tweaked ICallFrame::Copy. Changed policy of management of class ids.
1998-01-07 Added ICallIndirect::GetStackSize. Added ICallFrame::GetIIDAndMethod.
1998-01-15 Clarified user vs. kernel mode call frames; tweaked ICallFrame::Copyaccordingly. Added ICallFrame::Get-
StackLocation.Modified ICallFrame::Free to aid in copying out values back to parent call frames. Changed
SetReturnValue to work only for HRESULTs. Added some error code returns. Added HRESULT out-parameter
to ICallFarme::Invoke.
1998-01-21 Removed the funky lifetime management stuff from ICallFrame::Copy. Now it just returns you the new call
frame, period. Added explicit share-if-you can parameter.
1998-01-24 Removed the phReturnValue parameter to ICallFrame::Invoke. Instead, invoke will set the return value in the
call frame, retrievablewithGetReturnValue.ChangedICallFrame::Free's parent frameparameter tobe
ICallFrame* instead of void*.
1998-01-27 Separated the 'walker' variables to ICallFrame::Free.
1998-01-30 Removed ICallFrame::Unmarshal. Moved ReleaseMarshalData from ICallFrame to ICallUnmarshal.
1998-02-03 Added top-level APIs. Renamed IObjectMarshaller to IMarshallingManager; enhanced same interface. Restored
and fixed ICallFrame::Unmarshal.
1998-02-05 Added ibFirstRelease parameter to ReleaseMarshalData. Changed ICaFllrame::Freeto allow separate NULLing
of out vs. in-out parameters. Added ReleaseMarshalData to ICallFrame.
1998-02-19 Fix CoGetInterceptor's parameters.
1998-03-27 Extend IMarshallingManager.
1998-08-04 Add comments as to when walkers are called duringICallFrame::Free. Added ICallFrame::SetStackLocation.
Allowed retention of frames beyond the ICallFrameEvents::OnCallnotification. Added buffer management
control to ICallUnmarshal::Unmarshal.
1998-08-14 Separated freeing of data referenced by out-parameters from the freeing of the actual out pointer parameter
itself.
1998-08-26 Added third walker in Free case to free the in-out's in the parent frame. Changed OnWalkInterface to inform
as to directionality of interface in question. Removed OnWalkData method. Allowed more careful control in
ICallFrame::WalkFrame as to whether in-out vs. just plain in or just plain out interfaces are walked. Add in-out
information toCALLFRAMEINFO.Rearrangedmethodorder inICallFrame. AddedcParamsmember to
CALLFRAMEINFO; distinguished in-out information therein; renamed othermembers for clarity.Added
ICallFrame::GetParamInfomethod.AddedICallFrame::FreeParammethod.AddedICallFrame::SetParamand
ICallFrame::GetParam methods.
1998-09-15 SimplifyGetStackLocation,SetReturnValue,andGetReturnValuebasedonperformancemeasurements.
Enhanced CALLFRAMEINFO with cInInterfacesMax etc. Added ICallIndirect::GetInfo.
1998-10-1 Removeconfusingre-useofIMarshalinterface.DefineIMarshalSomeoneinstead.Enhance
CALLFRAME_MARSHALCONTEXT to include requested transfer syntax.
1998-11-13 Added interfaceandmethodnameretrievalmethods.ChangedIIDsofICallFrame,IllICandirect,and
ICallInterceptor.
1998-12-01 Added mechanism to indicate whether interface derives from IDispatch.
1999-02-05 Call CoGetInterceptorFromTypeInfo.
Index
ReleaseMarshalData...3 RegisterSink......8
Free..........4 GetRegisteredSink....8
C
SetReturnValue.....5 ICallUnmarshal..........9
CALLFRAME_COPY........6
GetReturnValue.....5 Unmarshal.......9
CALLFRAME_FREE........5
Invoke.........5 ReleaseMarshalData...9
CALLFRAME_MARSHALCONTEXT.2
Copy.........6 IInterfaceRelated.........10
CALLFRAME_NULL........5
WalkFrame.......6 SetIID........10
CoGetInterceptor.........11
ICallFrameEvents.........8 GetIID........10
OnCall.........8 IMarshallingManager.......10
ICallFrameWalker.........9 GetMarshallerFor...10
I
OnWalkInterface.....9 interceptor............1
ICallFrame............1
OnWalkData.....10
GetInfo........2
ICallIndirect
GetIIDAndMethod....2
U
CallIndirect.......7
GetStackLocation....2
user mode...........1, 6
GetStackSize......7
GetMarshalSizeMax...2
GetIID.........7
Marshal........3
ICallInterceptor..........8
Unmarshal.......3
#endif