/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Copyright (c) 1993-2000 Microsoft Corporation

Module Name :

    auxilary.c

Abstract :

    This file contains auxilary routines used for initialization of the
    RPC and stub messages and the offline batching of common code sequences
    needed by the stubs.

Author :

    David Kays  dkays   September 1993.

Revision History :

  ---------------------------------------------------------------------*/
#define _OLE32_
#include "ndrp.h"
#include "ndrole.h"
#include "ndrtypes.h"
#include "limits.h"
#include "interp.h"
#include "mulsyntx.h"
#include "pipendr.h"
#include "asyncndr.h"
#include "auxilary.h"

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    Static data for NS library operations
  ---------------------------------------------------------------------*/

int NsDllLoaded = 0;


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    OLE routines for interface pointer marshalling
  ---------------------------------------------------------------------*/

STDAPI NdrpCoCreateInstance(
    REFCLSID    rclsid,
    LPUNKNOWN   pUnkOuter,
    DWORD       dwClsContext, 
    REFIID      riid, 
    LPVOID *    ppv);

STDAPI NdrpCoReleaseMarshalData(
    IStream *pStm);

STDAPI NdrpDcomChannelSetHResult(
        PRPC_MESSAGE    pmsg,
        ULONG *         pulReserved,
        HRESULT         appsHR );

STDAPI NdrCoGetPSClsid(
    REFIID  iid,
    LPCLSID lpclsid);

HINSTANCE       hOle32 = 0;

RPC_GET_CLASS_OBJECT_ROUTINE        NdrCoGetClassObject;
RPC_GET_CLASS_OBJECT_ROUTINE     *  pfnCoGetClassObject = &NdrCoGetClassObject;

RPC_GET_MARSHAL_SIZE_MAX_ROUTINE    NdrCoGetMarshalSizeMax;
RPC_GET_MARSHAL_SIZE_MAX_ROUTINE *  pfnCoGetMarshalSizeMax = &NdrCoGetMarshalSizeMax;

RPC_MARSHAL_INTERFACE_ROUTINE       NdrCoMarshalInterface;
RPC_MARSHAL_INTERFACE_ROUTINE    *  pfnCoMarshalInterface = &NdrCoMarshalInterface;

RPC_UNMARSHAL_INTERFACE_ROUTINE     NdrCoUnmarshalInterface;
RPC_UNMARSHAL_INTERFACE_ROUTINE  *  pfnCoUnmarshalInterface = &NdrCoUnmarshalInterface;

RPC_STRING_FROM_IID                 OleStringFromIID;
RPC_STRING_FROM_IID              *  pfnStringFromIID = &OleStringFromIID;

RPC_GET_PS_CLSID                    NdrCoGetPSClsid;
RPC_GET_PS_CLSID                 *  pfnCoGetPSClsid = &NdrCoGetPSClsid;

RPC_CO_CREATE_INSTANCE              NdrpCoCreateInstance;
RPC_CO_CREATE_INSTANCE           *  pfnCoCreateInstance = &NdrpCoCreateInstance;

RPC_CLIENT_ALLOC                    NdrCoTaskMemAlloc;
RPC_CLIENT_ALLOC                 *  pfnCoTaskMemAlloc = &NdrCoTaskMemAlloc;

RPC_CLIENT_FREE                     NdrCoTaskMemFree;
RPC_CLIENT_FREE                  *  pfnCoTaskMemFree = &NdrCoTaskMemFree;

RPC_CO_RELEASEMARSHALDATA           NdrpCoReleaseMarshalData;
RPC_CO_RELEASEMARSHALDATA        *  pfnCoReleaseMarshalData = &NdrpCoReleaseMarshalData;

RPC_DCOMCHANNELSETHRESULT           NdrpDcomChannelSetHResult;
RPC_DCOMCHANNELSETHRESULT        *  pfnDcomChannelSetHResult = &NdrpDcomChannelSetHResult;

RPC_NS_GET_BUFFER_ROUTINE        pRpcNsGetBuffer;
RPC_NS_SEND_RECEIVE_ROUTINE      pRpcNsSendReceive;
RPC_NS_NEGOTIATETRANSFERSYNTAX_ROUTINE  pRpcNsNegotiateTransferSyntax;


HRESULT    NdrLoadOleRoutines()
{
    void * pTempRoutine;

    //Load ole32.dll
    if(hOle32 == 0)
    {
#ifdef DOSWIN32RPC
        hOle32 = LoadLibraryA("OLE32");
#else
        hOle32 = LoadLibraryW(L"OLE32");
#endif // DOSWIN32C
        if(hOle32 == 0)
            return HRESULT_FROM_WIN32(GetLastError());
    }

    pTempRoutine = GetProcAddress(hOle32, "CoGetClassObject");
    if(pTempRoutine == 0)
        return HRESULT_FROM_WIN32(GetLastError());
    else
        pfnCoGetClassObject = (RPC_GET_CLASS_OBJECT_ROUTINE*) pTempRoutine;

    pTempRoutine = GetProcAddress(hOle32, "CoGetMarshalSizeMax");
    if(pTempRoutine == 0)
        return HRESULT_FROM_WIN32(GetLastError());
    else
        pfnCoGetMarshalSizeMax = (RPC_GET_MARSHAL_SIZE_MAX_ROUTINE*) pTempRoutine;

    pTempRoutine = GetProcAddress(hOle32, "CoMarshalInterface");
    if(pTempRoutine == 0)
        return HRESULT_FROM_WIN32(GetLastError());
    else
        pfnCoMarshalInterface = (RPC_MARSHAL_INTERFACE_ROUTINE*) pTempRoutine;

    pTempRoutine = GetProcAddress(hOle32, "CoUnmarshalInterface");
    if(pTempRoutine == 0)
        return HRESULT_FROM_WIN32(GetLastError());
    else
        pfnCoUnmarshalInterface = (RPC_UNMARSHAL_INTERFACE_ROUTINE*) pTempRoutine;

    pTempRoutine = GetProcAddress(hOle32, "StringFromIID");
    if(pTempRoutine == 0)
        return HRESULT_FROM_WIN32(GetLastError());
    else
        pfnStringFromIID = (RPC_STRING_FROM_IID*) pTempRoutine;

    pTempRoutine = GetProcAddress(hOle32, "CoGetPSClsid");
    if(pTempRoutine == 0)
        return HRESULT_FROM_WIN32(GetLastError());
    else
        pfnCoGetPSClsid = (RPC_GET_PS_CLSID*) pTempRoutine;

    pTempRoutine = GetProcAddress(hOle32, "CoTaskMemAlloc");
    if(pTempRoutine == 0)
        return HRESULT_FROM_WIN32(GetLastError());
    else
        pfnCoTaskMemAlloc = (RPC_CLIENT_ALLOC*) pTempRoutine;

    pTempRoutine = GetProcAddress(hOle32, "CoTaskMemFree");
    if(pTempRoutine == 0)
        return HRESULT_FROM_WIN32(GetLastError());
    else
        pfnCoTaskMemFree = (RPC_CLIENT_FREE*) pTempRoutine;

    pTempRoutine = GetProcAddress(hOle32, "CoCreateInstance");
    if(pTempRoutine == 0)
        return HRESULT_FROM_WIN32(GetLastError());
    else
        pfnCoCreateInstance = (RPC_CO_CREATE_INSTANCE*) pTempRoutine;

    pTempRoutine = GetProcAddress(hOle32, "CoReleaseMarshalData");
    if(pTempRoutine == 0)
        return HRESULT_FROM_WIN32(GetLastError());
    else
        pfnCoReleaseMarshalData = (RPC_CO_RELEASEMARSHALDATA*) pTempRoutine;
    pTempRoutine = GetProcAddress(hOle32, "DcomChannelSetHResult");
    if(pTempRoutine == 0)
        return HRESULT_FROM_WIN32(GetLastError());
    else
        pfnDcomChannelSetHResult = (RPC_DCOMCHANNELSETHRESULT*) pTempRoutine;

    return( (HRESULT)0 );
}

HRESULT STDAPICALLTYPE
NdrCoGetClassObject(
    REFCLSID    rclsid,
    DWORD       dwClsContext,
    void       *pvReserved,
    REFIID      riid,
    void      **ppv)
/*++

Routine Description:
    Loads a class factory.  This function forwards the call to ole32.dll.

Arguments:
    rclsid          - Supplies the CLSID of the class to be loaded.
    dwClsContext    - Supplies the context in which to load the code.
    pvReserved      - Must be NULL.
    riid            - Supplies the IID of the desired interface.
    ppv             - Returns a pointer to the class factory.

Return Value:
    S_OK


--*/
{

    HRESULT hr;

    if ( FAILED(hr = NdrLoadOleRoutines()) )
        return hr;

    return (*pfnCoGetClassObject)(rclsid, dwClsContext, pvReserved, riid, ppv);
}

HRESULT STDAPICALLTYPE
NdrCoGetMarshalSizeMax(
    ULONG *     pulSize,
    REFIID      riid,
    LPUNKNOWN   pUnk,
    DWORD       dwDestContext,
    LPVOID      pvDestContext,
    DWORD       mshlflags)
/*++

Routine Description:
    Calculates the maximum size of a marshalled interface pointer.
    This function forwards the call to ole32.dll.

Arguments:
    pulSize         - Returns an upper bound for the size of a marshalled interface pointer.
    riid            - Supplies the IID of the interface to be marshalled.
    pUnk            - Supplies a pointer to the object to be marshalled.
    dwDestContext   - Supplies the destination of the marshalled interface pointer.
    pvDestContext
    mshlflags       - Flags.  See the MSHFLAGS enumeration.

Return Value:
    S_OK

--*/
{

    HRESULT hr;
    if ( FAILED(hr = NdrLoadOleRoutines()) )
        return hr;

    return (*pfnCoGetMarshalSizeMax)(pulSize, riid, pUnk, dwDestContext, pvDestContext, mshlflags);

}

RPC_STATUS
RPC_ENTRY
NdrGetDcomProtocolVersion(
    PMIDL_STUB_MESSAGE   pStubMsg,
    RPC_VERSION *        pVersion )
/*

    This is a helper routine for OLEAUT guys.
    It returns the actually negotiated protocol version for the connection,
    i.e. a "common denominator" - lower of the two.

*/
{
    HRESULT Hr = E_FAIL;

    if ( pStubMsg->pRpcChannelBuffer )
        {
        IRpcChannelBuffer2 * pBuffer2 = 0;

        Hr = ((IRpcChannelBuffer*)pStubMsg->pRpcChannelBuffer)->
                  QueryInterface( IID_IRpcChannelBuffer2,
                                  (void**) & pBuffer2 );
        if ( Hr == S_OK )
            {
            Hr = pBuffer2->GetProtocolVersion( (DWORD *) pVersion );
            pBuffer2->Release( );
            }
        }
    return Hr;
}

unsigned long
FixWireRepForDComVerGTE54(
    PMIDL_STUB_MESSAGE   pStubMsg )
/*
    Compares the current DCOM protocol version with the desired version ( 5.4 )
    Specific to interface pointer array and embedded conf struct wire rep fix.
*/
{
    if ( pStubMsg->pRpcChannelBuffer )
        {
        RPC_VERSION currRpcVersion = { 0, 0 };

        if ( SUCCEEDED ( NdrGetDcomProtocolVersion( pStubMsg, &currRpcVersion ) ) )
            {
            if ( currRpcVersion.MajorVersion > 5 )
                {
                return TRUE;
                }
            else
                {
                return currRpcVersion.MinorVersion >= 4;
                }
            }
        }
    return TRUE;
}

HRESULT STDAPICALLTYPE
NdrCoMarshalInterface(
    LPSTREAM    pStm,
    REFIID      riid,
    LPUNKNOWN   pUnk,
    DWORD       dwDestContext,
    LPVOID      pvDestContext,
    DWORD       mshlflags)
/*++

Routine Description:
    Marshals an interface pointer.
    This function forwards the call to ole32.dll.

Arguments:
    pStm            - Supplies the target stream.
    riid            - Supplies the IID of the interface to be marshalled.
    pUnk            - Supplies a pointer to the object to be marshalled.
    dwDestContext   - Specifies the destination context
    pvDestContext
    mshlflags       - Flags.  See the MSHFLAGS enumeration.

Return Value:
    S_OK

--*/
{
    HRESULT hr;
    if ( FAILED(hr = NdrLoadOleRoutines()) )
        return hr;

    return (*pfnCoMarshalInterface)(pStm, riid, pUnk, dwDestContext, pvDestContext, mshlflags);
}

HRESULT STDAPICALLTYPE
NdrCoUnmarshalInterface(
    LPSTREAM    pStm,
    REFIID      riid,
    void **     ppv)
/*++

Routine Description:
    Unmarshals an interface pointer from a stream.
    This function forwards the call to ole32.dll.

Arguments:
    pStm    - Supplies the stream containing the marshalled interface pointer.
    riid    - Supplies the IID of the interface pointer to be unmarshalled.
    ppv     - Returns the unmarshalled interface pointer.

Return Value:
    S_OK

--*/
{
    HRESULT hr;
    if ( FAILED(hr = NdrLoadOleRoutines()) )
        return hr;

    return (*pfnCoUnmarshalInterface)(pStm, riid, ppv);
}

STDAPI NdrpCoCreateInstance(
    REFCLSID    rclsid,
    LPUNKNOWN   pUnkOuter,
    DWORD       dwClsContext, 
    REFIID      riid, 
    LPVOID *    ppv)
{
    HRESULT hr;
    if ( FAILED(hr = NdrLoadOleRoutines()) )
        return hr;

    return (*pfnCoCreateInstance) (rclsid, pUnkOuter, dwClsContext, riid, ppv );
}

STDAPI NdrpCoReleaseMarshalData(
    IStream *pStm)
{
    HRESULT hr;
    if ( FAILED(hr = NdrLoadOleRoutines()) )
        return hr;

    return (*pfnCoReleaseMarshalData) (pStm );
}

STDAPI NdrpDcomChannelSetHResult(
        PRPC_MESSAGE    pmsg,
        ULONG *         pulReserved,
        HRESULT         appsHR )
{
    HRESULT hr;

    if ( FAILED(hr = NdrLoadOleRoutines()) )
        return hr;

    return (*pfnDcomChannelSetHResult)( pmsg, pulReserved, appsHR );
}


HRESULT STDAPICALLTYPE OleStringFromIID(
    REFIID rclsid,
    LPOLESTR FAR* lplpsz)
/*++

Routine Description:
    Converts an IID into a string.
    This function forwards the call to ole32.dll.

Arguments:
    rclsid  - Supplies the clsid to convert to string form.
    lplpsz  - Returns the string form of the clsid (with "{}" around it).

Return Value:
    S_OK

--*/
{
    HRESULT hr;
    
    if ( FAILED(hr = NdrLoadOleRoutines()) )
        return hr;

    return (*pfnStringFromIID)(rclsid, lplpsz);
}

STDAPI NdrCoGetPSClsid(
    REFIID  iid,
    LPCLSID lpclsid)
/*++

Routine Description:
    Converts an IID into a string.
    This function forwards the call to ole32.dll.

Arguments:
    rclsid  - Supplies the clsid to convert to string form.
    lplpsz  - Returns the string form of the clsid (with "{}" around it).

Return Value:
    S_OK

--*/
{
    
    HRESULT hr;
    if ( FAILED(hr = NdrLoadOleRoutines()) )
        return hr;

    return (*pfnCoGetPSClsid)(iid, lpclsid);
}


void * STDAPICALLTYPE
NdrCoTaskMemAlloc(
    size_t cb)
/*++

Routine Description:
    Allocate memory using OLE task memory allocator.
    This function forwards the call to ole32.dll.

Arguments:
    cb - Specifies the amount of memory to be allocated.

Return Value:
    This function returns a pointer to the allocated memory.
    If an error occurs, this function returns zero.

--*/
{
    if ( FAILED(NdrLoadOleRoutines()) )
        return 0;

    return (*pfnCoTaskMemAlloc)(cb);
}

void STDAPICALLTYPE
NdrCoTaskMemFree(
    void * pMemory)
/*++

Routine Description:
    Free memory using OLE task memory allocator.
    This function forwards the call to ole32.dll.

Arguments:
    pMemory - Supplies a pointer to the memory to be freed.

Return Value:
    None.

--*/
{
    if ( FAILED(NdrLoadOleRoutines()) )
        return;

   (*pfnCoTaskMemFree)(pMemory);
}


void * RPC_ENTRY NdrOleAllocate(size_t size)
/*++

Routine Description:
    Allocate memory via OLE task allocator.

Arguments:
    size - Specifies the amount of memory to be allocated.

Return Value:
    This function returns a pointer to the allocated memory.
    If an error occurs, this function raises an exception.

--*/
{
    void *pMemory;

    pMemory = (*pfnCoTaskMemAlloc)(size);

    if(pMemory == 0)
        RpcRaiseException(E_OUTOFMEMORY);

    return pMemory;
}

void RPC_ENTRY NdrOleFree(void *pMemory)
/*++

Routine Description:
    Free memory using OLE task allocator.

Arguments:
    None.

Return Value:
    None.

--*/
{
    (*pfnCoTaskMemFree)(pMemory);
}


HRESULT STDAPICALLTYPE NdrStringFromIID(
    REFIID rclsid,
    char * lpsz)
/*++

Routine Description:
    Converts an IID into a string.
    This function forwards the call to ole32.dll.

Arguments:
    rclsid  - Supplies the clsid to convert to string form.
    lplpsz  - Returns the string form of the clsid (with "{}" around it).

Return Value:
    S_OK

--*/
{
    HRESULT   hr;
    wchar_t * olestr;

    hr = (*pfnStringFromIID)(rclsid, &olestr);

    if(SUCCEEDED(hr))
    {
        WideCharToMultiByte(CP_ACP,
                            0,
                            (LPCWSTR)olestr,
                            -1,
                            (LPSTR)lpsz,
                            50,
                            NULL,
                            NULL);
        NdrOleFree(olestr);
    }

    return hr;
}


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

Routine Description :

    This routine is called by client side stubs to initialize the RPC message
    and stub message, and to get the RPC buffer.

Arguments :

    pRpcMsg            - pointer to RPC message structure
    pStubMsg        - pointer to stub message structure
    pStubDescriptor    - pointer to stub descriptor structure
    HandleType        - type of binding handle
    ProcNum            - remote procedure number

--*/
{
    NdrClientInitialize( pRpcMsg,
                         pStubMsg,
                         pStubDescriptor,
                         ProcNum );

    if ( pStubDescriptor->pMallocFreeStruct )
        {
        MALLOC_FREE_STRUCT *pMFS = pStubDescriptor->pMallocFreeStruct;

        NdrpSetRpcSsDefaults(pMFS->pfnAllocate, pMFS->pfnFree);
        }

    // This exception should be raised after initializing StubMsg.

    if ( pStubDescriptor->Version > NDR_VERSION )
        {
        NDR_ASSERT( 0, "ClientInitialize : Bad version number" );

        RpcRaiseException( RPC_X_WRONG_STUB_VERSION );
        }

    //
    // This is where we initialize fields behind the NT3.5 - NT5.0 field set.
    //
#ifdef _CS_CHAR_
    if ( NDR_VERSION_6_0 <= pStubDescriptor->Version )
        {
        pStubMsg->pCSInfo = 0;
        }
#endif // _CS_CHAR_
}

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

Routine Description :

    This routine is called by client side stubs to initialize the RPC message
    and stub message, and to get the RPC buffer.

Arguments :

    pRpcMsg          - pointer to RPC message structure
    pStubMsg         - pointer to stub message structure
    pStubDescriptor  - pointer to stub descriptor structure
    ProcNum          - remote procedure number
    
Notes:

    This routine has to be backward compatible with the old binaries built from
    -Os stubs. In particular, it cannot touch StubMsg fields outside of 
    the NT3.5 - NT5.0 field set, i.e. set of fields present since NT3.5 release.

--*/
{
    //
    // Initialize RPC message fields.
    //
    // The leftmost bit of the procnum field is supposed to be set to 1 inr
    // order for the runtime to know if it is talking to the older stubs or
    // not.
    //

    pRpcMsg->RpcInterfaceInformation = pStubDescriptor->RpcInterfaceInformation;
//#if !defined(__RPC_WIN64__)
    
    pRpcMsg->ProcNum = ProcNum | RPC_FLAGS_VALID_BIT;
//#endif     
    pRpcMsg->RpcFlags = 0;
    pRpcMsg->Handle = 0;

    //
    // Initialize the Stub messsage fields.
    //

    pStubMsg->RpcMsg = pRpcMsg;

    pStubMsg->StubDesc = pStubDescriptor;

    pStubMsg->pfnAllocate = pStubDescriptor->pfnAllocate;
    pStubMsg->pfnFree     = pStubDescriptor->pfnFree;

    pStubMsg->fInDontFree       = 0;
    pStubMsg->fDontCallFreeInst = 0;
    pStubMsg->fInOnlyParam      = 0;
    pStubMsg->fHasReturn        = 0;
    pStubMsg->fHasExtensions    = 0;
    pStubMsg->fHasNewCorrDesc   = 0;
    pStubMsg->fUnused           = 0;

    pStubMsg->IsClient = TRUE;

    pStubMsg->BufferLength = 0;
    pStubMsg->BufferStart = 0;
    pStubMsg->BufferEnd = 0;
    pStubMsg->uFlags    = 0;

    pStubMsg->fBufferValid = FALSE;
    pStubMsg->ReuseBuffer = FALSE;

    pStubMsg->StackTop = 0;

    pStubMsg->IgnoreEmbeddedPointers = FALSE;
    pStubMsg->PointerBufferMark = 0;
    pStubMsg->pAllocAllNodesContext = 0;
    pStubMsg->pPointerQueueState = 0;

    pStubMsg->FullPtrRefId = 0;
    pStubMsg->PointerLength = 0;

    pStubMsg->dwDestContext = MSHCTX_DIFFERENTMACHINE;
    pStubMsg->pvDestContext = 0;
    pStubMsg->pRpcChannelBuffer = 0;

    pStubMsg->pArrayInfo = 0;

    pStubMsg->dwStubPhase = 0;

    NdrSetupLowStackMark( pStubMsg );
    pStubMsg->pAsyncMsg = 0;
    pStubMsg->pCorrInfo = 0;
    pStubMsg->pCorrMemory = 0;
    pStubMsg->pMemoryList = 0;
}


void
MakeSureWeHaveNonPipeArgs(
    PMIDL_STUB_MESSAGE  pStubMsg,
    unsigned long       BufferSize )
/*

Routine description:

    This routine is called for pipe calls at the server.
    After the runtime dispatched to the stub with the first packet,
    it makes sure that we have a portion of the buffer big enough
    to keep all the non-pipe args.

Arguments:

    BufferSize - a pipe call: addtional number of bytes over what we have.

Note:

    The buffer location may change from before to after the call.

*/
{
    RPC_STATUS      Status;
    PRPC_MESSAGE    pRpcMsg = pStubMsg->RpcMsg;

    if ( !(pRpcMsg->RpcFlags & RPC_BUFFER_COMPLETE ) )
        {
        // May be the args fit into the first packet.

        if ( BufferSize <= pRpcMsg->BufferLength )
            return;

        // Set the partial flag to get the non-pipe args.
        // For a partial call with the "extra", the meaning of the size
        // arg is the addition required above what we have already.

        pRpcMsg->RpcFlags |= (RPC_BUFFER_PARTIAL |  RPC_BUFFER_EXTRA);

        // We will receive at least BufferSize.
        // (buffer location may change)

        BufferSize -= pRpcMsg->BufferLength;

        Status = I_RpcReceive( pRpcMsg, (unsigned int) BufferSize );

        if ( Status != RPC_S_OK )
            {
            // Note, that for this particular error case, i.e. non-pipe
            // data receive failing, we don't want to restore the 
            // original dispatch buffer into the rpc message.
            // In case of an error the buffer coming back here would be 0.
            //
            RpcRaiseException( Status );
            }

        NDR_ASSERT( 0 == BufferSize ||
                    NULL != pRpcMsg->Buffer,
                    "Rpc runtime returned an invalid buffer.");

        // In case this is a new buffer

        pStubMsg->Buffer      = (uchar*)pRpcMsg->Buffer;
        pStubMsg->BufferStart = (uchar*)pRpcMsg->Buffer;
        pStubMsg->BufferEnd   = pStubMsg->BufferStart + pRpcMsg->BufferLength;
        }
}


unsigned char * RPC_ENTRY
NdrServerInitializeNew(
    PRPC_MESSAGE            pRpcMsg,
    PMIDL_STUB_MESSAGE      pStubMsg,
    PMIDL_STUB_DESC         pStubDescriptor
    )
/*++

Routine Description :

    This routine is called by the server stubs before unmarshalling.
    It initializes the stub message fields.

Aruguments :

    pStubMsg        - pointer to the stub message structure
    pStubDescriptor - pointer to the stub descriptor structure

Note.
    NdrServerInitializeNew is almost identical to NdrServerInitializePartial.
    NdrServerInitializeNew is generated for non-pipes and is backward comp.
    NdrServerInitializePartial is generated for routines with pipes args.

--*/
{
    NdrServerInitialize( pRpcMsg,
                         pStubMsg,
                         pStubDescriptor );

    if ( pStubDescriptor->pMallocFreeStruct )
        {
        MALLOC_FREE_STRUCT *pMFS = pStubDescriptor->pMallocFreeStruct;

        NdrpSetRpcSsDefaults(pMFS->pfnAllocate, pMFS->pfnFree);
        }

    // This exception should be raised after initializing StubMsg.

    if ( pStubDescriptor->Version > NDR_VERSION )
        {
        NDR_ASSERT( 0, "ServerInitializeNew : bad version number" );

        RpcRaiseException( RPC_X_WRONG_STUB_VERSION );
        }

    //
    // This is where we initialize fields behind the NT3.5 - NT5.0 field set.
    //
#ifdef _CS_CHAR_
    if ( NDR_VERSION_6_0 <= pStubDescriptor->Version )
        {
        pStubMsg->pCSInfo = 0;
        }
#endif // _CS_CHAR_
    if ( !(pRpcMsg->RpcFlags & RPC_BUFFER_COMPLETE ) )
        {
        // A non-pipe call with an incomplete buffer.
        // This can happen only for non-pipe calls in an interface that
        // has some pipe calls. 

        RPC_STATUS Status;

        pRpcMsg->RpcFlags = RPC_BUFFER_EXTRA;

        // The size argument is ignored, we will get everything.

        Status = I_RpcReceive( pRpcMsg, 0 );

        if ( Status != RPC_S_OK )
            {
            // This is the same behavior (and comment) as in MakeSure..
            //    routine above for non-pipe data case in a pipe call.
            // For this particular error case, i.e. a call to Receive to get 
            // all (non-pipe) data failing, we don't want to restore the 
            // original dispatch buffer into the rpc message.
            // In case of an error the buffer coming back here would be 0.
            //
            RpcRaiseException( Status );
            }

        NDR_ASSERT( 0 == pRpcMsg->BufferLength ||
                    NULL != pRpcMsg->Buffer,
                    "Rpc runtime returned an invalid buffer.");

        // In case this is a new buffer

        pStubMsg->Buffer      = (uchar*)pRpcMsg->Buffer;
        pStubMsg->BufferStart = (uchar*)pRpcMsg->Buffer;
        pStubMsg->BufferEnd   = pStubMsg->BufferStart + pRpcMsg->BufferLength;
        }

    return 0;
}

unsigned char * RPC_ENTRY
NdrServerInitialize(
    PRPC_MESSAGE            pRpcMsg,
    PMIDL_STUB_MESSAGE      pStubMsg,
    PMIDL_STUB_DESC         pStubDescriptor )
/*++

Routine Description :

    This routine is called by the server stubs before unmarshalling.
    It initializes the stub message fields.

Aruguments :

    pStubMsg        - pointer to the stub message structure
    pStubDescriptor - pointer to the stub descriptor structure

Note :

    This is a core server-side initializer, called by everybody.
    
    This routine has to be backward compatible with the old binaries built from
    -Os stubs. In particular, it cannot touch StubMsg fields outside of 
    the NT3.5 - NT5.0 field set, i.e. set of fields present since NT3.5 release.

--*/
{
    pStubMsg->IsClient = FALSE;
    pStubMsg->pAllocAllNodesContext = 0;
    pStubMsg->pPointerQueueState = 0;
    pStubMsg->IgnoreEmbeddedPointers = FALSE;
    pStubMsg->PointerBufferMark = 0;
    pStubMsg->BufferLength = 0;
    pStubMsg->StackTop = 0;

    pStubMsg->FullPtrXlatTables = 0;
    pStubMsg->FullPtrRefId = 0;
    pStubMsg->PointerLength = 0;

    pStubMsg->fDontCallFreeInst = 0;
    pStubMsg->fInDontFree       = 0;
    pStubMsg->fInOnlyParam      = 0;
    pStubMsg->fHasReturn        = 0;
    pStubMsg->fHasExtensions    = 0;
    pStubMsg->fHasNewCorrDesc   = 0;
    pStubMsg->fUnused           = 0;

    pStubMsg->dwDestContext = MSHCTX_DIFFERENTMACHINE;
    pStubMsg->pvDestContext = 0;
    pStubMsg->pRpcChannelBuffer = 0;

    pStubMsg->pArrayInfo = 0;

    pStubMsg->RpcMsg = pRpcMsg;
    pStubMsg->Buffer = (uchar*)pRpcMsg->Buffer;

    //
    // Set BufferStart and BufferEnd before unmarshalling.
    // NdrPointerFree uses these values to detect pointers into the
    // rpc message buffer.
    //
    pStubMsg->BufferStart = (uchar*)pRpcMsg->Buffer;
    pStubMsg->BufferEnd   = pStubMsg->BufferStart + pRpcMsg->BufferLength;
    pStubMsg->uFlags      = 0;

    pStubMsg->pfnAllocate = pStubDescriptor->pfnAllocate;
    pStubMsg->pfnFree     = pStubDescriptor->pfnFree;

    pStubMsg->StubDesc = pStubDescriptor;
    pStubMsg->ReuseBuffer = FALSE;

    pStubMsg->dwStubPhase = 0;

    NdrSetupLowStackMark( pStubMsg );
    pStubMsg->pAsyncMsg = 0;
    pStubMsg->pCorrInfo = 0;
    pStubMsg->pCorrMemory = 0;
    pStubMsg->pMemoryList = 0;

    NdrRpcSetNDRSlot( pStubMsg );
    return(0);
}

void RPC_ENTRY
NdrServerInitializePartial(
    PRPC_MESSAGE            pRpcMsg,
    PMIDL_STUB_MESSAGE      pStubMsg,
    PMIDL_STUB_DESC         pStubDescriptor,
    unsigned long           RequestedBufferSize )
/*++

Routine Description :

    This routine is called by the server stubs for pipes.
    It is almost identical to NdrServerInitializeNew, except that
    it calls NdrpServerInitialize.

Aruguments :

    pStubMsg        - pointer to the stub message structure
    pStubDescriptor - pointer to the stub descriptor structure
    pBuffer         - pointer to the beginning of the RPC message buffer

--*/
{
    NdrServerInitialize( pRpcMsg,
                         pStubMsg,
                         pStubDescriptor );

    if ( pStubDescriptor->pMallocFreeStruct )
        {
        MALLOC_FREE_STRUCT *pMFS = pStubDescriptor->pMallocFreeStruct;

        NdrpSetRpcSsDefaults(pMFS->pfnAllocate, pMFS->pfnFree);
        }

    // This exception should be raised after initializing StubMsg.

    if ( pStubDescriptor->Version > NDR_VERSION )
        {
        NDR_ASSERT( 0, "ServerInitializePartial : bad version number" );

        RpcRaiseException( RPC_X_WRONG_STUB_VERSION );
        }

    //
    // This is where we initialize fields behind the NT3.5 - NT5.0 field set.
    //
#ifdef _CS_CHAR_
    if ( NDR_VERSION_6_0 <= pStubDescriptor->Version )
        {
        pStubMsg->pCSInfo = 0;
        }
#endif _CS_CHAR_    
    // Last but not least...

    MakeSureWeHaveNonPipeArgs( pStubMsg, RequestedBufferSize );
}


unsigned char * RPC_ENTRY
NdrGetBuffer(
    PMIDL_STUB_MESSAGE      pStubMsg,
    unsigned long           BufferLength,
    RPC_BINDING_HANDLE      Handle )
/*++

Routine Description :

    Performs an RpcGetBuffer.

Arguments :

    pStubMsg        - Pointer to stub message structure.
    BufferLength    - Length of requested rpc message buffer.
    Handle          - Bound handle.

--*/
{
    RPC_STATUS    Status;

    if ( pStubMsg->IsClient )
        pStubMsg->RpcMsg->Handle = pStubMsg->SavedHandle = Handle;

    pStubMsg->RpcMsg->BufferLength = BufferLength;

    Status = I_RpcGetBuffer( pStubMsg->RpcMsg );

    if ( Status )
        {
        // For raw rpc, if async, don't call abort later.

        if ( pStubMsg->pAsyncMsg )
            pStubMsg->pAsyncMsg->Flags.RuntimeCleanedUp = 1;

        RpcRaiseException( Status );
        }

    NDR_ASSERT( 0 == BufferLength ||
                NULL != pStubMsg->RpcMsg->Buffer,
                "Rpc runtime returned an invalid buffer.");

    NDR_ASSERT( ! ((ULONG_PTR)pStubMsg->RpcMsg->Buffer & 0x7),
                "marshaling buffer misaligned" );

    pStubMsg->Buffer = (uchar *) pStubMsg->RpcMsg->Buffer;
    pStubMsg->fBufferValid = TRUE;

    return pStubMsg->Buffer;
}


void
EnsureNSLoaded()
/*++

Routine Description :

    Guarantee that the RpcNs4 DLL is loaded.  Throw exception if unable
    to load it.
    Will load the RpcNs4 DLL if not already loaded

Arguments :


--*/
{
    HINSTANCE   DllHandle;
    LPSTR       EntryName;


    if ( NsDllLoaded )
        return;

#ifdef DOSWIN32RPC
    DllHandle    = LoadLibraryA( "RPCNS4" );
#else
    DllHandle    = LoadLibraryW( L"RPCNS4" );
#endif // DOSWIN32RPC

    if ( DllHandle == 0 )
        {
        RpcRaiseException (RPC_S_INVALID_BINDING);
        }

    EntryName = "I_RpcNsGetBuffer";


    pRpcNsGetBuffer = (RPC_NS_GET_BUFFER_ROUTINE)
                      GetProcAddress( DllHandle,
                                      EntryName);

    if ( pRpcNsGetBuffer == 0 )
        {
        RpcRaiseException (RPC_S_INVALID_BINDING);
        }

    EntryName = "I_RpcNsSendReceive";


    pRpcNsSendReceive = (RPC_NS_SEND_RECEIVE_ROUTINE)
                        GetProcAddress( DllHandle,
                                        EntryName);

    if ( pRpcNsSendReceive == 0 )
        {
        RpcRaiseException (RPC_S_INVALID_BINDING);
        }


    EntryName = "I_RpcNsNegotiateTransferSyntax";
    pRpcNsNegotiateTransferSyntax = ( RPC_NS_NEGOTIATETRANSFERSYNTAX_ROUTINE )
                                    GetProcAddress( DllHandle,
                                                    EntryName );
                                                    
    if ( pRpcNsNegotiateTransferSyntax == 0 )
        {
        RpcRaiseException (RPC_S_INVALID_BINDING);
        }

    NsDllLoaded = 1;
}


unsigned char * RPC_ENTRY
NdrNsGetBuffer( PMIDL_STUB_MESSAGE    pStubMsg,
                unsigned long         BufferLength,
                RPC_BINDING_HANDLE    Handle )
/*++

Routine Description :

    Performs an RpcNsGetBuffer.
    Will load the RpcNs4 DLL if not already loaded

Arguments :

    pStubMsg        - Pointer to stub message structure.
    BufferLength    - Length of requested rpc message buffer.
    Handle          - Bound handle

--*/
{
    RPC_STATUS    Status;

    if( pStubMsg->IsClient == TRUE )
        pStubMsg->RpcMsg->Handle = pStubMsg->SavedHandle = Handle;

    EnsureNSLoaded();

    pStubMsg->RpcMsg->BufferLength = BufferLength;

    Status = (*pRpcNsGetBuffer)( pStubMsg->RpcMsg );

    if ( Status )
        RpcRaiseException( Status );

    NDR_ASSERT( ! ((ULONG_PTR)pStubMsg->RpcMsg->Buffer & 0x7),
                "marshaling buffer misaligned" );

    pStubMsg->Buffer = (uchar *) pStubMsg->RpcMsg->Buffer;
    pStubMsg->fBufferValid = TRUE;

    return pStubMsg->Buffer;
}

unsigned char * RPC_ENTRY
NdrSendReceive(
    PMIDL_STUB_MESSAGE  pStubMsg,
    uchar *             pBufferEnd )
/*++

Routine Description :

    Performs an RpcSendRecieve.
    This routine is executed for the non-pipe calls only.
    It returns a whole marshaling buffer.

Arguments :

    pStubMsg    - Pointer to stub message structure.
    pBufferEnd  - End of the rpc message buffer being sent.

Return :

    The new message buffer pointer returned from the runtime after the
    SendReceive call to the server.

--*/
{
    RPC_STATUS      Status;
    PRPC_MESSAGE    pRpcMsg;

    pRpcMsg = pStubMsg->RpcMsg;

    if ( pRpcMsg->BufferLength <
                    (uint)(pBufferEnd - (uchar *)pRpcMsg->Buffer))
        {
        NDR_ASSERT( 0, "NdrSendReceive : buffer overflow" );
        RpcRaiseException( RPC_S_INTERNAL_ERROR );
        }

    pRpcMsg->BufferLength = (ulong)(pBufferEnd - (uchar *)pRpcMsg->Buffer);

    pStubMsg->fBufferValid = FALSE;

    Status = I_RpcSendReceive( pRpcMsg );

    if ( Status )
        RpcRaiseException(Status);

    NDR_ASSERT( 0 == pRpcMsg->BufferLength ||
                NULL != pRpcMsg->Buffer,
                "Rpc runtime returned an invalid buffer.");  

    NDR_ASSERT( ! ((ULONG_PTR)pRpcMsg->Buffer & 0x7),
                "marshaling buffer misaligned" );

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

    return 0;
}


unsigned char * RPC_ENTRY
NdrNsSendReceive(
    PMIDL_STUB_MESSAGE      pStubMsg,
    uchar *                 pBufferEnd,
    RPC_BINDING_HANDLE *    pAutoHandle )
/*++

Routine Description :

    Performs an RpcNsSendRecieve for a procedure which uses an auto handle.
    Will load the RpcNs4 DLL if not already loaded

Arguments :

    pStubMsg    - Pointer to stub message structure.
    pBufferEnd  - End of the rpc message buffer being sent.
    pAutoHandle - Pointer to the auto handle used in the call.

Return :

    The new message buffer pointer returned from the runtime after the
    SendReceive call to the server.

--*/
{
    RPC_STATUS      Status;
    PRPC_MESSAGE    pRpcMsg;

    EnsureNSLoaded();

    pRpcMsg = pStubMsg->RpcMsg;

    if ( pRpcMsg->BufferLength <
                    (uint)(pBufferEnd - (uchar *)pRpcMsg->Buffer) )
        {
        NDR_ASSERT( 0, "NdrNsSendReceive : buffer overflow" );
        RpcRaiseException( RPC_S_INTERNAL_ERROR );
        }

    pRpcMsg->BufferLength = (ulong)(pBufferEnd - (uchar *)pRpcMsg->Buffer);

    pStubMsg->fBufferValid = FALSE;

    Status = (*pRpcNsSendReceive)( pRpcMsg, pAutoHandle );

    if ( Status )
        RpcRaiseException(Status);

    pStubMsg->SavedHandle = *pAutoHandle;

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

    return pStubMsg->Buffer;
}

void RPC_ENTRY
NdrFreeBuffer(
    PMIDL_STUB_MESSAGE pStubMsg )
/*++

Routine Description :

    Performs an RpcFreeBuffer.

Arguments :

    pStubMsg    - pointer to stub message structure

Return :

    None.

--*/
{
    RPC_STATUS    Status;

    if ( ! pStubMsg->fBufferValid )
        return;

    if( ! pStubMsg->RpcMsg->Handle )
        return;

    Status = I_RpcFreeBuffer( pStubMsg->RpcMsg );

    pStubMsg->fBufferValid = FALSE;

    if ( Status )
        RpcRaiseException(Status);
}

void *  RPC_ENTRY
NdrAllocate(
    PMIDL_STUB_MESSAGE  pStubMsg,
    size_t              Len )
/*++

Routine Description :

    Private allocator.  Handles allocate all nodes cases.

Arguments :

    pStubMsg    - Pointer to stub message structure.
    Len         - Number of bytes to allocate.

Return :

    Valid memory pointer.

--*/
{
    void * pMemory;

    if ( pStubMsg->pAllocAllNodesContext )
        {
        //
        // We must guarantee 4 byte alignment on NT and MAC.
        //
#if defined(__RPC_WIN64__)
        ALIGN(pStubMsg->pAllocAllNodesContext->AllocAllNodesMemory,7);
#else
        ALIGN(pStubMsg->pAllocAllNodesContext->AllocAllNodesMemory,3);
#endif

        // Get the pointer.
        pMemory = pStubMsg->pAllocAllNodesContext->AllocAllNodesMemory;

        // Increment the block pointer.
        pStubMsg->pAllocAllNodesContext->AllocAllNodesMemory += Len;

        //
        // Check for memory allocs past the end of our allocated buffer.
        //
        if ( pStubMsg->pAllocAllNodesContext->AllocAllNodesMemoryEnd < 
             pStubMsg->pAllocAllNodesContext->AllocAllNodesMemory )
            {
            NDR_ASSERT( pStubMsg->pAllocAllNodesContext->AllocAllNodesMemory <=
                        pStubMsg->pAllocAllNodesContext->AllocAllNodesMemoryEnd,
                        "Not enough alloc all nodes memory!" );
            RpcRaiseException( RPC_S_INTERNAL_ERROR );
            }

        return pMemory;
        }
    else
        {
        size_t NodeOffset, FullSize;
        PNDR_MEMORY_LIST_TAIL_NODE pMemoryList;

        // Add linked list node to tail of allocation. Ensure that the tail
        // is at a 8 byte alignment so that the same code will work in 64bits.
        NodeOffset = Len;

        LENGTH_ALIGN(NodeOffset, 7); 
        
        FullSize = NodeOffset + sizeof(NDR_MEMORY_LIST_TAIL_NODE);

        if ( ! (pMemory = (*pStubMsg->pfnAllocate)( FullSize )) )
            RpcRaiseException( RPC_S_OUT_OF_MEMORY );

        pMemoryList = (PNDR_MEMORY_LIST_TAIL_NODE)((char *)pMemory + NodeOffset);

        pMemoryList->Signature = NDR_MEMORY_LIST_SIGNATURE;
        pMemoryList->pMemoryHead = pMemory;
        pMemoryList->pNextNode = (PNDR_MEMORY_LIST_TAIL_NODE)pStubMsg->pMemoryList;
        pStubMsg->pMemoryList =  pMemoryList; 

        return pMemory;
        }
}

void
NdrpFreeMemoryList(
    MIDL_STUB_MESSAGE *     pStubMsg)
/*++

Routine Description :

    Freeing the list of memory allocated by NdrAllocate.

Arguments :

    pStubMsg    - Pointer to stub message structure.

Return :

    None.

--*/
{
  RpcTryExcept
      {
         while(pStubMsg->pMemoryList) 
              {
              PNDR_MEMORY_LIST_TAIL_NODE pMemoryList = 
                  (PNDR_MEMORY_LIST_TAIL_NODE)pStubMsg->pMemoryList;

              if (pMemoryList->Signature != NDR_MEMORY_LIST_SIGNATURE) 
                 {
                 NDR_ASSERT( 0 , "bad rpc allocated memory signature" );
                 return;
                 }

              pStubMsg->pMemoryList = pMemoryList->pNextNode;
              (*pStubMsg->pfnFree)(pMemoryList->pMemoryHead); 
              }
      }
  RpcExcept(1)
      {
         // Something is wrong and perhaps memory has been corrupted.   If this happens,
         // just ignore the exception and stop freeing memory.   This will duplicate the 
         // behavior of NDR without the linked list.

      }
  RpcEndExcept
}
    

unsigned char * RPC_ENTRY
NdrServerInitializeUnmarshall (
    PMIDL_STUB_MESSAGE      pStubMsg,
    PMIDL_STUB_DESC         pStubDescriptor,
    PRPC_MESSAGE            pRpcMsg )
/*++

Routine Description :

    Old NT Beta2 (build 683) server stub initialization routine.  Used for
    backward compatability only.

Aruguments :

    pStubMsg        - Pointer to the stub message structure.
    pStubDescriptor    - Pointer to the stub descriptor structure.
    pBuffer            - Pointer to the beginning of the RPC message buffer.

--*/
{
    return NdrServerInitialize( pRpcMsg,
                                pStubMsg,
                                pStubDescriptor );
}

void RPC_ENTRY
NdrServerInitializeMarshall (
    PRPC_MESSAGE        pRpcMsg,
    PMIDL_STUB_MESSAGE  pStubMsg )
/*++

Routine Description :

    Old NT Beta2 (build 683) server stub initialization routine.  Used for
    backward compatability only.

Arguments :

    pRpcMsg         - Pointer to the RPC message structure.
    pStubMsg        - Pointer to the stub message structure.

--*/
{
}

//
// Functions to simulate a alloca across a function call.
// Note that this code is optimized for simplicity and speed.  It does 
// not attempt to search a list on each allocation to reuse partially full
// blocks as much as it could.  This gives max speed, but hurts space
// utilization when allocations of significantly different sizes are requested.
//
// This code can easily be optimized more in the future.

#if defined(NDR_PROFILE_ALLOCA)

VOID
NdrpAllocaWriteLog( CHAR *pChar, DWORD Size )
{

    HANDLE hMutex = NULL;
    HANDLE hLogFile = INVALID_HANDLE_VALUE;
    BOOL bHasMutex = FALSE;   

    RpcTryFinally
       {

       
       // Open and acquire the log mutex
       hMutex = CreateMutex( NULL, FALSE, "NDR_ALLOCA_LOG_MUTEX");
       if ( !hMutex) return;

       DWORD dwWaitResult = WaitForSingleObject( hMutex, INFINITE );
       if ( WAIT_FAILED == dwWaitResult ) return;
       bHasMutex = TRUE;         
 
       CHAR LogFile[MAX_PATH];
       UINT DirResult = 
           GetSystemDirectoryA( LogFile, sizeof(LogFile) );

       if ( !DirResult) return;

       strcat( LogFile, "\\ndralloca.log" );

       hLogFile = CreateFileA( LogFile, 
                               GENERIC_WRITE,
                               FILE_SHARE_READ | FILE_SHARE_WRITE,
                               NULL,
                               OPEN_ALWAYS,
                               FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
                               NULL );

       SetFilePointer( hLogFile, 0, NULL, FILE_END );

       DWORD dwBytesWritten;
       WriteFile( hLogFile, pChar, Size, &dwBytesWritten, NULL ); 

       }
   RpcFinally
       {
       if ( bHasMutex ) ReleaseMutex( hMutex );
       if ( NULL != hMutex) CloseHandle( hMutex );
       if ( INVALID_HANDLE_VALUE != hLogFile )  CloseHandle( hLogFile );
       }
   RpcEndFinally

}

VOID
NdrpAllocaDumpStatistics(
    PNDR_ALLOCA_CONTEXT pAllocaContext
    )
{

   // Produce a record suitable for entry into Excel.
   CHAR DataBuffer[4048];
   CHAR AppName[MAX_PATH];
   memset(AppName, 0, sizeof(AppName ) );

   GetModuleFileNameA( NULL, AppName, sizeof(AppName ) ); 

   sprintf( DataBuffer, "EXE,%s,PID,0x%X,TID,0x%x,CS,%d,AB,%d,AA,%d,MB,%d,MA,%d\r\n",
            AppName,
            GetCurrentProcessId(),
            GetCurrentThreadId(),
            (long)NDR_ALLOCA_PREALLOCED_BLOCK_SIZE,
            pAllocaContext->AllocaBytes,
            pAllocaContext->AllocaAllocations,
            pAllocaContext->MemoryBytes,
            pAllocaContext->MemoryAllocations );

   NdrpAllocaWriteLog( DataBuffer, strlen( DataBuffer ) );

}

#endif

VOID
NdrpAllocaInit(
    PNDR_ALLOCA_CONTEXT pAllocaContext
    )
/*++

Routine Description :

    Initiaizes the alloca context. 

Arguments :

    pAllocaContext  - Pointer to the Alloca context..

Return :

    None.

--*/
{

    pAllocaContext->pBlockPointer = pAllocaContext->PreAllocatedBlock;
    pAllocaContext->BytesRemaining = NDR_ALLOCA_PREALLOCED_BLOCK_SIZE;

#if defined(NDR_PROFILE_ALLOCA)
    pAllocaContext->AllocaBytes = 0;
    pAllocaContext->AllocaAllocations = 0;
    pAllocaContext->MemoryBytes = 0;
    pAllocaContext->MemoryAllocations = 0;
#endif
    
    InitializeListHead( &pAllocaContext->MemoryList );

}

VOID
NdrpAllocaDestroy(
    PNDR_ALLOCA_CONTEXT pAllocaContext
    )
/*++

Routine Description :

    Deinitializes this Alloca context and frees all memory
    from the allocation calls that were associated with this context. 

Arguments :

    pAllocaContext  - Pointer to the Alloca context.

Return :

    None.

--*/
{

#if defined(NDR_PROFILE_ALLOCA)
    NdrpAllocaDumpStatistics( pAllocaContext );
#endif

    PLIST_ENTRY pMemoryList = pAllocaContext->MemoryList.Flink; 

    while( pMemoryList != &pAllocaContext->MemoryList ) 
       {
       PLIST_ENTRY pMemoryListNext = pMemoryList->Flink;
       
       I_RpcFree( pMemoryList );
       
       pMemoryList = pMemoryListNext;
       }

    InitializeListHead( &pAllocaContext->MemoryList );

}

PVOID 
NdrpAlloca(
    PNDR_ALLOCA_CONTEXT pAllocaContext,
    UINT Size 
    )
/*++

Routine Description :

    Allocates memory from the allocation context. If no memory is available 
    in the cache, more memory is added.  If more memory can not be
    added, a RPC_S_NO_MEMORY exception is raised.     

Arguments :

    pAllocaContext  - Pointer to the Alloca context.
    Size            - Size of the memory to allocate.

Return :

    Newly allocated memory.

--*/
{
    PVOID pReturnedBlock;

    LENGTH_ALIGN( Size, 15 );

#if defined(NDR_PROFILE_ALLOCA)
    pAllocaContext->AllocaAllocations++;
    pAllocaContext->AllocaBytes += Size;
#endif

    // Check if the current block has enough memory to handle the request.
    if (Size > pAllocaContext->BytesRemaining) 
       {

       // Allocate a new block
       ULONG NewBlockSize = max( Size + sizeof(LIST_ENTRY), 
                                 NDR_ALLOCA_MIN_BLOCK_SIZE );

#if defined(NDR_PROFILE_ALLOCA)
       pAllocaContext->MemoryAllocations++;
       pAllocaContext->MemoryBytes += NewBlockSize;
#endif

       PBYTE pNewBlock = (PBYTE)I_RpcAllocate( NewBlockSize );

       if ( !pNewBlock ) 
          {
          
          RpcRaiseException( RPC_S_OUT_OF_MEMORY );
          return NULL; // keep the compiler happy
          }

       InsertHeadList( &pAllocaContext->MemoryList, (PLIST_ENTRY) pNewBlock);
       pAllocaContext->pBlockPointer = pNewBlock + sizeof(LIST_ENTRY);
       pAllocaContext->BytesRemaining = NewBlockSize - sizeof(LIST_ENTRY);

       }

    // alloc memory from an existing block.
    pReturnedBlock = pAllocaContext->pBlockPointer;
    pAllocaContext->pBlockPointer += Size;
    pAllocaContext->BytesRemaining -= Size;

    return pReturnedBlock;

}

PVOID
NdrpPrivateAllocate(
    PNDR_ALLOCA_CONTEXT pAllocaContext,
    UINT Size 
    )
/*++

Routine Description :

    Allocates memory using I_RpcAllocate and adds the memory to the
    memory list block.  If no memory is available, and RPC_S_OUT_OF_MEMORY exception
    is thrown.     

Arguments :

    pAllocaContext  - Pointer to the Alloca context.
    Size            - Size of the memory to allocate.

Return :

    Newly allocated memory.

--*/
{
    UINT AllocSize = sizeof(LIST_ENTRY) + Size;

    PBYTE pNewBlock = (PBYTE)I_RpcAllocate( AllocSize );

    if ( !pNewBlock ) 
       {
       RpcRaiseException( RPC_S_OUT_OF_MEMORY );
       return NULL; // keep the compiler happy
       }

    InsertHeadList( &pAllocaContext->MemoryList, (PLIST_ENTRY) pNewBlock);
    return ((uchar *)pNewBlock) + sizeof(PLIST_ENTRY);

}

void
NdrpPrivateFree(
    PNDR_ALLOCA_CONTEXT pAllocaContext,
    void *pMemory 
    )
/*++

Routine Description :

    Frees memory allocated with NdrpPrivateAllocate     

Arguments :

    pAllocaContext  - Pointer to the Alloca context.
    pMemory         - Memory allocated with NdrpPrivateAllocate.

Return :

    None.

--*/
{
    PLIST_ENTRY pListEntry;

    if (NULL == pMemory) 
        return;

    pListEntry = (PLIST_ENTRY)( ((uchar *)pMemory) - sizeof(LIST_ENTRY) );

    RemoveEntryList( pListEntry );
    I_RpcFree( pListEntry );
}

void
NdrpInitUserMarshalCB(
    MIDL_STUB_MESSAGE   *   pStubMsg,
    PFORMAT_STRING          pFormat,
    USER_MARSHAL_CB_TYPE    CBType,
    USER_MARSHAL_CB     *   pUserMarshalCB
    )
/*++

Routine Description :

    Initialize a user marshall callback structure.
    
Arguments :

    pStubMsg         - Supplies the stub message for the call.
    pFormat          - Supplies the format string for the type(FC_USER_MARSHAL). 
    CBType           - Supplies the callback type.   
    pUserMarshalCB   - Pointer to the callback to be initialized.

Return :

    None.

--*/
{

    pUserMarshalCB->Flags    = USER_CALL_CTXT_MASK( pStubMsg->dwDestContext );
    if ( USER_MARSHAL_CB_UNMARSHALL == CBType )
        {
        pUserMarshalCB->Flags |=
            (((pStubMsg->RpcMsg->DataRepresentation & (ulong)0x0000FFFF)) << 16 );  
        }
    if ( pStubMsg->pAsyncMsg )
        pUserMarshalCB->Flags |= USER_CALL_IS_ASYNC;
    if ( pStubMsg->fHasNewCorrDesc )
        pUserMarshalCB->Flags |= USER_CALL_NEW_CORRELATION_DESC;
    
    pUserMarshalCB->pStubMsg = pStubMsg;
    pUserMarshalCB->pReserve = (pFormat[1] & USER_MARSHAL_IID)  ? pFormat + 10
                                                                : 0;
    pUserMarshalCB->Signature = USER_MARSHAL_CB_SIGNATURE;
    pUserMarshalCB->CBType = CBType;

    pUserMarshalCB->pFormat = pFormat;
    pUserMarshalCB->pTypeFormat = pFormat + 8;
    pUserMarshalCB->pTypeFormat = pUserMarshalCB->pTypeFormat +
                                  *(short *)pUserMarshalCB->pTypeFormat;

}

RPC_STATUS
RPC_ENTRY
NdrGetUserMarshalInfo (
    IN unsigned long          * pFlags,
    IN unsigned long            InformationLevel,
    OUT NDR_USER_MARSHAL_INFO * pMarshalInfo
    )
/*++

Routine Description :

    The NdrGetUserMarshalInfo function is called by a application provided
    wire_marshal or user_marshal helper function to receive extra information
    in addition to the pFlags parameter.
    
Arguments :

    pFlags           - Supplies the pFlags pointer that rpc passed to the helper function.
    InformationLevel - Supplies the desired level of detail to be received. The amount of
                       information increases as the level increases.  
    pMarshalInfo     - Points to the buffer that is to receive the extra information.   

Return :

    On sucesss - RPC_S_OK.

--*/
{

    MIDL_STUB_MESSAGE *pStubMsg;
    USER_MARSHAL_CB * pCBInfo = (USER_MARSHAL_CB *)pFlags; 

    if ( InformationLevel != 1)
       {
       return RPC_S_INVALID_ARG;
       }

    RpcTryExcept
       {
       if ( USER_MARSHAL_CB_SIGNATURE != pCBInfo->Signature )
          {
          return RPC_S_INVALID_ARG;    
          }
       MIDL_memset( pMarshalInfo, 0, sizeof(NDR_USER_MARSHAL_INFO) ); 
       }
    RpcExcept(1)
        {
        return RPC_S_INVALID_ARG;
        }
    RpcEndExcept   

       
    pMarshalInfo->InformationLevel = InformationLevel;
    pStubMsg = pCBInfo->pStubMsg;

    // The buffer pointer and the buffer length only
    // make sense if the callback is for marshalling
    // and unmarshalling.
    if ( USER_MARSHAL_CB_MARSHALL == pCBInfo->CBType ||
         USER_MARSHAL_CB_UNMARSHALL == pCBInfo->CBType )
       {

       char *CurrentBuffer = (char *)pStubMsg->Buffer;
       char *BufferStart = (char *)pStubMsg->RpcMsg->Buffer;
       unsigned long BufferUsed = (unsigned long)(ULONG_PTR)(CurrentBuffer 
                                                             - BufferStart);   
       unsigned long BufferLength = pStubMsg->RpcMsg->BufferLength - BufferUsed;

       if ( CurrentBuffer < BufferStart ||
            CurrentBuffer > (BufferStart + pStubMsg->RpcMsg->BufferLength ) )
          {
             return RPC_X_INVALID_BUFFER;
          }
       
       pMarshalInfo->Level1.Buffer = pStubMsg->Buffer;
       pMarshalInfo->Level1.BufferSize = BufferLength;
       }
    
    pMarshalInfo->Level1.pfnAllocate = pStubMsg->pfnAllocate;
    pMarshalInfo->Level1.pfnFree = pStubMsg->pfnFree;
    pMarshalInfo->Level1.pRpcChannelBuffer = pStubMsg->pRpcChannelBuffer;
    pMarshalInfo->Level1.Reserved[0] = (ULONG_PTR)pCBInfo->pFormat;
    pMarshalInfo->Level1.Reserved[1] = (ULONG_PTR)pCBInfo->pTypeFormat;

    return RPC_S_OK;    

}



void RPC_ENTRY
RpcUserFree( HANDLE AsyncHandle, void * pBuffer )
{
    PMIDL_STUB_MESSAGE pStubMsg;
    RPC_STATUS Status;
    PRPC_ASYNC_STATE pHandle = ( PRPC_ASYNC_STATE) AsyncHandle;
    // User passes in NULL in sync case.
    if ( NULL == pHandle )
        {
        pStubMsg = (PMIDL_STUB_MESSAGE )I_RpcGetNDRSlot();
        Status = S_OK;
        }
    else
        {
        Status = NdrValidateBothAndLockAsyncHandle( pHandle);
        if ( Status == RPC_S_OK )
            {
            PNDR_ASYNC_MESSAGE pAsyncMsg = (PNDR_ASYNC_MESSAGE) pHandle->StubInfo;
            pStubMsg = &pAsyncMsg->StubMsg;
            }
        }

    // REVIEW: default behavior is not to raise exception?
    if ( Status != RPC_S_OK )
        {
        NDR_ASSERT( 0, "invalid rpc handle" );
        return ;
        }
        
    // validate the stubmsg.
    NDR_ASSERT( pStubMsg, "invalid stub message" );

    // We'll call into user's free routine to free the buffer if it's not 
    // part of dispatch buffer. 
    // We don't care about allocate_on_stack: it can only happen on top level
    // out ref pointer or ref pointer to pointer case, and freeing that is 
    // very much shooting self on the foot.
    if (  (pBuffer < pStubMsg->BufferStart) || (pBuffer > pStubMsg->BufferEnd))
        {
        pStubMsg->pfnFree( pBuffer );
        }
    else
        return;
        
}


BOOL
IsWriteAV (

    IN struct _EXCEPTION_POINTERS *ExceptionPointers

    )

{

    EXCEPTION_RECORD *ExceptionRecord;

 

    ExceptionRecord = ExceptionPointers->ExceptionRecord;

    if ((ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION)

        && (ExceptionRecord->ExceptionInformation[0]))

        {

        return TRUE;

        }

    else

        return FALSE;

}


int RPC_ENTRY
NdrServerUnmarshallExceptionFlag(
    IN struct _EXCEPTION_POINTERS *ExceptionPointers
)
{
    RPC_STATUS ExceptCode = ExceptionPointers->ExceptionRecord->ExceptionCode;
    if ( ( ExceptCode != STATUS_POSSIBLE_DEADLOCK )  && 
        ( ExceptCode != STATUS_INSTRUCTION_MISALIGNMENT )   && 
        ( ExceptCode != STATUS_DATATYPE_MISALIGNMENT )  && 
        ( ExceptCode != STATUS_PRIVILEGED_INSTRUCTION )  && 
        ( ExceptCode != STATUS_ILLEGAL_INSTRUCTION )  && 
        ( ExceptCode != STATUS_BREAKPOINT ) && 
        ( ExceptCode != STATUS_STACK_OVERFLOW ) && 
        !IsWriteAV(ExceptionPointers) ) 
        return EXCEPTION_EXECUTE_HANDLER;
    else
        return EXCEPTION_CONTINUE_SEARCH;
                
}



// check for overflow when calculating the total size. 
#if defined(_X86_)
ULONG MultiplyWithOverflowCheck( ULONG_PTR Count, ULONG_PTR ELemSize )
{
    register UINT32 IsOverFlowed = 0;
    NDR_ASSERT(  Count < 0x80000000, "invalid count" );
    NDR_ASSERT(  ELemSize < 0x80000000 , "invalid element size" );
    ULONG res = Count * ELemSize;
    __asm 
        {
        jno skip;
        mov IsOverFlowed, 1;
        skip:
        }
    if ( IsOverFlowed || res > 0x7fffffff )
        RpcRaiseException( RPC_X_INVALID_BOUND );

    return res;
}
#else   // we only have ia64 & amd64 here.
ULONG MultiplyWithOverflowCheck( ULONG_PTR Count, ULONG_PTR ElemSize )
{
    NDR_ASSERT( Count < 0x80000000, "invalid count" );
    NDR_ASSERT( ElemSize < 0x80000000 , "invalid element size" );
    UINT64 res = (UINT64)Count * ElemSize;
    if ( res > 0x7fffffff )
        RpcRaiseException( RPC_X_INVALID_BOUND );

    return (ULONG) res ;
}
#endif