text: /*++
  
  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);
      LENGTH_ALIGN(pStubMsg->BufferLength, 3);
      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;
  }
  
  
  