/*++

Microsoft Windows
Copyright (c) 1994-2000 Microsoft Corporation.  All rights reserved.

Module Name:
    proxy.c

Abstract:
    Implements the IRpcProxyBuffer interface.

Author:
    ShannonC    12-Oct-1994

Environment:
    Windows NT and Windows 95 and PowerMac.
    We do not support DOS, Win16 and Mac.

Revision History:

--*/

#define USE_STUBLESS_PROXY
#define CINTERFACE

#include <ndrp.h>
#include <ndrole.h>
#include <rpcproxy.h>
#include <stddef.h>

CStdProxyBuffer * RPC_ENTRY
NdrGetProxyBuffer(
    void *pThis);

const IID * RPC_ENTRY
NdrGetProxyIID(
    const void *pThis);

ULONG STDMETHODCALLTYPE
CStdProxyBuffer_Release(
    IN  IRpcProxyBuffer *This);

ULONG STDMETHODCALLTYPE
CStdProxyBuffer2_Release(
    IN  IRpcProxyBuffer *This);

BOOL NdrpFindInterface(
    IN  const ProxyFileInfo **  pProxyFileList, 
    IN  REFIID                  riid,
    OUT const ProxyFileInfo **  ppProxyFileInfo,
    OUT long *                  pIndex );


// The channel wrapper
//

typedef struct tagChannelWrapper
{
    const IRpcChannelBufferVtbl *lpVtbl;
    long                         RefCount;
    const IID *                  pIID;
    struct IRpcChannelBuffer *   pChannel;
} ChannelWrapper;


HRESULT STDMETHODCALLTYPE
CreateChannelWrapper
(
    const IID *          pIID,
    IRpcChannelBuffer *  pChannel,
    IRpcChannelBuffer ** pChannelWrapper
);

HRESULT STDMETHODCALLTYPE
CreateAsyncChannelWrapper
(
    const IID *          pIID,
    IRpcChannelBuffer *  pChannel,
    IRpcChannelBuffer ** pChannelWrapper
);

HRESULT STDMETHODCALLTYPE
ChannelWrapper_QueryInterface
(
    IRpcChannelBuffer3 * This,
    REFIID               riid,
    void **              ppvObject
);

ULONG STDMETHODCALLTYPE
ChannelWrapper_AddRef
(
    IRpcChannelBuffer3 * This
);

ULONG STDMETHODCALLTYPE
ChannelWrapper_Release
(
    IRpcChannelBuffer3 * This
);

HRESULT STDMETHODCALLTYPE
ChannelWrapper_GetBuffer
(
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage,
    REFIID              riid
);

HRESULT STDMETHODCALLTYPE
ChannelWrapper_SendReceive
(
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage,
    ULONG *             pStatus
);

HRESULT STDMETHODCALLTYPE
ChannelWrapper_FreeBuffer
(
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage
);

HRESULT STDMETHODCALLTYPE
ChannelWrapper_GetDestCtx
(
    IRpcChannelBuffer3 * This,
    DWORD *             pdwDestContext,
    void **             ppvDestContext
);

HRESULT STDMETHODCALLTYPE
ChannelWrapper_IsConnected
(
    IRpcChannelBuffer3 * This
);

HRESULT STDMETHODCALLTYPE
ChannelWrapper_GetProtocolVersion
(
    IRpcChannelBuffer3 * This,
    DWORD             * pdwVersion
);

HRESULT STDMETHODCALLTYPE
ChannelWrapper_Send(
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage,
    ULONG *             pStatus
    );

HRESULT STDMETHODCALLTYPE
ChannelWrapper_Receive(
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage,
    ULONG               ulSize,
    ULONG *             pStatus
    );

HRESULT STDMETHODCALLTYPE
ChannelWrapper_Cancel(
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage
    );

HRESULT STDMETHODCALLTYPE
ChannelWrapper_GetCallContext(
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage,
    REFIID              riid,
    void    **          pInterface
    );

HRESULT STDMETHODCALLTYPE
ChannelWrapper_GetDestCtxEx(
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage,
    DWORD *             pdwDestContext,
    void **             ppvDestContext
    );

HRESULT STDMETHODCALLTYPE
ChannelWrapper_GetState(
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage,
    DWORD         *     pState
    );

HRESULT STDMETHODCALLTYPE
ChannelWrapper_RegisterAsync(
    IRpcChannelBuffer3 *    This,
    RPCOLEMESSAGE *         pMessage,
    IAsyncManager *         pAsyncMgr
    );



HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_QueryInterface
(
    IAsyncRpcChannelBuffer  *   This,
    REFIID                      riid,
    void **                     ppvObject
);

ULONG STDMETHODCALLTYPE
AsyncChannelWrapper_AddRef
(
    IAsyncRpcChannelBuffer  *   This
);

ULONG STDMETHODCALLTYPE
AsyncChannelWrapper_Release
(
    IAsyncRpcChannelBuffer  *   This
);

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_GetBuffer
(
    IAsyncRpcChannelBuffer  *   This,
    RPCOLEMESSAGE *             pMessage,
    REFIID                      riid
);

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_SendReceive
(
    IAsyncRpcChannelBuffer  *   This,
    RPCOLEMESSAGE *             pMessage,
    ULONG *                     pStatus
);

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_FreeBuffer
(
    IAsyncRpcChannelBuffer  *   This,
    RPCOLEMESSAGE *             pMessage
);

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_GetDestCtx
(
    IAsyncRpcChannelBuffer  *   This,
    DWORD *                     pdwDestContext,
    void **                     ppvDestContext
);

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_IsConnected
(
    IAsyncRpcChannelBuffer  *   This
);

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_GetProtocolVersion
(
    IAsyncRpcChannelBuffer  *   This,
    DWORD                   *   pdwVersion
);

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_Send(
    IAsyncRpcChannelBuffer  *   This,
    RPCOLEMESSAGE *             pMessage,
    ISynchronize *              pSynchronize,
    ULONG *                     pStatus
    );

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_Receive(
    IAsyncRpcChannelBuffer  *   This,
    RPCOLEMESSAGE *             pMessage,
    ULONG *                     pStatus
    );

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_GetDestCtxEx
(
    IAsyncRpcChannelBuffer  *   This,
    RPCOLEMESSAGE *             pMessage,
    DWORD *                     pdwDestContext,
    void **                     ppvDestContext
);


//+-------------------------------------------------------------------------
//
//  Global data
//
//--------------------------------------------------------------------------

// ProxyBuffer vtables for non-delegaed and delegated case.

extern const IRpcProxyBufferVtbl CStdProxyBufferVtbl = {
    CStdProxyBuffer_QueryInterface,
    CStdProxyBuffer_AddRef,
    CStdProxyBuffer_Release,
    CStdProxyBuffer_Connect,
    CStdProxyBuffer_Disconnect };

extern const IRpcProxyBufferVtbl CStdProxyBuffer2Vtbl = {
    CStdProxyBuffer_QueryInterface,
    CStdProxyBuffer_AddRef,
    CStdProxyBuffer2_Release,
    CStdProxyBuffer2_Connect,
    CStdProxyBuffer2_Disconnect };

// ICallFactory interface on the ProxyBuffer objects.
// ICallFactory is an interface on a sync proxy only.
// It has been introduced for NT5 beta2.

extern const ICallFactoryVtbl CStdProxyBuffer_CallFactoryVtbl = {
    CStdProxyBuffer_CF_QueryInterface,
    CStdProxyBuffer_CF_AddRef,
    CStdProxyBuffer_CF_Release,
    CStdProxyBuffer_CF_CreateCall };

extern const ICallFactoryVtbl CStdProxyBuffer2_CallFactoryVtbl = {
    CStdProxyBuffer_CF_QueryInterface,
    CStdProxyBuffer_CF_AddRef,
    CStdProxyBuffer_CF_Release,
    CStdProxyBuffer2_CF_CreateCall };

extern const IReleaseMarshalBuffersVtbl CStdProxyBuffer_ReleaseMarshalBuffersVtbl = {
    CStdProxyBuffer_RMB_QueryInterface,
    CStdProxyBuffer_RMB_AddRef,
    CStdProxyBuffer_RMB_Release,
    CStdProxyBuffer_RMB_ReleaseMarshalBuffer };

extern const IReleaseMarshalBuffersVtbl CStdAsyncProxyBuffer_ReleaseMarshalBuffersVtbl = {
    CStdProxyBuffer_RMB_QueryInterface,
    CStdProxyBuffer_RMB_AddRef,
    CStdProxyBuffer_RMB_Release,
    CStdAsyncProxyBuffer_RMB_ReleaseMarshalBuffer };

// Async proxy buffer vtables

extern const IRpcProxyBufferVtbl CStdAsyncProxyBufferVtbl = {
    CStdAsyncProxyBuffer_QueryInterface,
    CStdProxyBuffer_AddRef,
    CStdAsyncProxyBuffer_Release,
    CStdAsyncProxyBuffer_Connect,
    CStdProxyBuffer_Disconnect };

extern const IRpcProxyBufferVtbl CStdAsyncProxyBuffer2Vtbl = {
    CStdAsyncProxyBuffer_QueryInterface,
    CStdProxyBuffer_AddRef,
    CStdAsyncProxyBuffer2_Release,
    CStdAsyncProxyBuffer2_Connect,
    CStdProxyBuffer2_Disconnect };

// Channel wrapper is used for delegetion only.


extern const IRpcChannelBuffer3Vtbl ChannelWrapperVtbl = {
    ChannelWrapper_QueryInterface,
    ChannelWrapper_AddRef,
    ChannelWrapper_Release,
    ChannelWrapper_GetBuffer,
    ChannelWrapper_SendReceive,
    ChannelWrapper_FreeBuffer,
    ChannelWrapper_GetDestCtx,
    ChannelWrapper_IsConnected,
    ChannelWrapper_GetProtocolVersion,
    ChannelWrapper_Send,
    ChannelWrapper_Receive,
    ChannelWrapper_Cancel,
    ChannelWrapper_GetCallContext,
    ChannelWrapper_GetDestCtxEx,
    ChannelWrapper_GetState,
    ChannelWrapper_RegisterAsync
    };

extern const IAsyncRpcChannelBufferVtbl AsyncChannelWrapperVtbl = {
    AsyncChannelWrapper_QueryInterface,
    AsyncChannelWrapper_AddRef,
    AsyncChannelWrapper_Release,
    AsyncChannelWrapper_GetBuffer,
    AsyncChannelWrapper_SendReceive,
    AsyncChannelWrapper_FreeBuffer,
    AsyncChannelWrapper_GetDestCtx,
    AsyncChannelWrapper_IsConnected,
    AsyncChannelWrapper_GetProtocolVersion,
    AsyncChannelWrapper_Send,
    AsyncChannelWrapper_Receive,
    AsyncChannelWrapper_GetDestCtxEx
    };

//+-------------------------------------------------------------------------
//
//  End of Global data
//
//--------------------------------------------------------------------------


#pragma code_seg(".orpc")

// __inline
CStdProxyBuffer * RPC_ENTRY
NdrGetProxyBuffer(
    IN  void *pThis)
/*++

Routine Description:
    The "this" pointer points to the pProxyVtbl field in the
    CStdProxyBuffer structure.  The NdrGetProxyBuffer function
    returns a pointer to the top of the CStdProxyBuffer
    structure.

Arguments:
    pThis - Supplies a pointer to the interface proxy.

Return Value:
    This function returns a pointer to the proxy buffer.

--*/
{
    unsigned char *pTemp;

    pTemp = (unsigned char *) pThis;
    pTemp -= offsetof(CStdProxyBuffer, pProxyVtbl);

    return (CStdProxyBuffer *)pTemp;
}

//__inline
const IID * RPC_ENTRY
NdrGetProxyIID(
    IN  const void *pThis)
/*++

Routine Description:
    The NDRGetProxyIID function returns a pointer to IID.

Arguments:
    pThis - Supplies a pointer to the interface proxy.

Return Value:
    This function returns a pointer to the IID.

--*/
{
    unsigned char **    ppTemp;
    unsigned char *     pTemp;
    CInterfaceProxyVtbl *pProxyVtbl;

    //Get a pointer to the proxy vtbl.
    ppTemp = (unsigned char **) pThis;
    pTemp = *ppTemp;
    pTemp -= sizeof(CInterfaceProxyHeader);
    pProxyVtbl = (CInterfaceProxyVtbl *) pTemp;

    return pProxyVtbl->header.piid;
}


HRESULT STDMETHODCALLTYPE
CStdProxyBuffer_QueryInterface(
    IN  IRpcProxyBuffer *   This,
    IN  REFIID              riid,
    OUT void **             ppv)
/*++

Routine Description:
    Query for an interface on the proxy.  This function provides access
    to both internal and external interfaces.

Arguments:
    riid - Supplies the IID of the requested interface.
        ppv  - Returns a pointer to the requested interface.

Return Value:
    S_OK
        E_NOINTERFACE

--*/
{
    CStdProxyBuffer   * pCThis  = (CStdProxyBuffer *) This;
    HRESULT             hr = E_NOINTERFACE;
    const IID *         pIID;

    *ppv = 0;

    if( (memcmp(&riid, &IID_IUnknown, sizeof(IID)) == 0) ||
        (memcmp(&riid, &IID_IRpcProxyBuffer, sizeof(IID)) == 0) )
    {
        //This is an internal interface. Increment the internal reference count.
        InterlockedIncrement( &pCThis->RefCount);
        *ppv = This;
        hr = S_OK;
        return hr;   
    }
    else if ( pCThis->pCallFactoryVtbl != 0  && 
              memcmp(&riid, &IID_ICallFactory, sizeof(IID)) == 0 )
        {
        // This is an exposed interface so go through punkOuter ot addref.
        pCThis->punkOuter->lpVtbl->AddRef(pCThis->punkOuter);

        *ppv = (void *) & pCThis->pCallFactoryVtbl;
        hr = S_OK;
        return hr;
        }
    else if ( pCThis->pRMBVtbl && 
              (memcmp(&riid, &IID_IReleaseMarshalBuffers,sizeof(IID)) == 0))
    {
        InterlockedIncrement( &pCThis->RefCount);

        *ppv = (void *) & pCThis->pRMBVtbl;
        hr = S_OK;
        return hr;
    }

    pIID = NdrGetProxyIID(&pCThis->pProxyVtbl);

    if( memcmp(&riid, pIID, sizeof(IID)) == 0)
    {
        //Increment the reference count.

        pCThis->punkOuter->lpVtbl->AddRef(pCThis->punkOuter);
        *ppv = (void *) &pCThis->pProxyVtbl;
        hr = S_OK;
    }

    return hr;
};


HRESULT STDMETHODCALLTYPE
CStdAsyncProxyBuffer_QueryInterface(
    IN  IRpcProxyBuffer *   This,
    IN  REFIID              riid,
    OUT void **             ppv)
/*++

Routine Description:
    Query for an interface on the proxy.  This function provides access
    to both internal and external interfaces.
    
Used for
    CStdAsyncProxyBuffer2 as well.

Arguments:
    riid - Supplies the IID of the requested interface.
        ppv  - Returns a pointer to the requested interface.

Return Value:
    S_OK
        E_NOINTERFACE

--*/
{
    CStdProxyBuffer   * pCThis  = (CStdProxyBuffer *) This;
    HRESULT             hr = E_NOINTERFACE;
    const IID *         pIID;

    *ppv = 0;

    if( (memcmp(&riid, &IID_IUnknown, sizeof(IID)) == 0) ||
        (memcmp(&riid, &IID_IRpcProxyBuffer, sizeof(IID)) == 0))
    {
        //This is an internal interface. Increment the internal reference count.
        InterlockedIncrement( &pCThis->RefCount);
        *ppv = This;
        hr = S_OK;
        return hr;   
    }
    else if ( pCThis->pRMBVtbl && 
              (memcmp(&riid, &IID_IReleaseMarshalBuffers,sizeof(IID)) == 0))
    {
        InterlockedIncrement( &pCThis->RefCount);

        *ppv = (void *) & pCThis->pRMBVtbl;
        hr = S_OK;
        return hr;
    }

    if(memcmp(&riid, &IID_ISynchronize, sizeof(IID)) == 0)
    {
        hr = pCThis->punkOuter->lpVtbl->QueryInterface( pCThis->punkOuter,
                                                        IID_ISynchronize,
                                                        ppv);
    }

    pIID = NdrGetProxyIID(&pCThis->pProxyVtbl);

    if(memcmp(&riid, pIID, sizeof(IID)) == 0)
    {
        //Increment the reference count.
        pCThis->punkOuter->lpVtbl->AddRef(pCThis->punkOuter);
        
        *ppv = (void *) &pCThis->pProxyVtbl;
        hr = S_OK;
    }

    return hr;
};


ULONG STDMETHODCALLTYPE
CStdProxyBuffer_AddRef(
    IN  IRpcProxyBuffer *This)
/*++

Routine Description:
    Increment reference count.

Used for
    CStdProxyBuffer2
    CStdAsyncProxyBuffer
    CStdAsuncProxyBuffer2

Arguments:

Return Value:
    Reference count.

--*/
{
    // We do not need to go through punkOuter for ICallFactory.

    CStdProxyBuffer   *  pCThis  = (CStdProxyBuffer *) This;

    InterlockedIncrement(&pCThis->RefCount);

    return (ULONG) pCThis->RefCount;
};



ULONG STDMETHODCALLTYPE
CStdProxyBuffer_Release(
    IN  IRpcProxyBuffer *This)
/*++

Routine Description:
    Decrement reference count.

Arguments:

Return Value:
    Reference count.

--*/
{
    ULONG count;
    IPSFactoryBuffer *pFactory;

    NDR_ASSERT(((CStdProxyBuffer *)This)->RefCount > 0, "Invalid reference count");

    count = (unsigned long) ((CStdProxyBuffer *)This)->RefCount - 1;


    if(InterlockedDecrement(&((CStdProxyBuffer *)This)->RefCount) == 0)
    {
        count = 0;

        pFactory = (IPSFactoryBuffer *) ((CStdProxyBuffer *)This)->pPSFactory;

        //Decrement the DLL reference count.
        pFactory->lpVtbl->Release(pFactory);

#if DBG == 1
        //In debug builds, zero fill the memory.
        memset(This,  '\0', sizeof(CStdProxyBuffer));
#endif

        //Free the memory
        (*pfnCoTaskMemFree)(This);
    }

    return count;
};


ULONG STDMETHODCALLTYPE
CStdProxyBuffer2_Release(
    IN  IRpcProxyBuffer *   This)
/*++

Routine Description:
    Decrement reference count.  This function is used by proxies
    which delegate to the base interface.

Arguments:
    This - Points to a CStdProxyBuffer2.

Return Value:
    Reference count.

--*/
{
    ULONG               count;
    IPSFactoryBuffer *  pFactory;
    IRpcProxyBuffer *   pBaseProxyBuffer;
    IUnknown *          pBaseProxy;

    NDR_ASSERT(((CStdProxyBuffer2 *)This)->RefCount > 0, "Invalid reference count");

    count = (ULONG) ((CStdProxyBuffer2 *)This)->RefCount - 1;

    if(InterlockedDecrement(&((CStdProxyBuffer2 *)This)->RefCount) == 0)
    {
        count = 0;

        //Delegation support.
        pBaseProxy = ((CStdProxyBuffer2 *)This)->pBaseProxy;
        if(pBaseProxy != 0)
        {
// Shannon - why?
            //This is a weak reference, so we don't release it.
            //pBaseProxy->lpVtbl->Release(pBaseProxy);
        }

        pBaseProxyBuffer = ((CStdProxyBuffer2 *)This)->pBaseProxyBuffer;

        if( pBaseProxyBuffer != 0)
        {
            pBaseProxyBuffer->lpVtbl->Release(pBaseProxyBuffer);
        }

        //Decrement the DLL reference count.
        pFactory = (IPSFactoryBuffer *) ((CStdProxyBuffer2 *)This)->pPSFactory;
        pFactory->lpVtbl->Release(pFactory);

#if DBG == 1
        //In debug builds, zero fill the memory.
        memset(This,  '\0', sizeof(CStdProxyBuffer2));
#endif

        //Free the memory
        (*pfnCoTaskMemFree)(This);
    }

    return count;
};


ULONG STDMETHODCALLTYPE
CStdAsyncProxyBuffer_Release(
    IN  IRpcProxyBuffer *This)
/*++

Routine Description:
    Decrement reference count.

Arguments:

Return Value:
    Reference count.

--*/
{
    // We do not need to go through punkOuter for ICallFactory
    // and so everything is local.

    CStdAsyncProxyBuffer * pAsyncPB = (CStdAsyncProxyBuffer *)This;
    ULONG                  count;


    NDR_ASSERT( pAsyncPB->RefCount > 0, "Async proxy Invalid reference count");

    count = (unsigned long) pAsyncPB->RefCount - 1;


    if ( InterlockedDecrement(&pAsyncPB->RefCount) == 0)
        {
        IPSFactoryBuffer * pFactory = pAsyncPB->pPSFactory;

        count = 0;

        // Release the pAsyncMsg and the related state
        NdrpAsyncProxyMsgDestructor( pAsyncPB );

        //Decrement the DLL reference count.
        pFactory->lpVtbl->Release( pFactory );

#if DBG == 1
        //In debug builds, zero fill the memory.
        memset( pAsyncPB,  '\32', sizeof(CStdAsyncProxyBuffer));
#endif

        //Free the memory
        (*pfnCoTaskMemFree)(pAsyncPB);
        }

    return count;
};


ULONG STDMETHODCALLTYPE
CStdAsyncProxyBuffer2_Release(
    IN  IRpcProxyBuffer *   This)
/*++

Routine Description:
    Decrement reference count.  This function is used by proxies
    which delegate to the base interface.

Arguments:
    This - Points to a CStdProxyBuffer2.

Return Value:
    Reference count.

--*/
{
    CStdAsyncProxyBuffer * pAsyncPB = (CStdAsyncProxyBuffer *)This;
    ULONG                  count;

    NDR_ASSERT( pAsyncPB->RefCount > 0, "Invalid reference count");

    count = (ULONG) pAsyncPB->RefCount - 1;

    if ( InterlockedDecrement(&pAsyncPB->RefCount) == 0)
        {
        IRpcProxyBuffer *   pBaseProxyBuffer ;
        IPSFactoryBuffer *  pFactory = pAsyncPB->pPSFactory;

        count = 0;

        // Delegation support - release the base async proxy.

        if( pAsyncPB->map.pBaseProxy != 0)
            {
            // Shannon - why?
            //This is a weak reference, so we don't release it.
            //pBaseProxy->lpVtbl->Release(pBaseProxy);
            }

        pBaseProxyBuffer = pAsyncPB->pBaseProxyBuffer;

        if( pBaseProxyBuffer != 0)
            pBaseProxyBuffer->lpVtbl->Release(pBaseProxyBuffer);

        // Release the pAsyncMsg and the related state
        NdrpAsyncProxyMsgDestructor( (CStdAsyncProxyBuffer*)This );

        // Then clean up the async proxy itself.

        //Decrement the DLL reference count.
        pFactory->lpVtbl->Release(pFactory);

#if DBG == 1
        //In debug builds, zero fill the memory.
        memset(pAsyncPB,  '\32', sizeof(CStdAsyncProxyBuffer));
#endif

        //Free the memory
        (*pfnCoTaskMemFree)(pAsyncPB);
        }

    return count;
};


HRESULT STDMETHODCALLTYPE
CStdProxyBuffer_RMB_QueryInterface(
    IN  IReleaseMarshalBuffers   *This,
    IN  REFIID          riid,
    OUT void **         ppvObject)
/*++

Routine Description:
    Query for an interface on the interface stub IReleaseMarshalBuffers pointer.

Arguments:
    riid        - Supplies the IID of the interface being requested.
    ppvObject   - Returns a pointer to the requested interface.

Return Value:
    S_OK
    E_NOINTERFACE

Note:
    Works the same way for ProxyBuffer2 and AsyncProxyBuffer.
--*/
{
    CStdProxyBuffer * pSyncPB = (CStdProxyBuffer *)
                        ((uchar *)This - offsetof(CStdProxyBuffer,pRMBVtbl));

    return pSyncPB->lpVtbl->QueryInterface( (IRpcProxyBuffer *)pSyncPB,
                                            riid,
                                            ppvObject );
}


ULONG STDMETHODCALLTYPE
CStdProxyBuffer_RMB_AddRef(
    IN  IReleaseMarshalBuffers *This)
/*++

Routine Description:
    Implementation of AddRef for interface proxy.

Arguments:

Return Value:
    Reference count.
    
--*/
{
    ULONG  count;

    CStdProxyBuffer * pSyncPB = (CStdProxyBuffer *)
                        ((uchar *)This - offsetof(CStdProxyBuffer,pRMBVtbl));

    // It needs to go through punkOuter.

    count = pSyncPB->lpVtbl->AddRef((IRpcProxyBuffer *) pSyncPB );
    return count;
};


ULONG STDMETHODCALLTYPE
CStdProxyBuffer_RMB_Release(
    IN  IReleaseMarshalBuffers *This)
/*++

Routine Description:
    Implementation of Release for interface proxy.

Arguments:

Return Value:
    Reference count.

--*/
{
    ULONG               count;

    CStdProxyBuffer2 * pSyncPB = (CStdProxyBuffer2 *)
                        ((uchar *)This - offsetof(CStdProxyBuffer2,pRMBVtbl));

    count = pSyncPB->lpVtbl->Release( (IRpcProxyBuffer *)pSyncPB);

    return count;
};


HRESULT STDMETHODCALLTYPE
CStdProxyBuffer_RMB_ReleaseMarshalBuffer(
    IN IReleaseMarshalBuffers *This,
    IN RPCOLEMESSAGE * pMsg,
    IN DWORD dwFlags,
    IN IUnknown *pChnl)
{
    CStdProxyBuffer *      pSyncPB;
    HRESULT hr;
    if (NULL != pChnl)
        return E_INVALIDARG;

    // [in] only in client side.
    if (dwFlags)
        return E_INVALIDARG;
             
    hr = NdrpClientReleaseMarshalBuffer(This,
                                        (RPC_MESSAGE *)pMsg, 
                                        dwFlags,
                                        FALSE );    // SYNC 

    return hr;
}

#define IN_BUFFER           0
#define OUT_BUFFER          1

// the pRMBVtbl member is in the same position is both CStdProxyBuffer(2) and 
//     CStdAsyncProxyBuffer so we can cast it anyway.
HRESULT STDMETHODCALLTYPE
CStdAsyncProxyBuffer_RMB_ReleaseMarshalBuffer(
    IN IReleaseMarshalBuffers *This,
    IN RPCOLEMESSAGE * pMsg,
    IN DWORD dwIOFlags,
    IN IUnknown *pChnl)
{
    HRESULT hr;
    if (NULL != pChnl)
        return E_INVALIDARG;

    // [in] only in client side.
    if (dwIOFlags != IN_BUFFER)
        return E_INVALIDARG;
             
    hr = NdrpClientReleaseMarshalBuffer(This,
                                        (RPC_MESSAGE *)pMsg, 
                                        dwIOFlags,
                                        TRUE);      // is async

    return hr;
}



HRESULT STDMETHODCALLTYPE
CStdProxyBuffer_Connect(
    IN  IRpcProxyBuffer *   This,
    IN  IRpcChannelBuffer * pChannel)
/*++

Routine Description:
    Connect the proxy to the channel.

Arguments:
    pChannel - Supplies a pointer to the channel.

Return Value:
    S_OK

--*/
{
    CStdProxyBuffer   *     pCThis  = (CStdProxyBuffer *) This;
    HRESULT                 hr;
    IRpcChannelBuffer *     pTemp = 0;

    //
    // Get a pointer to the new channel.
    //
    hr = pChannel->lpVtbl->QueryInterface(
        pChannel, IID_IRpcChannelBuffer, (void **) &pTemp);

    if(hr == S_OK)
    {
        //
        // Save the pointer to the new channel.
        //
        pTemp = (IRpcChannelBuffer *) InterlockedExchangePointer(
            (PVOID *) &pCThis->pChannel, (PVOID) pTemp);

        if(pTemp != 0)
        {
            //
            //Release the old channel.
            //
            pTemp->lpVtbl->Release(pTemp);
            pTemp = 0;
        }
    }
    return hr;
};


HRESULT STDMETHODCALLTYPE
CStdAsyncProxyBuffer_Connect(
    IN  IRpcProxyBuffer *   This,
    IN  IRpcChannelBuffer * pChannel)
/*++

Routine Description:
    Connect the proxy to the channel.

Arguments:
    pChannel - Supplies a pointer to the channel.

Return Value:
    S_OK

--*/
{
    CStdProxyBuffer   *     pCThis  = (CStdProxyBuffer *) This;
    HRESULT                 hr;
    IRpcChannelBuffer *    pTemp = 0;

    // Get a pointer to the new channel.
    // Note, the async proxy is not aggregated with the channel,
    // It simply keeps the channel pointer.
    //
    hr = pChannel->lpVtbl->QueryInterface(
        pChannel, IID_IAsyncRpcChannelBuffer, (void **) &pTemp);

    if(hr == S_OK)
    {
        //
        // Save the pointer to the new channel.
        //
        pTemp = (IRpcChannelBuffer *) InterlockedExchangePointer(
            (PVOID *) &pCThis->pChannel, (PVOID) pTemp);

        if(pTemp != 0)
        {
            //
            //Release the old channel.
            //
            pTemp->lpVtbl->Release(pTemp);
            pTemp = 0;
        }
    }
    return hr;
};



HRESULT STDMETHODCALLTYPE
CStdProxyBuffer2_Connect(
    IN  IRpcProxyBuffer *   This,
    IN  IRpcChannelBuffer * pChannel)
/*++

Routine Description:
    Connect the proxy to the channel.  Supports delegation.

Arguments:
    pChannel - Supplies a pointer to the channel.

Return Value:
    S_OK
        E_NOINTERFACE
        E_OUTOFMEMORY

--*/
{
    HRESULT                 hr;
    IRpcProxyBuffer *       pBaseProxyBuffer;
    IRpcChannelBuffer *     pWrapper;
    const IID *             pIID;

    hr = CStdProxyBuffer_Connect(This, pChannel);

    if(SUCCEEDED(hr))
    {
        pBaseProxyBuffer = ((CStdProxyBuffer2 *)This)->pBaseProxyBuffer;

        if(pBaseProxyBuffer != 0)
        {
           pIID = NdrGetProxyIID(&((CStdProxyBuffer2 *)This)->pProxyVtbl);

            hr = CreateChannelWrapper(pIID,
                                      pChannel,
                                      &pWrapper);
            if(SUCCEEDED(hr))
            {
                hr = pBaseProxyBuffer->lpVtbl->Connect(pBaseProxyBuffer, pWrapper);
                // HACKALERT: OleAutomation returns NULL pv in CreateProxy
                // in cases where they don't know whether to return an NDR
                // proxy or a custom-format proxy. So we have to go connect
                // the proxy first then Query for the real interface once that
                // is done.
                if((NULL == ((CStdProxyBuffer2 *)This)->pBaseProxy) &&
                   SUCCEEDED(hr))
                {
                    IUnknown *pv;

                    hr = pBaseProxyBuffer->lpVtbl->QueryInterface(pBaseProxyBuffer,
                                                                  ((CStdProxyBuffer2 *)This)->iidBase,
                                                                  (void **) &pv);
                    if(SUCCEEDED(hr))
                    {
                        //Release our reference here.
                        pv->lpVtbl->Release(pv);

                        //We keep a weak reference to pv.
                        ((CStdProxyBuffer2 *)This)->pBaseProxy = pv;
                    }
                }
                pWrapper->lpVtbl->Release(pWrapper);
            }
        }
    }

    return hr;
};


HRESULT STDMETHODCALLTYPE
CStdAsyncProxyBuffer2_Connect(
    IN  IRpcProxyBuffer *   This,
    IN  IRpcChannelBuffer * pChannel)
/*++

Routine Description:
    Connect the proxy to the channel.  Supports delegation.

Arguments:
    pChannel - Supplies a pointer to the channel.

Return Value:
    S_OK
        E_NOINTERFACE
        E_OUTOFMEMORY

--*/
{
    HRESULT                 hr;
    IRpcProxyBuffer *       pBaseProxyBuffer;
    IRpcChannelBuffer *     pWrapper;
    const IID *             pIID;

    hr = CStdAsyncProxyBuffer_Connect(This, pChannel);

    if(SUCCEEDED(hr))
    {
        // Note that all the fields from CStdProxyBuffer2 that we indicate below
        // have the same offsets in CStdAsyncProxyBuffer that is being handled.
        // So I leave the cast unchanged to make future code merge easier.
        //
        pBaseProxyBuffer = ((CStdProxyBuffer2 *)This)->pBaseProxyBuffer;

        if(pBaseProxyBuffer != 0)
        {
            pIID = NdrGetProxyIID(&((CStdProxyBuffer2 *)This)->pProxyVtbl);

            // We need a pChannel that is guaranteed to be IAsyncRpcChannelBuffer -
            // but note, this is exactly what we obtained in the Connect call above.

            hr = CreateAsyncChannelWrapper( pIID,
                                           ((CStdProxyBuffer2*)This)->pChannel,
                                            &pWrapper);
            if(SUCCEEDED(hr))
            {
                hr = pBaseProxyBuffer->lpVtbl->Connect(pBaseProxyBuffer, pWrapper);

                // This hack alert is rather for future.
                // HACKALERT: OleAutomation returns NULL pv in CreateProxy
                // in cases where they don't know whether to return an NDR
                // proxy or a custom-format proxy. So we have to go connect
                // the proxy first then Query for the real interface once that
                // is done.
                if((NULL == ((CStdProxyBuffer2 *)This)->pBaseProxy) &&
                   SUCCEEDED(hr))
                {
                    IUnknown *pv;

                    hr = pBaseProxyBuffer->lpVtbl->QueryInterface(pBaseProxyBuffer,
                                                                  ((CStdProxyBuffer2 *)This)->iidBase,
                                                                  (void **) &pv);
                    if(SUCCEEDED(hr))
                    {
                        //Release our reference here.
                        pv->lpVtbl->Release(pv);

                        //We keep a weak reference to pv.
                        ((CStdProxyBuffer2 *)This)->pBaseProxy = pv;
                    }
                }
                pWrapper->lpVtbl->Release(pWrapper);
            }
        }
    }

    return hr;
};


void STDMETHODCALLTYPE
CStdProxyBuffer_Disconnect(
    IN  IRpcProxyBuffer *This)
/*++

Routine Description:
    Disconnect the proxy from the channel.
    
Also used for:
    CStdAsyncProxyBuffer_Disconnect

Arguments:

Return Value:
    None.

--*/
{
    CStdProxyBuffer   * pCThis  = (CStdProxyBuffer *) This;
    IRpcChannelBuffer * pOldChannel;

    pOldChannel = (IRpcChannelBuffer *) InterlockedExchangePointer(
                                        (PVOID *) &pCThis->pChannel, 0);

    if(pOldChannel != 0)
    {
        //Release the old channel.
        //
        pOldChannel->lpVtbl->Release(pOldChannel);
    }
};

void STDMETHODCALLTYPE
CStdProxyBuffer2_Disconnect(
    IN  IRpcProxyBuffer *This)
/*++

Routine Description:
    Disconnect the proxy from the channel.

Also used for:
    CStdAsyncProxyBuffer2_Disconnect

Arguments:

Return Value:
    None.

--*/
{
    IRpcProxyBuffer *pBaseProxyBuffer;

    CStdProxyBuffer_Disconnect(This);

    pBaseProxyBuffer = ((CStdProxyBuffer2 *)This)->pBaseProxyBuffer;

    if(pBaseProxyBuffer != 0)
        pBaseProxyBuffer->lpVtbl->Disconnect(pBaseProxyBuffer);
};


HRESULT
NdrpCreateNonDelegatedAsyncProxy( 
//CStdProxyBuffer_CreateAsyncProxy(
    IN  IRpcProxyBuffer         *This, 
    IN  REFIID                  riid, // async IID
    IN  IUnknown *              punkOuter, // controlling unknown
    OUT CStdAsyncProxyBuffer ** ppAsyncProxy
    )
/*
    Creates a call object, i.e. an async proxy object.
    An async proxy doesn't have a pSynchronize, just passes it.
    
    Note, because the call comes via a CStdProxyBuffer, not Buffer2,
    we know that we need to create only a non-delegated async proxy.
    This is because CStdProxyBuffer itself is a non-delegated proxy.
*/
{
    BOOL                    fFound;
    long                    j;   // if index
    const ProxyFileInfo *   pProxyFileInfo;

    CStdProxyBuffer *       pSyncPB = (CStdProxyBuffer *)This;

    *ppAsyncProxy = 0;
    
    if ( ! pSyncPB->pCallFactoryVtbl  ||  !pSyncPB->pAsyncIID )
        return E_NOINTERFACE;

    // Check if sync and async iids match.

    if ( memcmp( &riid, pSyncPB->pAsyncIID, sizeof(IID)) != 0 )
        return E_NOINTERFACE;

    // same file, so we can use the sync pPSFactory.

    fFound = NdrpFindInterface( ((CStdPSFactoryBuffer *)pSyncPB->pPSFactory)->pProxyFileList, 
                                riid, 
                                &pProxyFileInfo, 
                                & j);
    if ( !fFound )
        return E_NOINTERFACE;

    CStdAsyncProxyBuffer *pAsyncPB = 
        (CStdAsyncProxyBuffer*)(*pfnCoTaskMemAlloc)(sizeof(CStdAsyncProxyBuffer));
        
    if( ! pAsyncPB )
        return E_OUTOFMEMORY;

    memset( pAsyncPB, 0, sizeof(CStdAsyncProxyBuffer));
    //
    //  Everything gets zeroed out regardless of their position
    //  when mapping CStdBuffer vs. CstdBuffer2 into CStdAsyncBuffer

    // Non-delegated case.

    pAsyncPB->lpVtbl     = & CStdAsyncProxyBufferVtbl;
    pAsyncPB->pProxyVtbl = & pProxyFileInfo->pProxyVtblList[j]->Vtbl;
    pAsyncPB->RefCount   = 1;
    pAsyncPB->punkOuter  = punkOuter ? punkOuter 
                                     : (IUnknown *) pAsyncPB;
                                         
    pAsyncPB->pSyncIID   = NdrGetProxyIID( &pSyncPB->pProxyVtbl );
    // Note, no connection to channel yet.
    // Actually we never call create call on the channel.
                                  
    NdrpAsyncProxyMsgConstructor( pAsyncPB );

    // Increment the DLL reference count for DllCanUnloadNow.
    // Same dll, so we can use the sync pPSFactory.
    //
    pSyncPB->pPSFactory->lpVtbl->AddRef( pSyncPB->pPSFactory );
    // This is in the "map".
    ((CStdProxyBuffer *)pAsyncPB)->pPSFactory = pSyncPB->pPSFactory;

    // Just have it in both places.
    pAsyncPB->pPSFactory = pSyncPB->pPSFactory;

    *ppAsyncProxy = pAsyncPB;

    return S_OK;
}


HRESULT
// CStdProxyBuffer2_CreateAsyncProxy(
NdrpCreateDelegatedAsyncProxy(
    IN  IRpcProxyBuffer         *This, 
    IN  REFIID                  riid, // async IID
    IN  IUnknown *              punkOuter, // controlling unknown
    OUT CStdAsyncProxyBuffer ** ppAsyncProxy   
    )
/*
    Creates a call object, i.e. an async proxy object.
    
    Note, because the call comes via a CStdProxyBuffer2, not Buffer,
    we know that we need to create only a delegated async proxy.
*/
{
    HRESULT                 hr;
    BOOL                    fFound;
    long                     j;   // if index
    const ProxyFileInfo *   pProxyFileInfo;

    CStdProxyBuffer2 *      pSyncPB = (CStdProxyBuffer2 *)This;
    CStdAsyncProxyBuffer    *pBaseAsyncPB;

    ICallFactory *          pCallFactory;

    *ppAsyncProxy = 0;
    
    if ( ! pSyncPB->pCallFactoryVtbl  ||  !pSyncPB->pAsyncIID )
        return E_NOINTERFACE;

    if ( memcmp( &riid, pSyncPB->pAsyncIID, sizeof(IID)) != 0 )
        return E_NOINTERFACE;

    // same file, so we can use the sync pPSFactory.

    fFound = NdrpFindInterface( ((CStdPSFactoryBuffer *)pSyncPB->pPSFactory)->pProxyFileList, 
                                riid, 
                                &pProxyFileInfo, 
                                & j);
    if ( !fFound )
        return E_NOINTERFACE;

    // Create async proxy.

    CStdAsyncProxyBuffer *pAsyncPB = 
        (CStdAsyncProxyBuffer*)(*pfnCoTaskMemAlloc)(sizeof(CStdAsyncProxyBuffer));
        
    if( ! pAsyncPB )
        return E_OUTOFMEMORY;

    memset( pAsyncPB, 0, sizeof(CStdAsyncProxyBuffer));
    //
    //  Everything gets zeroed out regardless of their position
    //  when mapping CStdBuffer vs. CstdBuffer2 into CStdAsyncBuffer

    // Fill in for a delegated case.

    pAsyncPB->lpVtbl     = & CStdAsyncProxyBuffer2Vtbl;
    pAsyncPB->pProxyVtbl = & pProxyFileInfo->pProxyVtblList[j]->Vtbl;
    pAsyncPB->RefCount   = 1;
    pAsyncPB->punkOuter  = punkOuter ? punkOuter 
                                     : (IUnknown *) pAsyncPB;
    pAsyncPB->iidBase    = *pProxyFileInfo->pDelegatedIIDs[j];
    pAsyncPB->pPSFactory = pSyncPB->pPSFactory;
    pAsyncPB->pSyncIID   = NdrGetProxyIID( &pSyncPB->pProxyVtbl );
                                 
    // Note, no connection to channel yet.
    // So we cannot call create call on the channel.

    NdrpAsyncProxyMsgConstructor( pAsyncPB );

    // Create an async proxy for the base interface.
    // We don't know if the base is delegated, so we have to use base call factory.
    // Get the call factory from the base proxy.

    hr = pSyncPB->pBaseProxyBuffer->lpVtbl->QueryInterface(
                                                   pSyncPB->pBaseProxyBuffer,
                                                   IID_ICallFactory,
                                                   (void**)& pCallFactory );

    if ( SUCCEEDED(hr) )
        {
        const IID * pBaseAsyncIID;

        pBaseAsyncIID = *(const IID **)( (uchar*)pSyncPB->pBaseProxyBuffer
                                         + offsetof(CStdProxyBuffer, pAsyncIID));

        // Aggregate the base async proxy with the current async proxy,
        // not with the channel's punkOuter.
    
        hr = pCallFactory->lpVtbl->CreateCall( pCallFactory,
                                               *pBaseAsyncIID,
                                               (IUnknown*) pAsyncPB,
                                               IID_IUnknown,
                                               (IUnknown**)& pBaseAsyncPB );
        pCallFactory->lpVtbl->Release( pCallFactory );
        }


    if ( SUCCEEDED(hr) )
        {
        // Increment the DLL reference count for DllCanUnloadNow.
        // Same dll, so we can use the sync pPSFactory.
        //
        pSyncPB->pPSFactory->lpVtbl->AddRef( pSyncPB->pPSFactory );

        // Hook up the base async proxy.
    
        pAsyncPB->pBaseProxyBuffer = (IRpcProxyBuffer*) pBaseAsyncPB;
        pAsyncPB->map.pBaseProxy   = (IUnknown *) & pBaseAsyncPB->pProxyVtbl;

        *ppAsyncProxy = pAsyncPB;
        }
    else
        {
        (*pfnCoTaskMemFree)( pAsyncPB );
        }

    return hr;
}


//
//  ICallFactory interface on the sync ProxyBuffer and ProxyBuffer2 objects.
//

HRESULT STDMETHODCALLTYPE
CStdProxyBuffer_CF_QueryInterface(
    IN  ICallFactory   *This,
    IN  REFIID          riid,
    OUT void **         ppvObject)
/*++

Routine Description:
    Query for an interface on the interface stub CallFactory pointer.

Arguments:
    riid        - Supplies the IID of the interface being requested.
    ppvObject   - Returns a pointer to the requested interface.

Return Value:
    S_OK
    E_NOINTERFACE

Note:
    Works the same way for ProxyBuffer2 and AsyncProxyBuffer.
--*/
{
    CStdProxyBuffer * pSyncPB = (CStdProxyBuffer *)
                        ((uchar *)This - offsetof(CStdProxyBuffer,pCallFactoryVtbl));

    return pSyncPB->punkOuter->lpVtbl->QueryInterface( pSyncPB->punkOuter,
                                                       riid,
                                                       ppvObject );
}


ULONG STDMETHODCALLTYPE
CStdProxyBuffer_CF_AddRef(
    IN  ICallFactory *This)
/*++

Routine Description:
    Implementation of AddRef for interface proxy.

Arguments:

Return Value:
    Reference count.
    
--*/
{
    ULONG  count;

    CStdProxyBuffer * pSyncPB = (CStdProxyBuffer *)
                        ((uchar *)This - offsetof(CStdProxyBuffer,pCallFactoryVtbl));

    // It needs to go through punkOuter.

    count = pSyncPB->punkOuter->lpVtbl->AddRef( pSyncPB->punkOuter );
    return count;
};


ULONG STDMETHODCALLTYPE
CStdProxyBuffer_CF_Release(
    IN  ICallFactory *This)
/*++

Routine Description:
    Implementation of Release for interface proxy.

Arguments:

Return Value:
    Reference count.

--*/
{
    ULONG               count;

    CStdProxyBuffer2 * pSyncPB = (CStdProxyBuffer2 *)
                        ((uchar *)This - offsetof(CStdProxyBuffer2,pCallFactoryVtbl));

    count = pSyncPB->punkOuter->lpVtbl->Release( pSyncPB->punkOuter );

    return count;
};


HRESULT STDMETHODCALLTYPE
CStdProxyBuffer_CF_CreateCall(
    IN  ICallFactory *This, 
    IN  REFIID        riid, 
    IN  IUnknown *    punkOuter, // controlling unknown
    IN  REFIID        riid2, 
    OUT IUnknown **   ppv   
    )
/*
    Creates a call object, i.e. an async proxy object.
    
    Note, because the call comes via a CStdProxyBuffer, not Buffer2,
    we know that we need to create only a non-delegated async proxy.
*/
{
    CStdProxyBuffer * pSyncPB;

    if ( memcmp( &riid2, &IID_IUnknown, sizeof(IID)) != 0 )
        return E_INVALIDARG;
              
    pSyncPB = (CStdProxyBuffer *)
                  (((uchar *)This) - offsetof( CStdProxyBuffer, pCallFactoryVtbl ));
    
    return NdrpCreateNonDelegatedAsyncProxy( (IRpcProxyBuffer*) pSyncPB, 
                                      riid,
                                      punkOuter,
                                      (CStdAsyncProxyBuffer**) ppv );
}

HRESULT STDMETHODCALLTYPE
CStdProxyBuffer2_CF_CreateCall(
    IN  ICallFactory *This, 
    IN  REFIID        riid, 
    IN  IUnknown *    punkOuter, // controlling unknown
    IN  REFIID        riid2, 
    OUT IUnknown **   ppv   
    )
/*
    Creates a call object, i.e. an async proxy object.

    Note, because the virtual call comes via a CStdProxyBuffer2,
    we know that we need to create only a delegated async proxy.
*/
{
    CStdProxyBuffer2 *      pSyncPB;

    if ( memcmp( &riid2, &IID_IUnknown, sizeof(IID)) != 0 )
        return E_INVALIDARG;
              
    pSyncPB = (CStdProxyBuffer2 *)
                  (((uchar *)This) - offsetof( CStdProxyBuffer2, pCallFactoryVtbl ));

    return NdrpCreateDelegatedAsyncProxy( (IRpcProxyBuffer*) pSyncPB, 
                                          riid,
                                          punkOuter,
                                          (CStdAsyncProxyBuffer**) ppv );
}
/*
HRESULT STDAPICALLTYPE
NdrClientReleaseMarshalBuffer(
    IN IRpcProxyBuffer *pProxy,
    IN RPCOLEMESSAGE * pMsg,
    IN DWORD dwFlags,
    IN IUnknown *pChnl)
{
    CStdProxyBuffer *      pSyncPB;
    void * This = NULL;
    HRESULT hr;

    if (NULL != pChnl)
        return E_INVALIDARG;

    if (dwFlags)
        return E_INVALIDARG;

    hr = pProxy->lpVtbl->QueryInterface(pProxy,&IID_IReleaseMarshalBuffers, &This);
    if (FAILED(hr))
        return E_NOTIMPL;
             
    pSyncPB = (CStdProxyBuffer *)
                  (((uchar *)This) - offsetof( CStdProxyBuffer, lpVtbl ));

    hr = NdrpClientReleaseMarshalBuffer(pSyncPB,(RPC_MESSAGE *)pMsg, dwFlags);
    ((IRpcProxyBuffer *)This)->lpVtbl->Release(This);

    return hr;
}

*/

//
//   IUknown Query, AddRef and Release.
//
HRESULT STDMETHODCALLTYPE
IUnknown_QueryInterface_Proxy(
    IN  IUnknown *  This,
    IN  REFIID      riid,
    OUT void **     ppv)
/*++

Routine Description:
    Implementation of QueryInterface for interface proxy.

Arguments:
    riid - Supplies the IID of the requested interface.
    ppv  - Returns a pointer to the requested interface.

Return Value:
    S_OK
        E_NOINTERFACE

--*/
{
    HRESULT             hr = E_NOINTERFACE;
    CStdProxyBuffer *   pProxyBuffer;

    pProxyBuffer = NdrGetProxyBuffer(This);

    hr = pProxyBuffer->punkOuter->lpVtbl->QueryInterface(
                                pProxyBuffer->punkOuter, riid, ppv);

    return hr;
};


ULONG STDMETHODCALLTYPE
IUnknown_AddRef_Proxy(
    IN  IUnknown *This)
/*++

Routine Description:
    Implementation of AddRef for interface proxy.

Arguments:

Return Value:
    Reference count.

--*/
{
    CStdProxyBuffer *   pProxyBuffer;
    ULONG               count;

    pProxyBuffer = NdrGetProxyBuffer(This);
    count = pProxyBuffer->punkOuter->lpVtbl->AddRef(pProxyBuffer->punkOuter);

    return count;
};


ULONG STDMETHODCALLTYPE
IUnknown_Release_Proxy(
    IN  IUnknown *This)
/*++

Routine Description:
    Implementation of Release for interface proxy.

Arguments:

Return Value:
    Reference count.

--*/
{
    CStdProxyBuffer *   pProxyBuffer;
    ULONG               count;

    pProxyBuffer = NdrGetProxyBuffer(This);
    count = pProxyBuffer->punkOuter->lpVtbl->Release(pProxyBuffer->punkOuter);

    return count;
};



void RPC_ENTRY
NdrProxyInitialize(
    IN  void * pThis,
    IN  PRPC_MESSAGE        pRpcMsg,
    IN  PMIDL_STUB_MESSAGE  pStubMsg,
    IN  PMIDL_STUB_DESC     pStubDescriptor,
    IN  unsigned int        ProcNum )
/*++

Routine Description:
    Initialize the MIDL_STUB_MESSAGE.

Arguments:
    pThis - Supplies a pointer to the interface proxy.
    pRpcMsg
        pStubMsg
        pStubDescriptor
        ProcNum

Return Value:

--*/
{
    CStdProxyBuffer *   pProxyBuffer;
    HRESULT             hr;

    pProxyBuffer = NdrGetProxyBuffer(pThis);

    //
    // Initialize the stub message fields.
    //
    NdrClientInitializeNew(
        pRpcMsg,
        pStubMsg,
        pStubDescriptor,
        ProcNum );

    //Note that NdrClientInitializeNew sets RPC_FLAGS_VALID_BIT in the ProcNum.
    //We don't want to do this for object interfaces, so we clear the flag here.
    pRpcMsg->ProcNum &= ~RPC_FLAGS_VALID_BIT;

    pStubMsg->pRpcChannelBuffer = pProxyBuffer->pChannel;

    //Check if we are connected to a channel.
    if(pStubMsg->pRpcChannelBuffer != 0)
    {
        //AddRef the channel.
        //We will release it later in NdrProxyFreeBuffer.
        pStubMsg->pRpcChannelBuffer->lpVtbl->AddRef(pStubMsg->pRpcChannelBuffer);

        //Get the destination context from the channel
        hr = pStubMsg->pRpcChannelBuffer->lpVtbl->GetDestCtx(
            pStubMsg->pRpcChannelBuffer, &pStubMsg->dwDestContext, &pStubMsg->pvDestContext);
    }
    else
    {
        //We are not connected to a channel.
        RpcRaiseException(CO_E_OBJNOTCONNECTED);
    }
}


void RPC_ENTRY
NdrProxyGetBuffer(
    IN  void *              pThis,
    IN  PMIDL_STUB_MESSAGE  pStubMsg)
/*++

Routine Description:
    Get a message buffer from the channel

Arguments:
    pThis - Supplies a pointer to the interface proxy.
    pStubMsg

Return Value:
    None.  If an error occurs, this function will raise an exception.

--*/
{
    HRESULT     hr;

    const IID * pIID = NdrGetProxyIID(pThis);
    pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength;
    pStubMsg->RpcMsg->DataRepresentation = NDR_LOCAL_DATA_REPRESENTATION;
    pStubMsg->dwStubPhase = PROXY_GETBUFFER;

    hr = pStubMsg->pRpcChannelBuffer->lpVtbl->GetBuffer(
        pStubMsg->pRpcChannelBuffer,
        (RPCOLEMESSAGE *) pStubMsg->RpcMsg,
        *pIID);

    pStubMsg->dwStubPhase = PROXY_MARSHAL;

    if(FAILED(hr))
    {
        RpcRaiseException(hr);
    }
    else
    {
        NDR_ASSERT( ! ((ULONG_PTR)pStubMsg->RpcMsg->Buffer & 0x7),
                    "marshaling buffer misaligned" );

        pStubMsg->Buffer = (unsigned char *) pStubMsg->RpcMsg->Buffer;
        pStubMsg->fBufferValid = TRUE;
    }
}


void RPC_ENTRY
NdrProxySendReceive(
    IN  void *              pThis,
    IN  MIDL_STUB_MESSAGE * pStubMsg)
/*++

Routine Description:
    Send a message to server, then wait for reply message.

Arguments:
    pThis - Supplies a pointer to the interface proxy.
    pStubMsg

Return Value:
        None.  If an error occurs, this function will raise an exception.

--*/
{
    HRESULT hr;
    DWORD   dwStatus;

    //Calculate the number of bytes to send.

    if ( pStubMsg->RpcMsg->BufferLength <
            (uint)(pStubMsg->Buffer - (uchar *)pStubMsg->RpcMsg->Buffer))
        {
        NDR_ASSERT( 0, "NdrProxySendReceive : buffer overflow" );
        RpcRaiseException( RPC_S_INTERNAL_ERROR );
        }

    pStubMsg->RpcMsg->BufferLength = (ulong)( pStubMsg->Buffer -
                                   (unsigned char *) pStubMsg->RpcMsg->Buffer );

    pStubMsg->fBufferValid = FALSE;
    pStubMsg->dwStubPhase = PROXY_SENDRECEIVE;

    hr = pStubMsg->pRpcChannelBuffer->lpVtbl->SendReceive(
        pStubMsg->pRpcChannelBuffer,
        (RPCOLEMESSAGE *) pStubMsg->RpcMsg, &dwStatus);

    pStubMsg->dwStubPhase = PROXY_UNMARSHAL;

    if(FAILED(hr))
    {
        switch(hr)
        {
        case RPC_E_FAULT:
            RpcRaiseException(dwStatus);
            break;

        default:
            RpcRaiseException(hr);
            break;
        }
    }
    else
    {
        NDR_ASSERT( ! ((ULONG_PTR)pStubMsg->RpcMsg->Buffer & 0x7),
                    "marshaling buffer misaligned" );

        pStubMsg->Buffer = (uchar*)pStubMsg->RpcMsg->Buffer;
        pStubMsg->BufferStart = pStubMsg->Buffer;
        pStubMsg->BufferEnd   = pStubMsg->BufferStart + pStubMsg->RpcMsg->BufferLength;
        pStubMsg->fBufferValid = TRUE;
    }
}


void RPC_ENTRY
NdrProxyFreeBuffer(
    IN  void *              pThis,
    IN  MIDL_STUB_MESSAGE * pStubMsg)
/*++

Routine Description:
    Free the message buffer.

Arguments:
    pThis - Supplies a pointer to the interface proxy.
    pStubMsg

Return Value:
    None.

--*/
{
    if(pStubMsg->pRpcChannelBuffer != 0)
    {
        //Free the message buffer.
        if(pStubMsg->fBufferValid == TRUE)
            {
            // If pipes, we need to reset the partial bit for some reason.

            pStubMsg->RpcMsg->RpcFlags &= ~RPC_BUFFER_PARTIAL;

            pStubMsg->pRpcChannelBuffer->lpVtbl->FreeBuffer(
                pStubMsg->pRpcChannelBuffer, (RPCOLEMESSAGE *) pStubMsg->RpcMsg);
            }

        //Release the channel.
        pStubMsg->pRpcChannelBuffer->lpVtbl->Release(pStubMsg->pRpcChannelBuffer);
        pStubMsg->pRpcChannelBuffer = 0;
    }
}

HRESULT RPC_ENTRY
NdrProxyErrorHandler(
    IN  DWORD dwExceptionCode)
/*++

Routine Description:
    Maps an exception code into an HRESULT failure code.

Arguments:
    dwExceptionCode

Return Value:
   This function returns an HRESULT failure code.

--*/
{
    HRESULT hr = dwExceptionCode;

    if(FAILED((HRESULT) dwExceptionCode))
        hr = (HRESULT) dwExceptionCode;
    else
        hr = HRESULT_FROM_WIN32(dwExceptionCode);

    return hr;
}


HRESULT STDMETHODCALLTYPE
CreateChannelWrapper
/*++

Routine Description:
    Creates a wrapper for the channel.  The wrapper ensures
        that we use the correct IID when the proxy for the base
        interface calls GetBuffer.

Arguments:
    pIID
        pChannel
        pChannelWrapper

Return Value:
    S_OK
        E_OUTOFMEMORY

--*/
(
    const IID *             pIID,
    IRpcChannelBuffer *     pChannel,
    IRpcChannelBuffer **    ppChannelWrapper
)
{
    HRESULT hr;
    ChannelWrapper *pWrapper = 
        (ChannelWrapper*)(*pfnCoTaskMemAlloc)(sizeof(ChannelWrapper));

    if(pWrapper != 0)
    {
        hr = S_OK;
        pWrapper->lpVtbl = (IRpcChannelBufferVtbl*) &ChannelWrapperVtbl;
        pWrapper->RefCount = 1;
        pWrapper->pIID = pIID;
        pChannel->lpVtbl->AddRef(pChannel);
        pWrapper->pChannel = pChannel;
        *ppChannelWrapper = (IRpcChannelBuffer *) pWrapper;
    }
    else
    {
        hr = E_OUTOFMEMORY;
        *ppChannelWrapper = 0;
    }
    return hr;
}


HRESULT STDMETHODCALLTYPE
CreateAsyncChannelWrapper
/*++

Routine Description:
    Creates a wrapper for the channel.  The wrapper ensures
        that we use the correct IID when the proxy for the base
        interface calls GetBuffer.

Arguments:
    pIID
        pChannel
        pChannelWrapper

Return Value:
    S_OK
        E_OUTOFMEMORY

--*/
(
    const IID *             pIID,
    IRpcChannelBuffer *     pChannel,
    IRpcChannelBuffer **    ppChannelWrapper
)
{
    HRESULT hr;
    ChannelWrapper *pWrapper = 
        (ChannelWrapper*)(*pfnCoTaskMemAlloc)(sizeof(ChannelWrapper));

    if(pWrapper != 0)
    {
        hr = S_OK;
        pWrapper->lpVtbl = (IRpcChannelBufferVtbl*) &AsyncChannelWrapperVtbl;
        pWrapper->RefCount = 1;
        pWrapper->pIID = pIID;
        pChannel->lpVtbl->AddRef(pChannel);
        pWrapper->pChannel = pChannel;
        *ppChannelWrapper = (IRpcChannelBuffer *) pWrapper;
    }
    else
    {
        hr = E_OUTOFMEMORY;
        *ppChannelWrapper = 0;
    }
    return hr;
}


HRESULT STDMETHODCALLTYPE
ChannelWrapper_QueryInterface
/*++

Routine Description:
    The channel wrapper supports the IUnknown and IRpcChannelBuffer interfaces.

Arguments:
    riid
        ppvObject

Return Value:
    S_OK
        E_NOINTERFACE

--*/
(
    IRpcChannelBuffer3 * This,
    REFIID riid,
    void **ppvObject
)
{
    HRESULT hr;

    if((memcmp(&riid, &IID_IUnknown, sizeof(IID)) == 0) ||
        (memcmp(&riid, &IID_IRpcChannelBuffer, sizeof(IID)) == 0) ||
        (memcmp(&riid, &IID_IRpcChannelBuffer2, sizeof(IID)) == 0) ||
        (memcmp(&riid, &IID_IRpcChannelBuffer3, sizeof(IID)) == 0))
    {
        hr = S_OK;
        This->lpVtbl->AddRef(This);
        *ppvObject = This;
    }
    else
    {
        hr = E_NOINTERFACE;
        *ppvObject = 0;
    }

    return hr;
}


HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_QueryInterface
/*++

Routine Description:
    The channel wrapper supports the IUnknown and IRpcChannelBuffer interfaces.

Arguments:
    riid
        ppvObject

Return Value:
    S_OK
        E_NOINTERFACE

--*/
    (
    IAsyncRpcChannelBuffer *    This,
    REFIID                      riid,
    void **                     ppvObject
    )
{
    HRESULT hr;

    if((memcmp(&riid, &IID_IUnknown, sizeof(IID)) == 0) ||
        (memcmp(&riid, &IID_IRpcChannelBuffer, sizeof(IID)) == 0) ||
        (memcmp(&riid, &IID_IRpcChannelBuffer2, sizeof(IID)) == 0) ||
        (memcmp(&riid, &IID_IAsyncRpcChannelBuffer, sizeof(IID)) == 0))
    {
        hr = S_OK;
        This->lpVtbl->AddRef(This);
        *ppvObject = This;
    }
    else
    {
        hr = E_NOINTERFACE;
        *ppvObject = 0;
    }

    return hr;
}


ULONG STDMETHODCALLTYPE
ChannelWrapper_AddRef
/*++

Routine Description:
    Increment reference count.

Arguments:

Return Value:
    Reference count.

--*/
(
    IRpcChannelBuffer3 * This
)
{
    ChannelWrapper *pWrapper = (ChannelWrapper *) This;

    InterlockedIncrement(&pWrapper->RefCount);

    return (ULONG) pWrapper->RefCount;

}

ULONG STDMETHODCALLTYPE
AsyncChannelWrapper_AddRef(
    IAsyncRpcChannelBuffer * This
    )
{
    return ChannelWrapper_AddRef( (IRpcChannelBuffer3 *) This );
}


ULONG STDMETHODCALLTYPE
ChannelWrapper_Release
/*++

Routine Description:
    Decrement reference count.

Arguments:

Return Value:
    Reference count.

--*/
(
    IRpcChannelBuffer3 * This
)
{
    unsigned long           count;
    IRpcChannelBuffer *     pChannel;

    NDR_ASSERT(((ChannelWrapper *)This)->RefCount > 0, "Invalid reference count");

    count = (unsigned long) ((ChannelWrapper *)This)->RefCount - 1;

    if(InterlockedDecrement(&((ChannelWrapper *)This)->RefCount) == 0)
    {
        count = 0;

        pChannel = ((ChannelWrapper *)This)->pChannel;

        if(pChannel != 0)
            pChannel->lpVtbl->Release(pChannel);

#if DBG == 1
        //In debug builds, zero fill the memory.
        memset(This,  '\0', sizeof(ChannelWrapper));
#endif

        //Free the memory
        (*pfnCoTaskMemFree)(This);
    }

    return count;
}

ULONG STDMETHODCALLTYPE
AsyncChannelWrapper_Release(
    IAsyncRpcChannelBuffer * This
    )
{
    return ChannelWrapper_Release( (IRpcChannelBuffer3 *) This );
}


HRESULT STDMETHODCALLTYPE
ChannelWrapper_GetBuffer
/*++

Routine Description:
    Get a message buffer from the channel.
    
    This is the reason we have the ChannelWrapper at all.
    We replace the riid of the current proxy by the one from the Wrapper.

Arguments:
    pMessage
        riid

Return Value:

--*/
(
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *      pMessage,
    REFIID               riid
)
{
    HRESULT             hr;
    IRpcChannelBuffer * pChannel;
    const IID *         pIID;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    pIID = ((ChannelWrapper *)This)->pIID;

    hr = pChannel->lpVtbl->GetBuffer(pChannel,
                                     pMessage,
                                     *pIID);
    return hr;
}

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_GetBuffer(
    IAsyncRpcChannelBuffer * This,
    RPCOLEMESSAGE *      pMessage,
    REFIID               riid
    )
{
    return ChannelWrapper_GetBuffer( (IRpcChannelBuffer3 *) This,
                                     pMessage,
                                     riid );
}


HRESULT STDMETHODCALLTYPE
ChannelWrapper_SendReceive
/*++

Routine Description:
    Get a message buffer from the channel

Arguments:
    pMessage
        pStatus

Return Value:
    S_OK

--*/
(
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *      pMessage,
    ULONG *              pStatus
)
{
    HRESULT             hr;
    IRpcChannelBuffer * pChannel;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    hr = pChannel->lpVtbl->SendReceive(pChannel,
                                       pMessage,
                                       pStatus);
    return hr;
}

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_SendReceive(
    IAsyncRpcChannelBuffer * This,
    RPCOLEMESSAGE *      pMessage,
    ULONG *              pStatus
    )
{
    // This can never happen for an async call stub.
    return E_NOTIMPL;
}


HRESULT STDMETHODCALLTYPE
ChannelWrapper_FreeBuffer
/*++

Routine Description:
    Free the message buffer.

Arguments:
    pMessage

Return Value:
    S_OK

--*/
(
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *pMessage
)
{
    HRESULT             hr;
    IRpcChannelBuffer * pChannel;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    hr = pChannel->lpVtbl->FreeBuffer(pChannel,
                                      pMessage);
    return hr;
}

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_FreeBuffer(
    IAsyncRpcChannelBuffer * This,
    RPCOLEMESSAGE *         pMessage
    )
{
    return ChannelWrapper_FreeBuffer( (IRpcChannelBuffer3 *) This,
                                      pMessage );
}



HRESULT STDMETHODCALLTYPE
ChannelWrapper_GetDestCtx
/*++

Routine Description:
    Get the destination context from the channel

Arguments:
    pdwDestContext
        ppvDestContext

Return Value:
    S_OK

--*/
(
    IRpcChannelBuffer3 * This,
    DWORD              * pdwDestContext,
    void              ** ppvDestContext
)
{
    HRESULT             hr;
    IRpcChannelBuffer * pChannel;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    hr = pChannel->lpVtbl->GetDestCtx(pChannel,
                                      pdwDestContext,
                                      ppvDestContext);
    return hr;
}

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_GetDestCtx(
    IAsyncRpcChannelBuffer * This,
    DWORD *                 pdwDestContext,
    void **                 ppvDestContext
    )
{
    return ChannelWrapper_GetDestCtx( (IRpcChannelBuffer3 *) This,
                                      pdwDestContext,
                                      ppvDestContext );
}



HRESULT STDMETHODCALLTYPE
ChannelWrapper_IsConnected
/*++

Routine Description:
    Determines if the channel is connected.

Arguments:

Return Value:
    S_TRUE
        S_FALSE

--*/
(
    IRpcChannelBuffer3 * This
)
{
    HRESULT             hr;
    IRpcChannelBuffer * pChannel;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    hr = pChannel->lpVtbl->IsConnected(pChannel);
    return hr;
}

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_IsConnected(
    IAsyncRpcChannelBuffer * This
    )
{
    return ChannelWrapper_IsConnected( (IRpcChannelBuffer3 *) This );
}


HRESULT STDMETHODCALLTYPE
ChannelWrapper_GetProtocolVersion
/*++

Routine Description:
    Returns the protocol version if available.

Arguments:

Return Value:
    S_OK
    E_NOINTERFACE
--*/
(
    IRpcChannelBuffer3 * This,
    DWORD             * pdwVersion
)
{
    HRESULT             hr;
    IRpcChannelBuffer  * pChannel;
    IRpcChannelBuffer2 * pChannel2;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    hr = pChannel->lpVtbl->QueryInterface(pChannel, IID_IRpcChannelBuffer2, (void**)&pChannel2);
    if (S_OK == hr)
    {
        hr = pChannel2->lpVtbl->GetProtocolVersion(pChannel2, pdwVersion);
        pChannel2->lpVtbl->Release(pChannel2);
    }
    return hr;
}

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_GetProtocolVersion(
    IAsyncRpcChannelBuffer * This,
    DWORD                  * pdwVersion
    )
{
    return ChannelWrapper_GetProtocolVersion( (IRpcChannelBuffer3 *) This,
                                              pdwVersion );
}


HRESULT STDMETHODCALLTYPE
ChannelWrapper_Send
/*++

Routine Description:
    Executes an asynchronous or partial send.

Arguments:

Return Value:
    S_OK
    E_NOINTERFACE
--*/
    (
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage,
    ULONG *             pStatus 
    )
{
    HRESULT              hr;
    IRpcChannelBuffer  * pChannel;
    IRpcChannelBuffer3 * pChannel3;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    hr = pChannel->lpVtbl->QueryInterface( pChannel, IID_IRpcChannelBuffer3, (void**)&pChannel3 );
    if (S_OK == hr)
    {
        hr = pChannel3->lpVtbl->Send(pChannel3, pMessage, pStatus);
        pChannel3->lpVtbl->Release(pChannel3);
    }
    return hr;
}

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_Send(
/*++

Routine Description:
    Executes an asynchronous or partial send.

Arguments:

Return Value:
    S_OK
    E_NOINTERFACE
--*/
    IAsyncRpcChannelBuffer * This,
    RPCOLEMESSAGE *         pMessage,
    ISynchronize *          pSynchronize,
    ULONG *                 pStatus 
    )
{
    HRESULT                  hr;
    IRpcChannelBuffer  *     pChannel;
    IAsyncRpcChannelBuffer * pAsChannel;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    hr = pChannel->lpVtbl->QueryInterface( pChannel, 
                                           IID_IAsyncRpcChannelBuffer, 
                                           (void**)&pAsChannel );
    if (S_OK == hr)
    {
        hr = pAsChannel->lpVtbl->Send( pAsChannel, 
                                       pMessage, 
                                       pSynchronize,
                                       pStatus);
        pAsChannel->lpVtbl->Release( pAsChannel);
    }
    return hr;
}


HRESULT STDMETHODCALLTYPE
ChannelWrapper_Receive
/*++

Routine Description:
    Executes an asynchronous or partial receive.

Arguments:

Return Value:
    S_OK
    E_NOINTERFACE
--*/
    (
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage,
    ULONG               ulSize,
    ULONG *             pStatus 
    )
{
    HRESULT              hr;
    IRpcChannelBuffer  * pChannel;
    IRpcChannelBuffer3 * pChannel3;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    hr = pChannel->lpVtbl->QueryInterface(pChannel, IID_IRpcChannelBuffer3, (void**)&pChannel3);
    if (S_OK == hr)
    {
        hr = pChannel3->lpVtbl->Receive( pChannel3, pMessage, ulSize, pStatus );
        pChannel3->lpVtbl->Release(pChannel3);
    }
    return hr;
}

HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_Receive(
/*++

Routine Description:
    Executes an asynchronous or partial receive.

Arguments:

Return Value:
    S_OK
    E_NOINTERFACE
--*/
    IAsyncRpcChannelBuffer * This,
    RPCOLEMESSAGE *     pMessage,
    ULONG *             pStatus 
    )
{
    HRESULT                 hr;
    IRpcChannelBuffer  *    pChannel;
    IAsyncRpcChannelBuffer *pAsChannel;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    hr = pChannel->lpVtbl->QueryInterface( pChannel, 
                                           IID_IAsyncRpcChannelBuffer, 
                                           (void**)&pAsChannel);
    if (S_OK == hr)
    {
        hr = pAsChannel->lpVtbl->Receive( pAsChannel, 
                                          pMessage, 
                                          pStatus );
        pAsChannel->lpVtbl->Release(pAsChannel);
    }
    return hr;
}


HRESULT STDMETHODCALLTYPE
ChannelWrapper_Cancel(
/*++

Routine Description:
    Executes an asynchronous Cancel.

Arguments:

Return Value:
    S_OK
    E_NOINTERFACE
--*/
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage
    )
{
    HRESULT              hr;
    IRpcChannelBuffer  * pChannel;
    IRpcChannelBuffer3 * pChannel3;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    hr = pChannel->lpVtbl->QueryInterface(pChannel, IID_IRpcChannelBuffer3, (void**)&pChannel3);
    if (S_OK == hr)
    {
        hr = pChannel3->lpVtbl->Cancel( pChannel3, pMessage );
        pChannel3->lpVtbl->Release(pChannel3);
    }
    return hr;
}


HRESULT STDMETHODCALLTYPE
ChannelWrapper_GetCallContext(
/*++

Routine Description:
    Gets an asynchronous call context.

Arguments:

Return Value:
    S_OK
    E_NOINTERFACE
--*/
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage,
    REFIID              riid,
    void    **          ppInterface
    )
{
    HRESULT              hr;
    IRpcChannelBuffer  * pChannel;
    IRpcChannelBuffer3 * pChannel3;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    hr = pChannel->lpVtbl->QueryInterface(pChannel, IID_IRpcChannelBuffer3, (void**)&pChannel3);
    if (S_OK == hr)
    {
        hr = pChannel3->lpVtbl->GetCallContext( pChannel3, pMessage, riid, ppInterface );
        pChannel3->lpVtbl->Release(pChannel3);
    }
    return hr;
}


HRESULT STDMETHODCALLTYPE
AsyncChannelWrapper_GetDestCtxEx(
/*++

Routine Description:
    Gets an asynchronous call context.

Arguments:

Return Value:
    S_OK
    E_NOINTERFACE
--*/
    IAsyncRpcChannelBuffer * This,
    RPCOLEMESSAGE *         pMessage,
    DWORD *                 pdw,
    void **                 ppv
    )
{
    HRESULT                     hr;
    IRpcChannelBuffer  *        pChannel;
    IAsyncRpcChannelBuffer *    pAsChannel;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    hr = pChannel->lpVtbl->QueryInterface( pChannel, 
                                           IID_IAsyncRpcChannelBuffer, 
                                           (void**)&pAsChannel);
    if (S_OK == hr)
    {
        hr = pAsChannel->lpVtbl->GetDestCtxEx( pAsChannel, 
                                               pMessage, 
                                               pdw, 
                                               ppv );
        pAsChannel->lpVtbl->Release(pAsChannel);
    }
    return hr;
}


HRESULT STDMETHODCALLTYPE
ChannelWrapper_GetDestCtxEx(
/*++

Routine Description:
    Gets the new destination context.

Arguments:

Return Value:
    S_OK
    E_NOINTERFACE
--*/
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage,
    DWORD *             pdwDestContext,
    void **             ppvDestContext
    )
{
    HRESULT              hr;
    IRpcChannelBuffer  * pChannel;
    IRpcChannelBuffer3 * pChannel3;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    hr = pChannel->lpVtbl->QueryInterface(pChannel, IID_IRpcChannelBuffer3, (void**)&pChannel3);
    if (S_OK == hr)
    {
        hr = pChannel3->lpVtbl->GetDestCtxEx( pChannel3, pMessage, pdwDestContext, ppvDestContext );
        pChannel3->lpVtbl->Release(pChannel3);
    }
    return hr;
}

HRESULT STDMETHODCALLTYPE
ChannelWrapper_GetState(
/*++

Routine Description:
    Gets the call state.

Arguments:

Return Value:
    S_OK
    E_NOINTERFACE
--*/
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage,
    DWORD         *     pState
    )
{
    HRESULT              hr;
    IRpcChannelBuffer  * pChannel;
    IRpcChannelBuffer3 * pChannel3;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    hr = pChannel->lpVtbl->QueryInterface(pChannel, IID_IRpcChannelBuffer3, (void**)&pChannel3);
    if (S_OK == hr)
    {
        hr = pChannel3->lpVtbl->GetState( pChannel3, pMessage, pState );
        pChannel3->lpVtbl->Release(pChannel3);
    }
    return hr;
}


HRESULT STDMETHODCALLTYPE
ChannelWrapper_RegisterAsync(
/*++

Routine Description:
    Registers the async manager object and call with the channel.

Arguments:

Return Value:
    S_OK
    E_NOINTERFACE
--*/
    IRpcChannelBuffer3 * This,
    RPCOLEMESSAGE *     pMessage,
    IAsyncManager *     pAsyncMgr
    )
{
    HRESULT              hr;
    IRpcChannelBuffer  * pChannel;
    IRpcChannelBuffer3 * pChannel3;

    pChannel = ((ChannelWrapper *)This)->pChannel;
    hr = pChannel->lpVtbl->QueryInterface(pChannel, IID_IRpcChannelBuffer3, (void**)&pChannel3);
    if (S_OK == hr)
    {
        hr = pChannel3->lpVtbl->RegisterAsync( pChannel3, pMessage, pAsyncMgr );
        pChannel3->lpVtbl->Release(pChannel3);
    }
    return hr;
}