I am told that our APIs are not part of our documentation.  :-(  I know for sure we documented these, but I'm told there is a documentation update coming soon, so they must only have made it into the update.  My apologies on behalf of Microsoft.  Keep an eye out for update notifications inside Platform Builder / Visual Studio.

In the meantime, to help you out, I am posting the comments from some of our code.  This is part of %_WINCEROOT%\private\winceos\coreos\core\thunks which does not appear to be part of our shared source.  :-(

//

// Access-checks and marshals a buffer pointer from the source process, so

// that it may be accessed by the current process.  Returns the marshalled

// pointer.  This function allocates resources which must be freed by a

// subsequent call to CeCloseCallerBuffer.

//

// Duplication prevents asynchronous modification of the buffer by the caller.

// If duplication is not required for security purposes, don't use it.  Then

// CeOpenCallerBuffer can select the most efficient marshalling method for

// best performance.

//

// If duplication is required, allocates a new heap buffer, copies data from the

// source buffer to the heap buffer [if necessary due to "in" descriptors

// ARG_I* or ARG_IO*], and returns the new heap buffer.  If duplication is not

// required, CeOpenCallerBuffer may still duplicate the buffer, or it may

// allocate virtual address space in the current process (VirtualAlloc) and

// point it at the caller process' memory (VirtualCopy) to create an alias to

// the same memory.  In all cases, any required write-back to the source buffer

// will be managed by CeCloseCallerBuffer [if necessary due to "out" descriptors

// ARG_IO* or ARG_O*].

//

// This call uses ReadProcessMemory and WriteProcessMemory to do its work.  If

// your code is running at a low enough privilege level that it does not have

// access to those APIs, this call will fail with E_ACCESSDENIED.

//

// Does not allocate any resources if the call fails, or if the source buffer

// was NULL.  If this call fails for any reason, the pointer returned in

// *ppDestMarshalled is NULL.

//

// This function opens the caller buffer for synchronous access during an API

// call.  You must call CeAllocAsynchronousBuffer in order to use the buffer

// returned by CeOpenCallerBuffer asynchronously.  Do not close the caller

// buffer until after you have called CeFreeAsynchronousBuffer.

//

// This function is protected by __try/__except so as not to throw an exception

// while accessing the input pointer pSrcUnmarshalled.

//

// Possible return values:

// E_INVALIDARG    pSrcUnmarshalled was NULL, the length was 0, or some other

//                 argument was invalid.

// E_ACCESSDENIED  The source buffer was an invalid address, or your code does

//                 not have sufficient privilege to access the memory.

// E_OUTOFMEMORY   The memory allocation failed.

// S_OK            The allocation (and duplication, if necessary) succeeded.

//

// It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test

// the return value of this function.

//

HRESULT

CeOpenCallerBuffer(

    PVOID* ppDestMarshalled,        // Receives a pointer that the current

                                    // process can use to access the buffer

                                    // synchronously.

    PVOID  pSrcUnmarshalled,        // Pointer to the caller's data,

                                    // to be access checked, marshalled, and

                                    // possibly duplicated.

    DWORD  cbSrc,                   // Size of the caller's buffer, in bytes.

                                    // If the ArgumentDescriptor is a WSTR

                                    // or ASTR, then a size of 0 can be used.

                                    // If the size of a string is non-zero, then

                                    // it must include the terminating NULL.

    DWORD  ArgumentDescriptor,      // Descriptor explaining what kind of API

                                    // argument the buffer is, eg. ARG_I_WSTR,

                                    // ARG_O_PTR, etc. ARG_DW is NOT a valid

                                    // descriptor for marshalling!

    BOOL   ForceDuplicate           // Set to TRUE to require a temporary heap

                                    // buffer to be allocated in the current

                                    // process.  Set to FALSE to allow

                                    // CeOpenCallerBuffer to select the most

                                    // efficient marshalling method.

    )

 

 

//

// Frees any resources that were allocated by CeOpenCallerBuffer.

// Performs any required write-back to the caller buffer.  (Due to "out"

// descriptors ARG_IO* or ARG_O*)

//

// This function is protected by __try/__except so as not to throw an exception

// while accessing the input pointer pSrcUnmarshalled.

//

// Possible return values:

// E_INVALIDARG    pSrcUnmarshalled was NULL, the length was 0, or some other

//                 argument was invalid.

// E_ACCESSDENIED  Required write-back could not be performed.  If this error

//                 occurs, resources are still released and the marshalled

//                 pointer is no longer accessible.

// S_OK            The free succeeded.

//

// It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test

// the return value of this function.

//

HRESULT

CeCloseCallerBuffer(

    PVOID  pDestMarshalled,     // Pointer to the buffer that was allocated by

                                // CeOpenCallerBuffer.

    PVOID  pSrcUnmarshalled,    // The source pointer that was passed to

                                // CeOpenCallerBuffer.

    DWORD  cbSrc,               // The buffer size that was passed to

                                // CeOpenCallerBuffer.

    DWORD  ArgumentDescriptor   // The descriptor that was passed to

                                // CeOpenCallerBuffer.

    )

 

 

//

// Re-marshals a buffer that was already marshalled by CeOpenCallerBuffer, so

// that the server can use it asynchronously after the API call has returned.

// Call this function synchronously before your API call returns.  You can not

// call this function asynchronously.  This function allocates resources which

// must be freed by a subsequent call to CeFreeAsynchronousBuffer.

//

// API parameter access (KERNEL MODE ONLY):

//   You can use CeAllocAsynchronousBuffer to get asynchronous access to an API

//   parameter (which would have already been marshalled by the kernel).

//   However if there is any chance that your code will run in user mode, then

//   don't do this.  Instead follow the user mode instructions below.

// API parameter access (USER MODE):

//   To access an API parameter asynchronously, define the API function

//   signature so that the parameter is declared as an ARG_DW value, so that

//   the kernel does not automatically marshal the parameter for you.  Then call

//   CeOpenCallerBuffer to marshal the parameter.  The asynchronous buffer will

//   become inaccessible if you close the marshaled buffer by calling

//   CeCloseCallerBuffer, so you should call CeFreeAsynchronousBuffer before

//   calling CeCloseCallerBuffer.  In other words, do not call

//   CeCloseCallerBuffer until after you have called CeFreeAsynchronousBuffer.

//

// CeAllocAsynchronousBuffer is not required for buffers that have been

// duplicated by CeAllocDuplicateBuffer.  You do not need to do anything in

// order to use those buffers asynchronously.  Those buffers can be used until

// they are closed/freed.  But if you choose to call CeAllocAsynchronousBuffer

// on a duplicated buffer, it will work.  In that case you must not call

// CeFreeDuplicateBuffer until after you have called CeFreeAsynchronousBuffer.

//

// Does not allocate any resources if the call fails, or if the source buffer

// was NULL.  If duplication is required but no memory is allocated, the pointer

// returned by CeFreeAsynchronousBuffer is NULL.

//

// This function is protected by __try/__except so as not to throw an exception

// while accessing the input pointer pSrcSyncMarshalled.

//

// Possible return values:

// E_INVALIDARG    pSrcUnmarshalled was NULL, or the length was 0.

// E_ACCESSDENIED  The source buffer was an invalid address.

// E_OUTOFMEMORY   The memory allocation failed.

// S_OK            The allocation (and duplication, if necessary) succeeded.

//

// It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test

// the return value of this function.

//

HRESULT

CeAllocAsynchronousBuffer(

    PVOID* ppDestAsyncMarshalled,   // Receives a pointer that the current

                                    // process can use to access the buffer

                                    // asynchronously.

    PVOID  pSrcSyncMarshalled,      // Pointer to the buffer that has already

                                    // been marshalled for synchronous access

                                    // by the current process.

    DWORD  cbSrc,                   // Size of the marshalled buffer, in bytes.

                                    // If the ArgumentDescriptor is a WSTR

                                    // or ASTR, then a size of 0 can be used.

                                    // If the size of a string is non-zero, then

                                    // it must include the terminating NULL.

    DWORD  ArgumentDescriptor       // Descriptor explaining what kind of API

                                    // argument the buffer is, eg. ARG_I_WSTR,

                                    // ARG_O_PTR, etc. ARG_DW is NOT a valid

                                    // descriptor for marshalling!

    )

 

 

//

// Frees any resources that were allocated by CeAllocAsynchronousBuffer.

// Performs any required write-back to the source buffer.  (Due to "out"

// descriptors ARG_IO* or ARG_O*)

//

// This function is protected by __try/__except so as not to throw an exception

// while accessing the input pointer pSrcSyncMarshalled.

//

// Possible return values:

// E_FAIL          Required write-back could not be performed.  If this error

//                 occurs, resources are still released and the marshalled

//                 pointer is no longer accessible.

// S_OK            The allocation (and duplication, if necessary) succeeded.

//

// It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test

// the return value of this function.

//

HRESULT

CeFreeAsynchronousBuffer(

    PVOID  pDestAsyncMarshalled,// Pointer to the buffer that was allocated by

                                // CeAllocAsynchronousBuffer.

    PVOID  pSrcSyncMarshalled,  // The source pointer that was passed to

                                // CeAllocAsynchronousBuffer.

    DWORD  cbSrc,               // The buffer size that was passed to

                                // CeAllocAsynchronousBuffer.

    DWORD  ArgumentDescriptor   // The descriptor that was passed to

                                // CeAllocAsynchronousBuffer.

    )

 

 

//

// Flushes any changed data between source and destination buffer allocated by

// CeAllocAsynchronousBuffer.

// ARG_O_PTR:   Writes back data from asynchronous buffer into source buffer.

// ARG_IO_PTR:  Writes back data from asynchronous buffer into source buffer.

//              Does NOT read from source buffer.

// Others:      Fail with ERROR_NOT_SUPPORTED

//

// This function is protected by __try/__except so as not to throw an exception

// while accessing the input pointer pSrcSyncMarshalled.

//

// Possible return values:

// E_FAIL          Required read or write-back could not be performed.

// S_OK            The read or write succeeded.

//

// It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test

// the return value of this function.

//

HRESULT

CeFlushAsynchronousBuffer(

    PVOID  pDestAsyncMarshalled,// Pointer to the buffer that was allocated by

                                // CeAllocAsynchronousBuffer.

    PVOID  pSrcSyncMarshalled,  // The source pointer that was passed to

                                // CeAllocAsynchronousBuffer.

    PVOID  pSrcUnmarshalled,    // The source pointer that was passed to

                                // CeOpenCallerBuffer, or NULL if the buffer

                                // was an API parameter than never came from

                                // CeOpenCallerBuffer (kernel mode only).

    DWORD  cbSrc,               // The buffer size that was passed to

                                // CeAllocAsynchronousBuffer.

    DWORD  ArgumentDescriptor   // The descriptor that was passed to

                                // CeAllocAsynchronousBuffer.

    )

 

 

//

// This function abstracts the work required to make secure-copies of API

// arguments.  Don't use it for buffers other than API arguments.  Don't

// expect the duplicated buffer to be accessible after the API call returns.

//

// Allocates a new heap buffer, copies data from the source buffer to the heap

// buffer [if necessary due to "in" descriptors ARG_I* or ARG_IO*], and returns

// the new heap buffer.  This function allocates resources which must be freed

// by a subsequent call to CeFreeDuplicateBuffer.  Any required write-back to

// the source buffer will be managed by CeFreeDuplicateBuffer [if necessary due

// to "out" descriptors ARG_IO* or ARG_O*].

//

// Duplication prevents asynchronous modification of the buffer by the caller.

// If duplication is not required for security purposes, don't use it.  Just

// access the caller's buffer as passed to your API.

//

// Does not allocate any memory if the call fails, or if the source buffer was

// NULL.  If no memory is allocated, the pointer returned in *ppDestDuplicate

// is NULL.

//

// Do not use CeAllocDuplicateBuffer with a buffer marshalled by

// CeOpenCallerBuffer.  Instead have CeOpenCallerBuffer do the duplication.

//

// You do not need to call CeAllocAsynchronousBuffer in order to use the buffer

// returned by CeAllocDuplicateBuffer asynchronously.  The duplicate buffer can

// be used until it is closed by CeCloseCallerBuffer.  CeAllocAsynchronousBuffer

// will not work on buffers that have been duplicated by CeAllocDuplicateBuffer.

//

// This function is protected by __try/__except so as not to throw an exception

// while accessing the input pointer pSrcMarshalled.

//

// Possible return values:

// E_INVALIDARG    pSrcMarshalled was NULL, or the length was 0.

// E_ACCESSDENIED  The source buffer was an invalid address, possibly a pointer

//                 that has not been marshalled.

// E_OUTOFMEMORY   The memory allocation failed.

// S_OK            The allocation and copy succeeded.

//

// It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test

// the return value of this function.

//

HRESULT

CeAllocDuplicateBuffer(

    PVOID* ppDestDuplicate,     // Receives a pointer to a newly-allocated heap

                                // buffer.

    PVOID  pSrcMarshalled,      // Pointer to the caller's data, that has

                                // already been marshalled.

    DWORD  cbSrc,               // Size of the caller's buffer, in bytes.

                                // If the ArgumentDescriptor is a WSTR

                                // or ASTR, then a size of 0 can be used.

                                // If the size of a string is non-zero, then

                                // it must include the terminating NULL.

    DWORD  ArgumentDescriptor   // Descriptor explaining what kind of API

                                // argument the buffer is, eg. ARG_I_WSTR,

                                // ARG_O_PTR, etc. ARG_DW is NOT a valid

                                // descriptor for duplicating!

    )

 

 

//

// Frees a duplicate buffer that was allocated by CeAllocDuplicateBuffer.

// Performs any required write-back to the source buffer.  (Due to "out"

// descriptors ARG_IO* or ARG_O*)

//

// This function is protected by __try/__except so as not to throw an exception

// while accessing the input pointer pSrcMarshalled.

//

// Possible return values:

// E_FAIL          Required write-back could not be performed.  If this error

//                 occurs, resources are still released and the duplicated

//                 pointer is no longer accessible.

// S_OK            The free (and write-back, if necessary) succeeded.

//

// It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test

// the return value of this function.

//

HRESULT

CeFreeDuplicateBuffer(

    PVOID  pDestDuplicate,      // Pointer to the buffer that was allocated by

                                // CeAllocDuplicateBuffer.

    PVOID  pSrcMarshalled,      // The source pointer that was passed to

                                // CeAllocDuplicateBuffer.

    DWORD  cbSrc,               // The buffer size that was passed to

                                // CeAllocDuplicateBuffer.

    DWORD  ArgumentDescriptor   // The descriptor that was passed to

                                // CeAllocDuplicateBuffer.

    )

 

And here are the C++ classes from %_WINCEROOT%\public\common\oak\inc\marshal.hpp:

// This class is a wrapper for CeOpenCallerBuffer / CeCloseCallerBuffer and

// CeAllocAsynchronousBuffer / CeFreeAsynchronousBuffer.

// You should only use it with embedded pointers that have NOT already been

// access-checked or marshalled by the kernel.  To duplicate a buffer that has

// already been marshalled, use DuplicatedBuffer_t.  To gain asynchronous

// access to a buffer that has already been marshalled, use AsynchronousBuffer_t.

class MarshalledBuffer_t {

public:

 

    //

    // Access-checks and marshals a buffer pointer from the source process, so

    // that it may be accessed by the current process.  Exposes the marshalled

    // pointer via the ptr() accessor.  Any allocated resources related to the

    // marshalling are freed only by a subsequent call to Unmarshal(), or by the

    // destructor.

    //

    // Typically, you would either use the default constructor plus Marshal()

    // to marshal the buffer, or you would use the marshalling constructor to

    // accomplish the same task.  Use the former method if you require an

    // HRESULT.  Similarly, you can allow the destructor to release marshalling

    // resources, or use Unmarshal().  If an HRESULT is required, use the

    // Unmarshal function.

    //

 

    MarshalledBuffer_t();

    ~MarshalledBuffer_t();

 

    // Please see the description of CeOpenCallerBuffer and

    // CeAllocAsynchronousBuffer for more information about the operation of

    // this function.

    //

    // If marshalling fails, ptr() will return NULL and size() will return zero.

    // Otherwise the marshalled buffer will be accessible via ptr() and size().

    MarshalledBuffer_t(

        PVOID pSrcUnmarshalled,

        DWORD cbSrc,

        DWORD ArgumentDescriptor,

        BOOL  ForceDuplicate = TRUE,

        BOOL  Asynchronous = FALSE

        );

 

    // Takes a const pSrcUnmarshalled, can only be used with ARG_I_* types

    MarshalledBuffer_t(

        PCVOID pSrcUnmarshalled,

        DWORD cbSrc,

        DWORD ArgumentDescriptor,

        BOOL  ForceDuplicate = TRUE,

        BOOL  Asynchronous = FALSE

        );

   

    // Please see the description of CeOpenCallerBuffer and

    // CeAllocAsynchronousBuffer for more information about the operation of

    // this function.

    //

    // Once a MarshalledBuffer is marshalled (using the marshalling constructor

    // or the Marshal() method, it cannot be re-used by calling Marshal(), until

    // after Unmarshal() is called.  An attempt to do so will return

    // ERROR_ALREADY_EXISTS.

    //

    // If Marshal() fails, ptr() will return NULL and size() will return zero.

    // Otherwise the marshalled buffer will be accessible via ptr() and size().

    HRESULT

    Marshal(

        PVOID pSrcUnmarshalled,

        DWORD cbSrc,

        DWORD ArgumentDescriptor,

        BOOL  ForceDuplicate = TRUE,

        BOOL  Asynchronous = FALSE

        );

 

    // Takes a const pSrcUnmarshalled, can only be used with ARG_I_* types

    HRESULT

    Marshal(

        PCVOID pSrcUnmarshalled,

        DWORD cbSrc,

        DWORD ArgumentDescriptor,

        BOOL  ForceDuplicate = TRUE,

        BOOL  Asynchronous = FALSE

        );

   

    // Please see the description of CeFlushAsynchronousBuffer for more

    // information about the operation of this function.

    //

    // If the buffer has already been unmarshalled, or if it is not an

    // asynchronous buffer, Flush will fail with ERROR_INVALID_PARAMETER.

    HRESULT Flush();

 

    // Please see the description of CeCloseCallerBuffer for more information

    // about the operation of this function.

    //

    // If the buffer has already been unmarshalled, Unmarshal will fail with

    // ERROR_ALREADY_EXISTS.

    HRESULT Unmarshal();

 

    // Returns a pointer to the marshalled buffer, or NULL if the buffer

    // has not been marshalled or has already been unmarshalled.

    LPVOID ptr() const;

 

    // Returns the size of the marshalled buffer, or zero if the buffer

    // has not been marshalled or has already been unmarshalled.

    DWORD size() const;

};

 

 

 

class DuplicatedBuffer_t;

// This class is a wrapper for CeAllocDuplicateBuffer / CeFreeDuplicateBuffer.

// It should only be called with API arguments that have already been

// access-checked and automatically marshalled (if necessary) by the kernel.

// All other duplication can be done by MarshalledBuffer_t.

//

// You can either call the constructor to do the duplication, or use

// the default constructor and then duplicate using the Allocate() method.

// If an HRESULT is required, use Allocate().  Similarly, you can allow the

// destructor to release the duplicate memory, or use the Free() method.  If

// an HRESULT is required, use Free().

//

// If Allocate() fails, ptr() will return NULL and size() will return zero.

// Otherwise the duplicated buffer will be accessible via ptr() and size().

//

// Once a DuplicatedBuffer is allocated (using the constructor or the

// Allocate() method), it cannot be re-used by calling Allocate(), until

// after Free() is called.  An attempt to do so will return

// ERROR_ALREADY_EXISTS.

//

// If the buffer is not currently allocated, Free() will fail with

// ERROR_ALREADY_EXISTS.

//

// Please see the description of CeAllocDuplicateBuffer and

// CeFreeDuplicateBuffer for more information about the operation of

// the Allocate() and Free() methods.

//

// Public methods are:

//      DuplicatedBuffer_t();

//      DuplicatedBuffer_t(PVOID  pSrcMarshalled, DWORD cbSrc, DWORD ArgumentDescriptor);

//      DuplicatedBuffer_t(PCVOID pSrcMarshalled, DWORD cbSrc, DWORD ArgumentDescriptor);

//      ~DuplicatedBuffer_t();

//

//      HRESULT Free();

//      HRESULT Allocate(PVOID  pSrcMarshalled, DWORD cbSrc, DWORD ArgumentDescriptor);

//      HRESULT Allocate(PCVOID pSrcMarshalled, DWORD cbSrc, DWORD ArgumentDescriptor);

//

//      LPVOID ptr() const;

//      DWORD size() const;

 

 

class AsynchronousBuffer_t;

// This class is a wrapper for CeAllocAsynchronousBuffer /

// CeFreeAsynchronousBuffer.  It is meant to be used with pointers

// already access-checked or marshalled by the kernel that require

// asynchronous buffer access.  It should ONLY be used in kernel mode!

// See the description of CeAllocAsynchronousBuffer for information on how to

// access a buffer asynchronously in user mode.

//

// You can either call the constructor to allocate the async buffer, or use

// the default constructor and then use the Allocate() method.

// If an HRESULT is required, use Allocate().  Similarly, you can allow the

// destructor to release the async buffer, or use the Free() method.  If

// an HRESULT is required, use Free().

//

// If Allocate() fails, ptr() will return NULL and size() will return zero.

// Otherwise the async buffer will be accessible via ptr() and size().

//

// Once an AsynchronousBuffer is allocated (using the constructor or the

// Allocate() method), it cannot be re-used by calling Allocate(), until

// after Free() is called.  An attempt to do so will return

// ERROR_ALREADY_EXISTS.

//

// If the buffer is not currently allocated, Free() will fail with

// ERROR_ALREADY_EXISTS.

//

// Please see the description of CeAllocAsynchronousBuffer and

// CeFreeAsynchronousBuffer for more information about the operation of

// the Allocate() and Free() methods.

//

// Public methods are:

//      AsynchronousBuffer_t();

//      AsynchronousBuffer_t(PVOID  pSrcMarshalled, DWORD cbSrc, DWORD ArgumentDescriptor);

//      AsynchronousBuffer_t(PCVOID pSrcMarshalled, DWORD cbSrc, DWORD ArgumentDescriptor);

//      ~AsynchronousBuffer_t();

//

//      HRESULT Free();

//      HRESULT Allocate(PVOID  pSrcMarshalled, DWORD cbSrc, DWORD ArgumentDescriptor);

//      HRESULT Allocate(PCVOID pSrcMarshalled, DWORD cbSrc, DWORD ArgumentDescriptor);

//      HRESULT Flush();

//

//      LPVOID ptr() const;

//      DWORD size() const;

Also see %_WINCEROOT%\public\common\oak\inc\pkfuncs.h for the ARG_* values to pass as an ArgumentDescriptor:

ARG_I_PTR           // input only pointer, size in the next argument

ARG_I_WSTR          // input only, unicode string

ARG_I_ASTR          // input only, ascii string

ARG_I_PDW           // input only, ptr to DWORD

 

ARG_O_PTR           // output only pointer, size in the next argument

ARG_O_PDW           // output only, pointer to DWORD

ARG_O_PI64          // output only, pointer to 64 bit value

 

ARG_IO_PTR          // I/O pointer, size in the next argument

ARG_IO_PDW          // I/O pointer to DWORD

ARG_IO_PI64         // I/O pointer to 64 bit value