/*++ 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 #include #include #include CStdProxyBuffer * RPC_ENTRY NdrGetProxyBuffer( void *pThis); const IID * RPC_ENTRY NdrGetProxyIID( const void *pThis); ULONG STDMETHODCALLTYPE CStdProxyBuffer_Release( IN IRpcProxyBuffer *This); ULONG STDMETHODCALLTYPE CStdProxyBuffer2_Release( IN IRpcProxyBuffer *This); BOOL NdrpFindInterface( IN const ProxyFileInfo ** pProxyFileList, IN REFIID riid, OUT const ProxyFileInfo ** ppProxyFileInfo, OUT long * pIndex ); // The channel wrapper // typedef struct tagChannelWrapper { const IRpcChannelBufferVtbl *lpVtbl; long RefCount; const IID * pIID; struct IRpcChannelBuffer * pChannel; } ChannelWrapper; HRESULT STDMETHODCALLTYPE CreateChannelWrapper ( const IID * pIID, IRpcChannelBuffer * pChannel, IRpcChannelBuffer ** pChannelWrapper ); HRESULT STDMETHODCALLTYPE CreateAsyncChannelWrapper ( const IID * pIID, IRpcChannelBuffer * pChannel, IRpcChannelBuffer ** pChannelWrapper ); HRESULT STDMETHODCALLTYPE ChannelWrapper_QueryInterface ( IRpcChannelBuffer3 * This, REFIID riid, void ** ppvObject ); ULONG STDMETHODCALLTYPE ChannelWrapper_AddRef ( IRpcChannelBuffer3 * This ); ULONG STDMETHODCALLTYPE ChannelWrapper_Release ( IRpcChannelBuffer3 * This ); HRESULT STDMETHODCALLTYPE ChannelWrapper_GetBuffer ( IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, REFIID riid ); HRESULT STDMETHODCALLTYPE ChannelWrapper_SendReceive ( IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, ULONG * pStatus ); HRESULT STDMETHODCALLTYPE ChannelWrapper_FreeBuffer ( IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage ); HRESULT STDMETHODCALLTYPE ChannelWrapper_GetDestCtx ( IRpcChannelBuffer3 * This, DWORD * pdwDestContext, void ** ppvDestContext ); HRESULT STDMETHODCALLTYPE ChannelWrapper_IsConnected ( IRpcChannelBuffer3 * This ); HRESULT STDMETHODCALLTYPE ChannelWrapper_GetProtocolVersion ( IRpcChannelBuffer3 * This, DWORD * pdwVersion ); HRESULT STDMETHODCALLTYPE ChannelWrapper_Send( IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, ULONG * pStatus ); HRESULT STDMETHODCALLTYPE ChannelWrapper_Receive( IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, ULONG ulSize, ULONG * pStatus ); HRESULT STDMETHODCALLTYPE ChannelWrapper_Cancel( IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage ); HRESULT STDMETHODCALLTYPE ChannelWrapper_GetCallContext( IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, REFIID riid, void ** pInterface ); HRESULT STDMETHODCALLTYPE ChannelWrapper_GetDestCtxEx( IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, DWORD * pdwDestContext, void ** ppvDestContext ); HRESULT STDMETHODCALLTYPE ChannelWrapper_GetState( IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, DWORD * pState ); HRESULT STDMETHODCALLTYPE ChannelWrapper_RegisterAsync( IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, IAsyncManager * pAsyncMgr ); HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_QueryInterface ( IAsyncRpcChannelBuffer * This, REFIID riid, void ** ppvObject ); ULONG STDMETHODCALLTYPE AsyncChannelWrapper_AddRef ( IAsyncRpcChannelBuffer * This ); ULONG STDMETHODCALLTYPE AsyncChannelWrapper_Release ( IAsyncRpcChannelBuffer * This ); HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_GetBuffer ( IAsyncRpcChannelBuffer * This, RPCOLEMESSAGE * pMessage, REFIID riid ); HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_SendReceive ( IAsyncRpcChannelBuffer * This, RPCOLEMESSAGE * pMessage, ULONG * pStatus ); HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_FreeBuffer ( IAsyncRpcChannelBuffer * This, RPCOLEMESSAGE * pMessage ); HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_GetDestCtx ( IAsyncRpcChannelBuffer * This, DWORD * pdwDestContext, void ** ppvDestContext ); HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_IsConnected ( IAsyncRpcChannelBuffer * This ); HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_GetProtocolVersion ( IAsyncRpcChannelBuffer * This, DWORD * pdwVersion ); HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_Send( IAsyncRpcChannelBuffer * This, RPCOLEMESSAGE * pMessage, ISynchronize * pSynchronize, ULONG * pStatus ); HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_Receive( IAsyncRpcChannelBuffer * This, RPCOLEMESSAGE * pMessage, ULONG * pStatus ); HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_GetDestCtxEx ( IAsyncRpcChannelBuffer * This, RPCOLEMESSAGE * pMessage, DWORD * pdwDestContext, void ** ppvDestContext ); //+------------------------------------------------------------------------- // // Global data // //-------------------------------------------------------------------------- // ProxyBuffer vtables for non-delegaed and delegated case. extern const IRpcProxyBufferVtbl CStdProxyBufferVtbl = { CStdProxyBuffer_QueryInterface, CStdProxyBuffer_AddRef, CStdProxyBuffer_Release, CStdProxyBuffer_Connect, CStdProxyBuffer_Disconnect }; extern const IRpcProxyBufferVtbl CStdProxyBuffer2Vtbl = { CStdProxyBuffer_QueryInterface, CStdProxyBuffer_AddRef, CStdProxyBuffer2_Release, CStdProxyBuffer2_Connect, CStdProxyBuffer2_Disconnect }; // ICallFactory interface on the ProxyBuffer objects. // ICallFactory is an interface on a sync proxy only. // It has been introduced for NT5 beta2. extern const ICallFactoryVtbl CStdProxyBuffer_CallFactoryVtbl = { CStdProxyBuffer_CF_QueryInterface, CStdProxyBuffer_CF_AddRef, CStdProxyBuffer_CF_Release, CStdProxyBuffer_CF_CreateCall }; extern const ICallFactoryVtbl CStdProxyBuffer2_CallFactoryVtbl = { CStdProxyBuffer_CF_QueryInterface, CStdProxyBuffer_CF_AddRef, CStdProxyBuffer_CF_Release, CStdProxyBuffer2_CF_CreateCall }; extern const IReleaseMarshalBuffersVtbl CStdProxyBuffer_ReleaseMarshalBuffersVtbl = { CStdProxyBuffer_RMB_QueryInterface, CStdProxyBuffer_RMB_AddRef, CStdProxyBuffer_RMB_Release, CStdProxyBuffer_RMB_ReleaseMarshalBuffer }; extern const IReleaseMarshalBuffersVtbl CStdAsyncProxyBuffer_ReleaseMarshalBuffersVtbl = { CStdProxyBuffer_RMB_QueryInterface, CStdProxyBuffer_RMB_AddRef, CStdProxyBuffer_RMB_Release, CStdAsyncProxyBuffer_RMB_ReleaseMarshalBuffer }; // Async proxy buffer vtables extern const IRpcProxyBufferVtbl CStdAsyncProxyBufferVtbl = { CStdAsyncProxyBuffer_QueryInterface, CStdProxyBuffer_AddRef, CStdAsyncProxyBuffer_Release, CStdAsyncProxyBuffer_Connect, CStdProxyBuffer_Disconnect }; extern const IRpcProxyBufferVtbl CStdAsyncProxyBuffer2Vtbl = { CStdAsyncProxyBuffer_QueryInterface, CStdProxyBuffer_AddRef, CStdAsyncProxyBuffer2_Release, CStdAsyncProxyBuffer2_Connect, CStdProxyBuffer2_Disconnect }; // Channel wrapper is used for delegetion only. extern const IRpcChannelBuffer3Vtbl ChannelWrapperVtbl = { ChannelWrapper_QueryInterface, ChannelWrapper_AddRef, ChannelWrapper_Release, ChannelWrapper_GetBuffer, ChannelWrapper_SendReceive, ChannelWrapper_FreeBuffer, ChannelWrapper_GetDestCtx, ChannelWrapper_IsConnected, ChannelWrapper_GetProtocolVersion, ChannelWrapper_Send, ChannelWrapper_Receive, ChannelWrapper_Cancel, ChannelWrapper_GetCallContext, ChannelWrapper_GetDestCtxEx, ChannelWrapper_GetState, ChannelWrapper_RegisterAsync }; extern const IAsyncRpcChannelBufferVtbl AsyncChannelWrapperVtbl = { AsyncChannelWrapper_QueryInterface, AsyncChannelWrapper_AddRef, AsyncChannelWrapper_Release, AsyncChannelWrapper_GetBuffer, AsyncChannelWrapper_SendReceive, AsyncChannelWrapper_FreeBuffer, AsyncChannelWrapper_GetDestCtx, AsyncChannelWrapper_IsConnected, AsyncChannelWrapper_GetProtocolVersion, AsyncChannelWrapper_Send, AsyncChannelWrapper_Receive, AsyncChannelWrapper_GetDestCtxEx }; //+------------------------------------------------------------------------- // // End of Global data // //-------------------------------------------------------------------------- #pragma code_seg(".orpc") // __inline CStdProxyBuffer * RPC_ENTRY NdrGetProxyBuffer( IN void *pThis) /*++ Routine Description: The "this" pointer points to the pProxyVtbl field in the CStdProxyBuffer structure. The NdrGetProxyBuffer function returns a pointer to the top of the CStdProxyBuffer structure. Arguments: pThis - Supplies a pointer to the interface proxy. Return Value: This function returns a pointer to the proxy buffer. --*/ { unsigned char *pTemp; pTemp = (unsigned char *) pThis; pTemp -= offsetof(CStdProxyBuffer, pProxyVtbl); return (CStdProxyBuffer *)pTemp; } //__inline const IID * RPC_ENTRY NdrGetProxyIID( IN const void *pThis) /*++ Routine Description: The NDRGetProxyIID function returns a pointer to IID. Arguments: pThis - Supplies a pointer to the interface proxy. Return Value: This function returns a pointer to the IID. --*/ { unsigned char ** ppTemp; unsigned char * pTemp; CInterfaceProxyVtbl *pProxyVtbl; //Get a pointer to the proxy vtbl. ppTemp = (unsigned char **) pThis; pTemp = *ppTemp; pTemp -= sizeof(CInterfaceProxyHeader); pProxyVtbl = (CInterfaceProxyVtbl *) pTemp; return pProxyVtbl->header.piid; } HRESULT STDMETHODCALLTYPE CStdProxyBuffer_QueryInterface( IN IRpcProxyBuffer * This, IN REFIID riid, OUT void ** ppv) /*++ Routine Description: Query for an interface on the proxy. This function provides access to both internal and external interfaces. Arguments: riid - Supplies the IID of the requested interface. ppv - Returns a pointer to the requested interface. Return Value: S_OK E_NOINTERFACE --*/ { CStdProxyBuffer * pCThis = (CStdProxyBuffer *) This; HRESULT hr = E_NOINTERFACE; const IID * pIID; *ppv = 0; if( (memcmp(&riid, &IID_IUnknown, sizeof(IID)) == 0) || (memcmp(&riid, &IID_IRpcProxyBuffer, sizeof(IID)) == 0) ) { //This is an internal interface. Increment the internal reference count. InterlockedIncrement( &pCThis->RefCount); *ppv = This; hr = S_OK; return hr; } else if ( pCThis->pCallFactoryVtbl != 0 && memcmp(&riid, &IID_ICallFactory, sizeof(IID)) == 0 ) { // This is an exposed interface so go through punkOuter ot addref. pCThis->punkOuter->lpVtbl->AddRef(pCThis->punkOuter); *ppv = (void *) & pCThis->pCallFactoryVtbl; hr = S_OK; return hr; } else if ( pCThis->pRMBVtbl && (memcmp(&riid, &IID_IReleaseMarshalBuffers,sizeof(IID)) == 0)) { InterlockedIncrement( &pCThis->RefCount); *ppv = (void *) & pCThis->pRMBVtbl; hr = S_OK; return hr; } pIID = NdrGetProxyIID(&pCThis->pProxyVtbl); if( memcmp(&riid, pIID, sizeof(IID)) == 0) { //Increment the reference count. pCThis->punkOuter->lpVtbl->AddRef(pCThis->punkOuter); *ppv = (void *) &pCThis->pProxyVtbl; hr = S_OK; } return hr; }; HRESULT STDMETHODCALLTYPE CStdAsyncProxyBuffer_QueryInterface( IN IRpcProxyBuffer * This, IN REFIID riid, OUT void ** ppv) /*++ Routine Description: Query for an interface on the proxy. This function provides access to both internal and external interfaces. Used for CStdAsyncProxyBuffer2 as well. Arguments: riid - Supplies the IID of the requested interface. ppv - Returns a pointer to the requested interface. Return Value: S_OK E_NOINTERFACE --*/ { CStdProxyBuffer * pCThis = (CStdProxyBuffer *) This; HRESULT hr = E_NOINTERFACE; const IID * pIID; *ppv = 0; if( (memcmp(&riid, &IID_IUnknown, sizeof(IID)) == 0) || (memcmp(&riid, &IID_IRpcProxyBuffer, sizeof(IID)) == 0)) { //This is an internal interface. Increment the internal reference count. InterlockedIncrement( &pCThis->RefCount); *ppv = This; hr = S_OK; return hr; } else if ( pCThis->pRMBVtbl && (memcmp(&riid, &IID_IReleaseMarshalBuffers,sizeof(IID)) == 0)) { InterlockedIncrement( &pCThis->RefCount); *ppv = (void *) & pCThis->pRMBVtbl; hr = S_OK; return hr; } if(memcmp(&riid, &IID_ISynchronize, sizeof(IID)) == 0) { hr = pCThis->punkOuter->lpVtbl->QueryInterface( pCThis->punkOuter, IID_ISynchronize, ppv); } pIID = NdrGetProxyIID(&pCThis->pProxyVtbl); if(memcmp(&riid, pIID, sizeof(IID)) == 0) { //Increment the reference count. pCThis->punkOuter->lpVtbl->AddRef(pCThis->punkOuter); *ppv = (void *) &pCThis->pProxyVtbl; hr = S_OK; } return hr; }; ULONG STDMETHODCALLTYPE CStdProxyBuffer_AddRef( IN IRpcProxyBuffer *This) /*++ Routine Description: Increment reference count. Used for CStdProxyBuffer2 CStdAsyncProxyBuffer CStdAsuncProxyBuffer2 Arguments: Return Value: Reference count. --*/ { // We do not need to go through punkOuter for ICallFactory. CStdProxyBuffer * pCThis = (CStdProxyBuffer *) This; InterlockedIncrement(&pCThis->RefCount); return (ULONG) pCThis->RefCount; }; ULONG STDMETHODCALLTYPE CStdProxyBuffer_Release( IN IRpcProxyBuffer *This) /*++ Routine Description: Decrement reference count. Arguments: Return Value: Reference count. --*/ { ULONG count; IPSFactoryBuffer *pFactory; NDR_ASSERT(((CStdProxyBuffer *)This)->RefCount > 0, "Invalid reference count"); count = (unsigned long) ((CStdProxyBuffer *)This)->RefCount - 1; if(InterlockedDecrement(&((CStdProxyBuffer *)This)->RefCount) == 0) { count = 0; pFactory = (IPSFactoryBuffer *) ((CStdProxyBuffer *)This)->pPSFactory; //Decrement the DLL reference count. pFactory->lpVtbl->Release(pFactory); #if DBG == 1 //In debug builds, zero fill the memory. memset(This, '\0', sizeof(CStdProxyBuffer)); #endif //Free the memory (*pfnCoTaskMemFree)(This); } return count; }; ULONG STDMETHODCALLTYPE CStdProxyBuffer2_Release( IN IRpcProxyBuffer * This) /*++ Routine Description: Decrement reference count. This function is used by proxies which delegate to the base interface. Arguments: This - Points to a CStdProxyBuffer2. Return Value: Reference count. --*/ { ULONG count; IPSFactoryBuffer * pFactory; IRpcProxyBuffer * pBaseProxyBuffer; IUnknown * pBaseProxy; NDR_ASSERT(((CStdProxyBuffer2 *)This)->RefCount > 0, "Invalid reference count"); count = (ULONG) ((CStdProxyBuffer2 *)This)->RefCount - 1; if(InterlockedDecrement(&((CStdProxyBuffer2 *)This)->RefCount) == 0) { count = 0; //Delegation support. pBaseProxy = ((CStdProxyBuffer2 *)This)->pBaseProxy; if(pBaseProxy != 0) { // Shannon - why? //This is a weak reference, so we don't release it. //pBaseProxy->lpVtbl->Release(pBaseProxy); } pBaseProxyBuffer = ((CStdProxyBuffer2 *)This)->pBaseProxyBuffer; if( pBaseProxyBuffer != 0) { pBaseProxyBuffer->lpVtbl->Release(pBaseProxyBuffer); } //Decrement the DLL reference count. pFactory = (IPSFactoryBuffer *) ((CStdProxyBuffer2 *)This)->pPSFactory; pFactory->lpVtbl->Release(pFactory); #if DBG == 1 //In debug builds, zero fill the memory. memset(This, '\0', sizeof(CStdProxyBuffer2)); #endif //Free the memory (*pfnCoTaskMemFree)(This); } return count; }; ULONG STDMETHODCALLTYPE CStdAsyncProxyBuffer_Release( IN IRpcProxyBuffer *This) /*++ Routine Description: Decrement reference count. Arguments: Return Value: Reference count. --*/ { // We do not need to go through punkOuter for ICallFactory // and so everything is local. CStdAsyncProxyBuffer * pAsyncPB = (CStdAsyncProxyBuffer *)This; ULONG count; NDR_ASSERT( pAsyncPB->RefCount > 0, "Async proxy Invalid reference count"); count = (unsigned long) pAsyncPB->RefCount - 1; if ( InterlockedDecrement(&pAsyncPB->RefCount) == 0) { IPSFactoryBuffer * pFactory = pAsyncPB->pPSFactory; count = 0; // Release the pAsyncMsg and the related state NdrpAsyncProxyMsgDestructor( pAsyncPB ); //Decrement the DLL reference count. pFactory->lpVtbl->Release( pFactory ); #if DBG == 1 //In debug builds, zero fill the memory. memset( pAsyncPB, '\32', sizeof(CStdAsyncProxyBuffer)); #endif //Free the memory (*pfnCoTaskMemFree)(pAsyncPB); } return count; }; ULONG STDMETHODCALLTYPE CStdAsyncProxyBuffer2_Release( IN IRpcProxyBuffer * This) /*++ Routine Description: Decrement reference count. This function is used by proxies which delegate to the base interface. Arguments: This - Points to a CStdProxyBuffer2. Return Value: Reference count. --*/ { CStdAsyncProxyBuffer * pAsyncPB = (CStdAsyncProxyBuffer *)This; ULONG count; NDR_ASSERT( pAsyncPB->RefCount > 0, "Invalid reference count"); count = (ULONG) pAsyncPB->RefCount - 1; if ( InterlockedDecrement(&pAsyncPB->RefCount) == 0) { IRpcProxyBuffer * pBaseProxyBuffer ; IPSFactoryBuffer * pFactory = pAsyncPB->pPSFactory; count = 0; // Delegation support - release the base async proxy. if( pAsyncPB->map.pBaseProxy != 0) { // Shannon - why? //This is a weak reference, so we don't release it. //pBaseProxy->lpVtbl->Release(pBaseProxy); } pBaseProxyBuffer = pAsyncPB->pBaseProxyBuffer; if( pBaseProxyBuffer != 0) pBaseProxyBuffer->lpVtbl->Release(pBaseProxyBuffer); // Release the pAsyncMsg and the related state NdrpAsyncProxyMsgDestructor( (CStdAsyncProxyBuffer*)This ); // Then clean up the async proxy itself. //Decrement the DLL reference count. pFactory->lpVtbl->Release(pFactory); #if DBG == 1 //In debug builds, zero fill the memory. memset(pAsyncPB, '\32', sizeof(CStdAsyncProxyBuffer)); #endif //Free the memory (*pfnCoTaskMemFree)(pAsyncPB); } return count; }; HRESULT STDMETHODCALLTYPE CStdProxyBuffer_RMB_QueryInterface( IN IReleaseMarshalBuffers *This, IN REFIID riid, OUT void ** ppvObject) /*++ Routine Description: Query for an interface on the interface stub IReleaseMarshalBuffers pointer. Arguments: riid - Supplies the IID of the interface being requested. ppvObject - Returns a pointer to the requested interface. Return Value: S_OK E_NOINTERFACE Note: Works the same way for ProxyBuffer2 and AsyncProxyBuffer. --*/ { CStdProxyBuffer * pSyncPB = (CStdProxyBuffer *) ((uchar *)This - offsetof(CStdProxyBuffer,pRMBVtbl)); return pSyncPB->lpVtbl->QueryInterface( (IRpcProxyBuffer *)pSyncPB, riid, ppvObject ); } ULONG STDMETHODCALLTYPE CStdProxyBuffer_RMB_AddRef( IN IReleaseMarshalBuffers *This) /*++ Routine Description: Implementation of AddRef for interface proxy. Arguments: Return Value: Reference count. --*/ { ULONG count; CStdProxyBuffer * pSyncPB = (CStdProxyBuffer *) ((uchar *)This - offsetof(CStdProxyBuffer,pRMBVtbl)); // It needs to go through punkOuter. count = pSyncPB->lpVtbl->AddRef((IRpcProxyBuffer *) pSyncPB ); return count; }; ULONG STDMETHODCALLTYPE CStdProxyBuffer_RMB_Release( IN IReleaseMarshalBuffers *This) /*++ Routine Description: Implementation of Release for interface proxy. Arguments: Return Value: Reference count. --*/ { ULONG count; CStdProxyBuffer2 * pSyncPB = (CStdProxyBuffer2 *) ((uchar *)This - offsetof(CStdProxyBuffer2,pRMBVtbl)); count = pSyncPB->lpVtbl->Release( (IRpcProxyBuffer *)pSyncPB); return count; }; HRESULT STDMETHODCALLTYPE CStdProxyBuffer_RMB_ReleaseMarshalBuffer( IN IReleaseMarshalBuffers *This, IN RPCOLEMESSAGE * pMsg, IN DWORD dwFlags, IN IUnknown *pChnl) { CStdProxyBuffer * pSyncPB; HRESULT hr; if (NULL != pChnl) return E_INVALIDARG; // [in] only in client side. if (dwFlags) return E_INVALIDARG; hr = NdrpClientReleaseMarshalBuffer(This, (RPC_MESSAGE *)pMsg, dwFlags, FALSE ); // SYNC return hr; } #define IN_BUFFER 0 #define OUT_BUFFER 1 // the pRMBVtbl member is in the same position is both CStdProxyBuffer(2) and // CStdAsyncProxyBuffer so we can cast it anyway. HRESULT STDMETHODCALLTYPE CStdAsyncProxyBuffer_RMB_ReleaseMarshalBuffer( IN IReleaseMarshalBuffers *This, IN RPCOLEMESSAGE * pMsg, IN DWORD dwIOFlags, IN IUnknown *pChnl) { HRESULT hr; if (NULL != pChnl) return E_INVALIDARG; // [in] only in client side. if (dwIOFlags != IN_BUFFER) return E_INVALIDARG; hr = NdrpClientReleaseMarshalBuffer(This, (RPC_MESSAGE *)pMsg, dwIOFlags, TRUE); // is async return hr; } HRESULT STDMETHODCALLTYPE CStdProxyBuffer_Connect( IN IRpcProxyBuffer * This, IN IRpcChannelBuffer * pChannel) /*++ Routine Description: Connect the proxy to the channel. Arguments: pChannel - Supplies a pointer to the channel. Return Value: S_OK --*/ { CStdProxyBuffer * pCThis = (CStdProxyBuffer *) This; HRESULT hr; IRpcChannelBuffer * pTemp = 0; // // Get a pointer to the new channel. // hr = pChannel->lpVtbl->QueryInterface( pChannel, IID_IRpcChannelBuffer, (void **) &pTemp); if(hr == S_OK) { // // Save the pointer to the new channel. // pTemp = (IRpcChannelBuffer *) InterlockedExchangePointer( (PVOID *) &pCThis->pChannel, (PVOID) pTemp); if(pTemp != 0) { // //Release the old channel. // pTemp->lpVtbl->Release(pTemp); pTemp = 0; } } return hr; }; HRESULT STDMETHODCALLTYPE CStdAsyncProxyBuffer_Connect( IN IRpcProxyBuffer * This, IN IRpcChannelBuffer * pChannel) /*++ Routine Description: Connect the proxy to the channel. Arguments: pChannel - Supplies a pointer to the channel. Return Value: S_OK --*/ { CStdProxyBuffer * pCThis = (CStdProxyBuffer *) This; HRESULT hr; IRpcChannelBuffer * pTemp = 0; // Get a pointer to the new channel. // Note, the async proxy is not aggregated with the channel, // It simply keeps the channel pointer. // hr = pChannel->lpVtbl->QueryInterface( pChannel, IID_IAsyncRpcChannelBuffer, (void **) &pTemp); if(hr == S_OK) { // // Save the pointer to the new channel. // pTemp = (IRpcChannelBuffer *) InterlockedExchangePointer( (PVOID *) &pCThis->pChannel, (PVOID) pTemp); if(pTemp != 0) { // //Release the old channel. // pTemp->lpVtbl->Release(pTemp); pTemp = 0; } } return hr; }; HRESULT STDMETHODCALLTYPE CStdProxyBuffer2_Connect( IN IRpcProxyBuffer * This, IN IRpcChannelBuffer * pChannel) /*++ Routine Description: Connect the proxy to the channel. Supports delegation. Arguments: pChannel - Supplies a pointer to the channel. Return Value: S_OK E_NOINTERFACE E_OUTOFMEMORY --*/ { HRESULT hr; IRpcProxyBuffer * pBaseProxyBuffer; IRpcChannelBuffer * pWrapper; const IID * pIID; hr = CStdProxyBuffer_Connect(This, pChannel); if(SUCCEEDED(hr)) { pBaseProxyBuffer = ((CStdProxyBuffer2 *)This)->pBaseProxyBuffer; if(pBaseProxyBuffer != 0) { pIID = NdrGetProxyIID(&((CStdProxyBuffer2 *)This)->pProxyVtbl); hr = CreateChannelWrapper(pIID, pChannel, &pWrapper); if(SUCCEEDED(hr)) { hr = pBaseProxyBuffer->lpVtbl->Connect(pBaseProxyBuffer, pWrapper); // HACKALERT: OleAutomation returns NULL pv in CreateProxy // in cases where they don't know whether to return an NDR // proxy or a custom-format proxy. So we have to go connect // the proxy first then Query for the real interface once that // is done. if((NULL == ((CStdProxyBuffer2 *)This)->pBaseProxy) && SUCCEEDED(hr)) { IUnknown *pv; hr = pBaseProxyBuffer->lpVtbl->QueryInterface(pBaseProxyBuffer, ((CStdProxyBuffer2 *)This)->iidBase, (void **) &pv); if(SUCCEEDED(hr)) { //Release our reference here. pv->lpVtbl->Release(pv); //We keep a weak reference to pv. ((CStdProxyBuffer2 *)This)->pBaseProxy = pv; } } pWrapper->lpVtbl->Release(pWrapper); } } } return hr; }; HRESULT STDMETHODCALLTYPE CStdAsyncProxyBuffer2_Connect( IN IRpcProxyBuffer * This, IN IRpcChannelBuffer * pChannel) /*++ Routine Description: Connect the proxy to the channel. Supports delegation. Arguments: pChannel - Supplies a pointer to the channel. Return Value: S_OK E_NOINTERFACE E_OUTOFMEMORY --*/ { HRESULT hr; IRpcProxyBuffer * pBaseProxyBuffer; IRpcChannelBuffer * pWrapper; const IID * pIID; hr = CStdAsyncProxyBuffer_Connect(This, pChannel); if(SUCCEEDED(hr)) { // Note that all the fields from CStdProxyBuffer2 that we indicate below // have the same offsets in CStdAsyncProxyBuffer that is being handled. // So I leave the cast unchanged to make future code merge easier. // pBaseProxyBuffer = ((CStdProxyBuffer2 *)This)->pBaseProxyBuffer; if(pBaseProxyBuffer != 0) { pIID = NdrGetProxyIID(&((CStdProxyBuffer2 *)This)->pProxyVtbl); // We need a pChannel that is guaranteed to be IAsyncRpcChannelBuffer - // but note, this is exactly what we obtained in the Connect call above. hr = CreateAsyncChannelWrapper( pIID, ((CStdProxyBuffer2*)This)->pChannel, &pWrapper); if(SUCCEEDED(hr)) { hr = pBaseProxyBuffer->lpVtbl->Connect(pBaseProxyBuffer, pWrapper); // This hack alert is rather for future. // HACKALERT: OleAutomation returns NULL pv in CreateProxy // in cases where they don't know whether to return an NDR // proxy or a custom-format proxy. So we have to go connect // the proxy first then Query for the real interface once that // is done. if((NULL == ((CStdProxyBuffer2 *)This)->pBaseProxy) && SUCCEEDED(hr)) { IUnknown *pv; hr = pBaseProxyBuffer->lpVtbl->QueryInterface(pBaseProxyBuffer, ((CStdProxyBuffer2 *)This)->iidBase, (void **) &pv); if(SUCCEEDED(hr)) { //Release our reference here. pv->lpVtbl->Release(pv); //We keep a weak reference to pv. ((CStdProxyBuffer2 *)This)->pBaseProxy = pv; } } pWrapper->lpVtbl->Release(pWrapper); } } } return hr; }; void STDMETHODCALLTYPE CStdProxyBuffer_Disconnect( IN IRpcProxyBuffer *This) /*++ Routine Description: Disconnect the proxy from the channel. Also used for: CStdAsyncProxyBuffer_Disconnect Arguments: Return Value: None. --*/ { CStdProxyBuffer * pCThis = (CStdProxyBuffer *) This; IRpcChannelBuffer * pOldChannel; pOldChannel = (IRpcChannelBuffer *) InterlockedExchangePointer( (PVOID *) &pCThis->pChannel, 0); if(pOldChannel != 0) { //Release the old channel. // pOldChannel->lpVtbl->Release(pOldChannel); } }; void STDMETHODCALLTYPE CStdProxyBuffer2_Disconnect( IN IRpcProxyBuffer *This) /*++ Routine Description: Disconnect the proxy from the channel. Also used for: CStdAsyncProxyBuffer2_Disconnect Arguments: Return Value: None. --*/ { IRpcProxyBuffer *pBaseProxyBuffer; CStdProxyBuffer_Disconnect(This); pBaseProxyBuffer = ((CStdProxyBuffer2 *)This)->pBaseProxyBuffer; if(pBaseProxyBuffer != 0) pBaseProxyBuffer->lpVtbl->Disconnect(pBaseProxyBuffer); }; HRESULT NdrpCreateNonDelegatedAsyncProxy( //CStdProxyBuffer_CreateAsyncProxy( IN IRpcProxyBuffer *This, IN REFIID riid, // async IID IN IUnknown * punkOuter, // controlling unknown OUT CStdAsyncProxyBuffer ** ppAsyncProxy ) /* Creates a call object, i.e. an async proxy object. An async proxy doesn't have a pSynchronize, just passes it. Note, because the call comes via a CStdProxyBuffer, not Buffer2, we know that we need to create only a non-delegated async proxy. This is because CStdProxyBuffer itself is a non-delegated proxy. */ { BOOL fFound; long j; // if index const ProxyFileInfo * pProxyFileInfo; CStdProxyBuffer * pSyncPB = (CStdProxyBuffer *)This; *ppAsyncProxy = 0; if ( ! pSyncPB->pCallFactoryVtbl || !pSyncPB->pAsyncIID ) return E_NOINTERFACE; // Check if sync and async iids match. if ( memcmp( &riid, pSyncPB->pAsyncIID, sizeof(IID)) != 0 ) return E_NOINTERFACE; // same file, so we can use the sync pPSFactory. fFound = NdrpFindInterface( ((CStdPSFactoryBuffer *)pSyncPB->pPSFactory)->pProxyFileList, riid, &pProxyFileInfo, & j); if ( !fFound ) return E_NOINTERFACE; CStdAsyncProxyBuffer *pAsyncPB = (CStdAsyncProxyBuffer*)(*pfnCoTaskMemAlloc)(sizeof(CStdAsyncProxyBuffer)); if( ! pAsyncPB ) return E_OUTOFMEMORY; memset( pAsyncPB, 0, sizeof(CStdAsyncProxyBuffer)); // // Everything gets zeroed out regardless of their position // when mapping CStdBuffer vs. CstdBuffer2 into CStdAsyncBuffer // Non-delegated case. pAsyncPB->lpVtbl = & CStdAsyncProxyBufferVtbl; pAsyncPB->pProxyVtbl = & pProxyFileInfo->pProxyVtblList[j]->Vtbl; pAsyncPB->RefCount = 1; pAsyncPB->punkOuter = punkOuter ? punkOuter : (IUnknown *) pAsyncPB; pAsyncPB->pSyncIID = NdrGetProxyIID( &pSyncPB->pProxyVtbl ); // Note, no connection to channel yet. // Actually we never call create call on the channel. NdrpAsyncProxyMsgConstructor( pAsyncPB ); // Increment the DLL reference count for DllCanUnloadNow. // Same dll, so we can use the sync pPSFactory. // pSyncPB->pPSFactory->lpVtbl->AddRef( pSyncPB->pPSFactory ); // This is in the "map". ((CStdProxyBuffer *)pAsyncPB)->pPSFactory = pSyncPB->pPSFactory; // Just have it in both places. pAsyncPB->pPSFactory = pSyncPB->pPSFactory; *ppAsyncProxy = pAsyncPB; return S_OK; } HRESULT // CStdProxyBuffer2_CreateAsyncProxy( NdrpCreateDelegatedAsyncProxy( IN IRpcProxyBuffer *This, IN REFIID riid, // async IID IN IUnknown * punkOuter, // controlling unknown OUT CStdAsyncProxyBuffer ** ppAsyncProxy ) /* Creates a call object, i.e. an async proxy object. Note, because the call comes via a CStdProxyBuffer2, not Buffer, we know that we need to create only a delegated async proxy. */ { HRESULT hr; BOOL fFound; long j; // if index const ProxyFileInfo * pProxyFileInfo; CStdProxyBuffer2 * pSyncPB = (CStdProxyBuffer2 *)This; CStdAsyncProxyBuffer *pBaseAsyncPB; ICallFactory * pCallFactory; *ppAsyncProxy = 0; if ( ! pSyncPB->pCallFactoryVtbl || !pSyncPB->pAsyncIID ) return E_NOINTERFACE; if ( memcmp( &riid, pSyncPB->pAsyncIID, sizeof(IID)) != 0 ) return E_NOINTERFACE; // same file, so we can use the sync pPSFactory. fFound = NdrpFindInterface( ((CStdPSFactoryBuffer *)pSyncPB->pPSFactory)->pProxyFileList, riid, &pProxyFileInfo, & j); if ( !fFound ) return E_NOINTERFACE; // Create async proxy. CStdAsyncProxyBuffer *pAsyncPB = (CStdAsyncProxyBuffer*)(*pfnCoTaskMemAlloc)(sizeof(CStdAsyncProxyBuffer)); if( ! pAsyncPB ) return E_OUTOFMEMORY; memset( pAsyncPB, 0, sizeof(CStdAsyncProxyBuffer)); // // Everything gets zeroed out regardless of their position // when mapping CStdBuffer vs. CstdBuffer2 into CStdAsyncBuffer // Fill in for a delegated case. pAsyncPB->lpVtbl = & CStdAsyncProxyBuffer2Vtbl; pAsyncPB->pProxyVtbl = & pProxyFileInfo->pProxyVtblList[j]->Vtbl; pAsyncPB->RefCount = 1; pAsyncPB->punkOuter = punkOuter ? punkOuter : (IUnknown *) pAsyncPB; pAsyncPB->iidBase = *pProxyFileInfo->pDelegatedIIDs[j]; pAsyncPB->pPSFactory = pSyncPB->pPSFactory; pAsyncPB->pSyncIID = NdrGetProxyIID( &pSyncPB->pProxyVtbl ); // Note, no connection to channel yet. // So we cannot call create call on the channel. NdrpAsyncProxyMsgConstructor( pAsyncPB ); // Create an async proxy for the base interface. // We don't know if the base is delegated, so we have to use base call factory. // Get the call factory from the base proxy. hr = pSyncPB->pBaseProxyBuffer->lpVtbl->QueryInterface( pSyncPB->pBaseProxyBuffer, IID_ICallFactory, (void**)& pCallFactory ); if ( SUCCEEDED(hr) ) { const IID * pBaseAsyncIID; pBaseAsyncIID = *(const IID **)( (uchar*)pSyncPB->pBaseProxyBuffer + offsetof(CStdProxyBuffer, pAsyncIID)); // Aggregate the base async proxy with the current async proxy, // not with the channel's punkOuter. hr = pCallFactory->lpVtbl->CreateCall( pCallFactory, *pBaseAsyncIID, (IUnknown*) pAsyncPB, IID_IUnknown, (IUnknown**)& pBaseAsyncPB ); pCallFactory->lpVtbl->Release( pCallFactory ); } if ( SUCCEEDED(hr) ) { // Increment the DLL reference count for DllCanUnloadNow. // Same dll, so we can use the sync pPSFactory. // pSyncPB->pPSFactory->lpVtbl->AddRef( pSyncPB->pPSFactory ); // Hook up the base async proxy. pAsyncPB->pBaseProxyBuffer = (IRpcProxyBuffer*) pBaseAsyncPB; pAsyncPB->map.pBaseProxy = (IUnknown *) & pBaseAsyncPB->pProxyVtbl; *ppAsyncProxy = pAsyncPB; } else { (*pfnCoTaskMemFree)( pAsyncPB ); } return hr; } // // ICallFactory interface on the sync ProxyBuffer and ProxyBuffer2 objects. // HRESULT STDMETHODCALLTYPE CStdProxyBuffer_CF_QueryInterface( IN ICallFactory *This, IN REFIID riid, OUT void ** ppvObject) /*++ Routine Description: Query for an interface on the interface stub CallFactory pointer. Arguments: riid - Supplies the IID of the interface being requested. ppvObject - Returns a pointer to the requested interface. Return Value: S_OK E_NOINTERFACE Note: Works the same way for ProxyBuffer2 and AsyncProxyBuffer. --*/ { CStdProxyBuffer * pSyncPB = (CStdProxyBuffer *) ((uchar *)This - offsetof(CStdProxyBuffer,pCallFactoryVtbl)); return pSyncPB->punkOuter->lpVtbl->QueryInterface( pSyncPB->punkOuter, riid, ppvObject ); } ULONG STDMETHODCALLTYPE CStdProxyBuffer_CF_AddRef( IN ICallFactory *This) /*++ Routine Description: Implementation of AddRef for interface proxy. Arguments: Return Value: Reference count. --*/ { ULONG count; CStdProxyBuffer * pSyncPB = (CStdProxyBuffer *) ((uchar *)This - offsetof(CStdProxyBuffer,pCallFactoryVtbl)); // It needs to go through punkOuter. count = pSyncPB->punkOuter->lpVtbl->AddRef( pSyncPB->punkOuter ); return count; }; ULONG STDMETHODCALLTYPE CStdProxyBuffer_CF_Release( IN ICallFactory *This) /*++ Routine Description: Implementation of Release for interface proxy. Arguments: Return Value: Reference count. --*/ { ULONG count; CStdProxyBuffer2 * pSyncPB = (CStdProxyBuffer2 *) ((uchar *)This - offsetof(CStdProxyBuffer2,pCallFactoryVtbl)); count = pSyncPB->punkOuter->lpVtbl->Release( pSyncPB->punkOuter ); return count; }; HRESULT STDMETHODCALLTYPE CStdProxyBuffer_CF_CreateCall( IN ICallFactory *This, IN REFIID riid, IN IUnknown * punkOuter, // controlling unknown IN REFIID riid2, OUT IUnknown ** ppv ) /* Creates a call object, i.e. an async proxy object. Note, because the call comes via a CStdProxyBuffer, not Buffer2, we know that we need to create only a non-delegated async proxy. */ { CStdProxyBuffer * pSyncPB; if ( memcmp( &riid2, &IID_IUnknown, sizeof(IID)) != 0 ) return E_INVALIDARG; pSyncPB = (CStdProxyBuffer *) (((uchar *)This) - offsetof( CStdProxyBuffer, pCallFactoryVtbl )); return NdrpCreateNonDelegatedAsyncProxy( (IRpcProxyBuffer*) pSyncPB, riid, punkOuter, (CStdAsyncProxyBuffer**) ppv ); } HRESULT STDMETHODCALLTYPE CStdProxyBuffer2_CF_CreateCall( IN ICallFactory *This, IN REFIID riid, IN IUnknown * punkOuter, // controlling unknown IN REFIID riid2, OUT IUnknown ** ppv ) /* Creates a call object, i.e. an async proxy object. Note, because the virtual call comes via a CStdProxyBuffer2, we know that we need to create only a delegated async proxy. */ { CStdProxyBuffer2 * pSyncPB; if ( memcmp( &riid2, &IID_IUnknown, sizeof(IID)) != 0 ) return E_INVALIDARG; pSyncPB = (CStdProxyBuffer2 *) (((uchar *)This) - offsetof( CStdProxyBuffer2, pCallFactoryVtbl )); return NdrpCreateDelegatedAsyncProxy( (IRpcProxyBuffer*) pSyncPB, riid, punkOuter, (CStdAsyncProxyBuffer**) ppv ); } /* HRESULT STDAPICALLTYPE NdrClientReleaseMarshalBuffer( IN IRpcProxyBuffer *pProxy, IN RPCOLEMESSAGE * pMsg, IN DWORD dwFlags, IN IUnknown *pChnl) { CStdProxyBuffer * pSyncPB; void * This = NULL; HRESULT hr; if (NULL != pChnl) return E_INVALIDARG; if (dwFlags) return E_INVALIDARG; hr = pProxy->lpVtbl->QueryInterface(pProxy,&IID_IReleaseMarshalBuffers, &This); if (FAILED(hr)) return E_NOTIMPL; pSyncPB = (CStdProxyBuffer *) (((uchar *)This) - offsetof( CStdProxyBuffer, lpVtbl )); hr = NdrpClientReleaseMarshalBuffer(pSyncPB,(RPC_MESSAGE *)pMsg, dwFlags); ((IRpcProxyBuffer *)This)->lpVtbl->Release(This); return hr; } */ // // IUknown Query, AddRef and Release. // HRESULT STDMETHODCALLTYPE IUnknown_QueryInterface_Proxy( IN IUnknown * This, IN REFIID riid, OUT void ** ppv) /*++ Routine Description: Implementation of QueryInterface for interface proxy. Arguments: riid - Supplies the IID of the requested interface. ppv - Returns a pointer to the requested interface. Return Value: S_OK E_NOINTERFACE --*/ { HRESULT hr = E_NOINTERFACE; CStdProxyBuffer * pProxyBuffer; pProxyBuffer = NdrGetProxyBuffer(This); hr = pProxyBuffer->punkOuter->lpVtbl->QueryInterface( pProxyBuffer->punkOuter, riid, ppv); return hr; }; ULONG STDMETHODCALLTYPE IUnknown_AddRef_Proxy( IN IUnknown *This) /*++ Routine Description: Implementation of AddRef for interface proxy. Arguments: Return Value: Reference count. --*/ { CStdProxyBuffer * pProxyBuffer; ULONG count; pProxyBuffer = NdrGetProxyBuffer(This); count = pProxyBuffer->punkOuter->lpVtbl->AddRef(pProxyBuffer->punkOuter); return count; }; ULONG STDMETHODCALLTYPE IUnknown_Release_Proxy( IN IUnknown *This) /*++ Routine Description: Implementation of Release for interface proxy. Arguments: Return Value: Reference count. --*/ { CStdProxyBuffer * pProxyBuffer; ULONG count; pProxyBuffer = NdrGetProxyBuffer(This); count = pProxyBuffer->punkOuter->lpVtbl->Release(pProxyBuffer->punkOuter); return count; }; void RPC_ENTRY NdrProxyInitialize( IN void * pThis, IN PRPC_MESSAGE pRpcMsg, IN PMIDL_STUB_MESSAGE pStubMsg, IN PMIDL_STUB_DESC pStubDescriptor, IN unsigned int ProcNum ) /*++ Routine Description: Initialize the MIDL_STUB_MESSAGE. Arguments: pThis - Supplies a pointer to the interface proxy. pRpcMsg pStubMsg pStubDescriptor ProcNum Return Value: --*/ { CStdProxyBuffer * pProxyBuffer; HRESULT hr; pProxyBuffer = NdrGetProxyBuffer(pThis); // // Initialize the stub message fields. // NdrClientInitializeNew( pRpcMsg, pStubMsg, pStubDescriptor, ProcNum ); //Note that NdrClientInitializeNew sets RPC_FLAGS_VALID_BIT in the ProcNum. //We don't want to do this for object interfaces, so we clear the flag here. pRpcMsg->ProcNum &= ~RPC_FLAGS_VALID_BIT; pStubMsg->pRpcChannelBuffer = pProxyBuffer->pChannel; //Check if we are connected to a channel. if(pStubMsg->pRpcChannelBuffer != 0) { //AddRef the channel. //We will release it later in NdrProxyFreeBuffer. pStubMsg->pRpcChannelBuffer->lpVtbl->AddRef(pStubMsg->pRpcChannelBuffer); //Get the destination context from the channel hr = pStubMsg->pRpcChannelBuffer->lpVtbl->GetDestCtx( pStubMsg->pRpcChannelBuffer, &pStubMsg->dwDestContext, &pStubMsg->pvDestContext); } else { //We are not connected to a channel. RpcRaiseException(CO_E_OBJNOTCONNECTED); } } void RPC_ENTRY NdrProxyGetBuffer( IN void * pThis, IN PMIDL_STUB_MESSAGE pStubMsg) /*++ Routine Description: Get a message buffer from the channel Arguments: pThis - Supplies a pointer to the interface proxy. pStubMsg Return Value: None. If an error occurs, this function will raise an exception. --*/ { HRESULT hr; const IID * pIID = NdrGetProxyIID(pThis); pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength; pStubMsg->RpcMsg->DataRepresentation = NDR_LOCAL_DATA_REPRESENTATION; pStubMsg->dwStubPhase = PROXY_GETBUFFER; hr = pStubMsg->pRpcChannelBuffer->lpVtbl->GetBuffer( pStubMsg->pRpcChannelBuffer, (RPCOLEMESSAGE *) pStubMsg->RpcMsg, *pIID); pStubMsg->dwStubPhase = PROXY_MARSHAL; if(FAILED(hr)) { RpcRaiseException(hr); } else { NDR_ASSERT( ! ((ULONG_PTR)pStubMsg->RpcMsg->Buffer & 0x7), "marshaling buffer misaligned" ); pStubMsg->Buffer = (unsigned char *) pStubMsg->RpcMsg->Buffer; pStubMsg->fBufferValid = TRUE; } } void RPC_ENTRY NdrProxySendReceive( IN void * pThis, IN MIDL_STUB_MESSAGE * pStubMsg) /*++ Routine Description: Send a message to server, then wait for reply message. Arguments: pThis - Supplies a pointer to the interface proxy. pStubMsg Return Value: None. If an error occurs, this function will raise an exception. --*/ { HRESULT hr; DWORD dwStatus; //Calculate the number of bytes to send. if ( pStubMsg->RpcMsg->BufferLength < (uint)(pStubMsg->Buffer - (uchar *)pStubMsg->RpcMsg->Buffer)) { NDR_ASSERT( 0, "NdrProxySendReceive : buffer overflow" ); RpcRaiseException( RPC_S_INTERNAL_ERROR ); } pStubMsg->RpcMsg->BufferLength = (ulong)( pStubMsg->Buffer - (unsigned char *) pStubMsg->RpcMsg->Buffer ); pStubMsg->fBufferValid = FALSE; pStubMsg->dwStubPhase = PROXY_SENDRECEIVE; hr = pStubMsg->pRpcChannelBuffer->lpVtbl->SendReceive( pStubMsg->pRpcChannelBuffer, (RPCOLEMESSAGE *) pStubMsg->RpcMsg, &dwStatus); pStubMsg->dwStubPhase = PROXY_UNMARSHAL; if(FAILED(hr)) { switch(hr) { case RPC_E_FAULT: RpcRaiseException(dwStatus); break; default: RpcRaiseException(hr); break; } } else { NDR_ASSERT( ! ((ULONG_PTR)pStubMsg->RpcMsg->Buffer & 0x7), "marshaling buffer misaligned" ); pStubMsg->Buffer = (uchar*)pStubMsg->RpcMsg->Buffer; pStubMsg->BufferStart = pStubMsg->Buffer; pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->RpcMsg->BufferLength; pStubMsg->fBufferValid = TRUE; } } void RPC_ENTRY NdrProxyFreeBuffer( IN void * pThis, IN MIDL_STUB_MESSAGE * pStubMsg) /*++ Routine Description: Free the message buffer. Arguments: pThis - Supplies a pointer to the interface proxy. pStubMsg Return Value: None. --*/ { if(pStubMsg->pRpcChannelBuffer != 0) { //Free the message buffer. if(pStubMsg->fBufferValid == TRUE) { // If pipes, we need to reset the partial bit for some reason. pStubMsg->RpcMsg->RpcFlags &= ~RPC_BUFFER_PARTIAL; pStubMsg->pRpcChannelBuffer->lpVtbl->FreeBuffer( pStubMsg->pRpcChannelBuffer, (RPCOLEMESSAGE *) pStubMsg->RpcMsg); } //Release the channel. pStubMsg->pRpcChannelBuffer->lpVtbl->Release(pStubMsg->pRpcChannelBuffer); pStubMsg->pRpcChannelBuffer = 0; } } HRESULT RPC_ENTRY NdrProxyErrorHandler( IN DWORD dwExceptionCode) /*++ Routine Description: Maps an exception code into an HRESULT failure code. Arguments: dwExceptionCode Return Value: This function returns an HRESULT failure code. --*/ { HRESULT hr = dwExceptionCode; if(FAILED((HRESULT) dwExceptionCode)) hr = (HRESULT) dwExceptionCode; else hr = HRESULT_FROM_WIN32(dwExceptionCode); return hr; } HRESULT STDMETHODCALLTYPE CreateChannelWrapper /*++ Routine Description: Creates a wrapper for the channel. The wrapper ensures that we use the correct IID when the proxy for the base interface calls GetBuffer. Arguments: pIID pChannel pChannelWrapper Return Value: S_OK E_OUTOFMEMORY --*/ ( const IID * pIID, IRpcChannelBuffer * pChannel, IRpcChannelBuffer ** ppChannelWrapper ) { HRESULT hr; ChannelWrapper *pWrapper = (ChannelWrapper*)(*pfnCoTaskMemAlloc)(sizeof(ChannelWrapper)); if(pWrapper != 0) { hr = S_OK; pWrapper->lpVtbl = (IRpcChannelBufferVtbl*) &ChannelWrapperVtbl; pWrapper->RefCount = 1; pWrapper->pIID = pIID; pChannel->lpVtbl->AddRef(pChannel); pWrapper->pChannel = pChannel; *ppChannelWrapper = (IRpcChannelBuffer *) pWrapper; } else { hr = E_OUTOFMEMORY; *ppChannelWrapper = 0; } return hr; } HRESULT STDMETHODCALLTYPE CreateAsyncChannelWrapper /*++ Routine Description: Creates a wrapper for the channel. The wrapper ensures that we use the correct IID when the proxy for the base interface calls GetBuffer. Arguments: pIID pChannel pChannelWrapper Return Value: S_OK E_OUTOFMEMORY --*/ ( const IID * pIID, IRpcChannelBuffer * pChannel, IRpcChannelBuffer ** ppChannelWrapper ) { HRESULT hr; ChannelWrapper *pWrapper = (ChannelWrapper*)(*pfnCoTaskMemAlloc)(sizeof(ChannelWrapper)); if(pWrapper != 0) { hr = S_OK; pWrapper->lpVtbl = (IRpcChannelBufferVtbl*) &AsyncChannelWrapperVtbl; pWrapper->RefCount = 1; pWrapper->pIID = pIID; pChannel->lpVtbl->AddRef(pChannel); pWrapper->pChannel = pChannel; *ppChannelWrapper = (IRpcChannelBuffer *) pWrapper; } else { hr = E_OUTOFMEMORY; *ppChannelWrapper = 0; } return hr; } HRESULT STDMETHODCALLTYPE ChannelWrapper_QueryInterface /*++ Routine Description: The channel wrapper supports the IUnknown and IRpcChannelBuffer interfaces. Arguments: riid ppvObject Return Value: S_OK E_NOINTERFACE --*/ ( IRpcChannelBuffer3 * This, REFIID riid, void **ppvObject ) { HRESULT hr; if((memcmp(&riid, &IID_IUnknown, sizeof(IID)) == 0) || (memcmp(&riid, &IID_IRpcChannelBuffer, sizeof(IID)) == 0) || (memcmp(&riid, &IID_IRpcChannelBuffer2, sizeof(IID)) == 0) || (memcmp(&riid, &IID_IRpcChannelBuffer3, sizeof(IID)) == 0)) { hr = S_OK; This->lpVtbl->AddRef(This); *ppvObject = This; } else { hr = E_NOINTERFACE; *ppvObject = 0; } return hr; } HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_QueryInterface /*++ Routine Description: The channel wrapper supports the IUnknown and IRpcChannelBuffer interfaces. Arguments: riid ppvObject Return Value: S_OK E_NOINTERFACE --*/ ( IAsyncRpcChannelBuffer * This, REFIID riid, void ** ppvObject ) { HRESULT hr; if((memcmp(&riid, &IID_IUnknown, sizeof(IID)) == 0) || (memcmp(&riid, &IID_IRpcChannelBuffer, sizeof(IID)) == 0) || (memcmp(&riid, &IID_IRpcChannelBuffer2, sizeof(IID)) == 0) || (memcmp(&riid, &IID_IAsyncRpcChannelBuffer, sizeof(IID)) == 0)) { hr = S_OK; This->lpVtbl->AddRef(This); *ppvObject = This; } else { hr = E_NOINTERFACE; *ppvObject = 0; } return hr; } ULONG STDMETHODCALLTYPE ChannelWrapper_AddRef /*++ Routine Description: Increment reference count. Arguments: Return Value: Reference count. --*/ ( IRpcChannelBuffer3 * This ) { ChannelWrapper *pWrapper = (ChannelWrapper *) This; InterlockedIncrement(&pWrapper->RefCount); return (ULONG) pWrapper->RefCount; } ULONG STDMETHODCALLTYPE AsyncChannelWrapper_AddRef( IAsyncRpcChannelBuffer * This ) { return ChannelWrapper_AddRef( (IRpcChannelBuffer3 *) This ); } ULONG STDMETHODCALLTYPE ChannelWrapper_Release /*++ Routine Description: Decrement reference count. Arguments: Return Value: Reference count. --*/ ( IRpcChannelBuffer3 * This ) { unsigned long count; IRpcChannelBuffer * pChannel; NDR_ASSERT(((ChannelWrapper *)This)->RefCount > 0, "Invalid reference count"); count = (unsigned long) ((ChannelWrapper *)This)->RefCount - 1; if(InterlockedDecrement(&((ChannelWrapper *)This)->RefCount) == 0) { count = 0; pChannel = ((ChannelWrapper *)This)->pChannel; if(pChannel != 0) pChannel->lpVtbl->Release(pChannel); #if DBG == 1 //In debug builds, zero fill the memory. memset(This, '\0', sizeof(ChannelWrapper)); #endif //Free the memory (*pfnCoTaskMemFree)(This); } return count; } ULONG STDMETHODCALLTYPE AsyncChannelWrapper_Release( IAsyncRpcChannelBuffer * This ) { return ChannelWrapper_Release( (IRpcChannelBuffer3 *) This ); } HRESULT STDMETHODCALLTYPE ChannelWrapper_GetBuffer /*++ Routine Description: Get a message buffer from the channel. This is the reason we have the ChannelWrapper at all. We replace the riid of the current proxy by the one from the Wrapper. Arguments: pMessage riid Return Value: --*/ ( IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, REFIID riid ) { HRESULT hr; IRpcChannelBuffer * pChannel; const IID * pIID; pChannel = ((ChannelWrapper *)This)->pChannel; pIID = ((ChannelWrapper *)This)->pIID; hr = pChannel->lpVtbl->GetBuffer(pChannel, pMessage, *pIID); return hr; } HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_GetBuffer( IAsyncRpcChannelBuffer * This, RPCOLEMESSAGE * pMessage, REFIID riid ) { return ChannelWrapper_GetBuffer( (IRpcChannelBuffer3 *) This, pMessage, riid ); } HRESULT STDMETHODCALLTYPE ChannelWrapper_SendReceive /*++ Routine Description: Get a message buffer from the channel Arguments: pMessage pStatus Return Value: S_OK --*/ ( IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, ULONG * pStatus ) { HRESULT hr; IRpcChannelBuffer * pChannel; pChannel = ((ChannelWrapper *)This)->pChannel; hr = pChannel->lpVtbl->SendReceive(pChannel, pMessage, pStatus); return hr; } HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_SendReceive( IAsyncRpcChannelBuffer * This, RPCOLEMESSAGE * pMessage, ULONG * pStatus ) { // This can never happen for an async call stub. return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE ChannelWrapper_FreeBuffer /*++ Routine Description: Free the message buffer. Arguments: pMessage Return Value: S_OK --*/ ( IRpcChannelBuffer3 * This, RPCOLEMESSAGE *pMessage ) { HRESULT hr; IRpcChannelBuffer * pChannel; pChannel = ((ChannelWrapper *)This)->pChannel; hr = pChannel->lpVtbl->FreeBuffer(pChannel, pMessage); return hr; } HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_FreeBuffer( IAsyncRpcChannelBuffer * This, RPCOLEMESSAGE * pMessage ) { return ChannelWrapper_FreeBuffer( (IRpcChannelBuffer3 *) This, pMessage ); } HRESULT STDMETHODCALLTYPE ChannelWrapper_GetDestCtx /*++ Routine Description: Get the destination context from the channel Arguments: pdwDestContext ppvDestContext Return Value: S_OK --*/ ( IRpcChannelBuffer3 * This, DWORD * pdwDestContext, void ** ppvDestContext ) { HRESULT hr; IRpcChannelBuffer * pChannel; pChannel = ((ChannelWrapper *)This)->pChannel; hr = pChannel->lpVtbl->GetDestCtx(pChannel, pdwDestContext, ppvDestContext); return hr; } HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_GetDestCtx( IAsyncRpcChannelBuffer * This, DWORD * pdwDestContext, void ** ppvDestContext ) { return ChannelWrapper_GetDestCtx( (IRpcChannelBuffer3 *) This, pdwDestContext, ppvDestContext ); } HRESULT STDMETHODCALLTYPE ChannelWrapper_IsConnected /*++ Routine Description: Determines if the channel is connected. Arguments: Return Value: S_TRUE S_FALSE --*/ ( IRpcChannelBuffer3 * This ) { HRESULT hr; IRpcChannelBuffer * pChannel; pChannel = ((ChannelWrapper *)This)->pChannel; hr = pChannel->lpVtbl->IsConnected(pChannel); return hr; } HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_IsConnected( IAsyncRpcChannelBuffer * This ) { return ChannelWrapper_IsConnected( (IRpcChannelBuffer3 *) This ); } HRESULT STDMETHODCALLTYPE ChannelWrapper_GetProtocolVersion /*++ Routine Description: Returns the protocol version if available. Arguments: Return Value: S_OK E_NOINTERFACE --*/ ( IRpcChannelBuffer3 * This, DWORD * pdwVersion ) { HRESULT hr; IRpcChannelBuffer * pChannel; IRpcChannelBuffer2 * pChannel2; pChannel = ((ChannelWrapper *)This)->pChannel; hr = pChannel->lpVtbl->QueryInterface(pChannel, IID_IRpcChannelBuffer2, (void**)&pChannel2); if (S_OK == hr) { hr = pChannel2->lpVtbl->GetProtocolVersion(pChannel2, pdwVersion); pChannel2->lpVtbl->Release(pChannel2); } return hr; } HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_GetProtocolVersion( IAsyncRpcChannelBuffer * This, DWORD * pdwVersion ) { return ChannelWrapper_GetProtocolVersion( (IRpcChannelBuffer3 *) This, pdwVersion ); } HRESULT STDMETHODCALLTYPE ChannelWrapper_Send /*++ Routine Description: Executes an asynchronous or partial send. Arguments: Return Value: S_OK E_NOINTERFACE --*/ ( IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, ULONG * pStatus ) { HRESULT hr; IRpcChannelBuffer * pChannel; IRpcChannelBuffer3 * pChannel3; pChannel = ((ChannelWrapper *)This)->pChannel; hr = pChannel->lpVtbl->QueryInterface( pChannel, IID_IRpcChannelBuffer3, (void**)&pChannel3 ); if (S_OK == hr) { hr = pChannel3->lpVtbl->Send(pChannel3, pMessage, pStatus); pChannel3->lpVtbl->Release(pChannel3); } return hr; } HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_Send( /*++ Routine Description: Executes an asynchronous or partial send. Arguments: Return Value: S_OK E_NOINTERFACE --*/ IAsyncRpcChannelBuffer * This, RPCOLEMESSAGE * pMessage, ISynchronize * pSynchronize, ULONG * pStatus ) { HRESULT hr; IRpcChannelBuffer * pChannel; IAsyncRpcChannelBuffer * pAsChannel; pChannel = ((ChannelWrapper *)This)->pChannel; hr = pChannel->lpVtbl->QueryInterface( pChannel, IID_IAsyncRpcChannelBuffer, (void**)&pAsChannel ); if (S_OK == hr) { hr = pAsChannel->lpVtbl->Send( pAsChannel, pMessage, pSynchronize, pStatus); pAsChannel->lpVtbl->Release( pAsChannel); } return hr; } HRESULT STDMETHODCALLTYPE ChannelWrapper_Receive /*++ Routine Description: Executes an asynchronous or partial receive. Arguments: Return Value: S_OK E_NOINTERFACE --*/ ( IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, ULONG ulSize, ULONG * pStatus ) { HRESULT hr; IRpcChannelBuffer * pChannel; IRpcChannelBuffer3 * pChannel3; pChannel = ((ChannelWrapper *)This)->pChannel; hr = pChannel->lpVtbl->QueryInterface(pChannel, IID_IRpcChannelBuffer3, (void**)&pChannel3); if (S_OK == hr) { hr = pChannel3->lpVtbl->Receive( pChannel3, pMessage, ulSize, pStatus ); pChannel3->lpVtbl->Release(pChannel3); } return hr; } HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_Receive( /*++ Routine Description: Executes an asynchronous or partial receive. Arguments: Return Value: S_OK E_NOINTERFACE --*/ IAsyncRpcChannelBuffer * This, RPCOLEMESSAGE * pMessage, ULONG * pStatus ) { HRESULT hr; IRpcChannelBuffer * pChannel; IAsyncRpcChannelBuffer *pAsChannel; pChannel = ((ChannelWrapper *)This)->pChannel; hr = pChannel->lpVtbl->QueryInterface( pChannel, IID_IAsyncRpcChannelBuffer, (void**)&pAsChannel); if (S_OK == hr) { hr = pAsChannel->lpVtbl->Receive( pAsChannel, pMessage, pStatus ); pAsChannel->lpVtbl->Release(pAsChannel); } return hr; } HRESULT STDMETHODCALLTYPE ChannelWrapper_Cancel( /*++ Routine Description: Executes an asynchronous Cancel. Arguments: Return Value: S_OK E_NOINTERFACE --*/ IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage ) { HRESULT hr; IRpcChannelBuffer * pChannel; IRpcChannelBuffer3 * pChannel3; pChannel = ((ChannelWrapper *)This)->pChannel; hr = pChannel->lpVtbl->QueryInterface(pChannel, IID_IRpcChannelBuffer3, (void**)&pChannel3); if (S_OK == hr) { hr = pChannel3->lpVtbl->Cancel( pChannel3, pMessage ); pChannel3->lpVtbl->Release(pChannel3); } return hr; } HRESULT STDMETHODCALLTYPE ChannelWrapper_GetCallContext( /*++ Routine Description: Gets an asynchronous call context. Arguments: Return Value: S_OK E_NOINTERFACE --*/ IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, REFIID riid, void ** ppInterface ) { HRESULT hr; IRpcChannelBuffer * pChannel; IRpcChannelBuffer3 * pChannel3; pChannel = ((ChannelWrapper *)This)->pChannel; hr = pChannel->lpVtbl->QueryInterface(pChannel, IID_IRpcChannelBuffer3, (void**)&pChannel3); if (S_OK == hr) { hr = pChannel3->lpVtbl->GetCallContext( pChannel3, pMessage, riid, ppInterface ); pChannel3->lpVtbl->Release(pChannel3); } return hr; } HRESULT STDMETHODCALLTYPE AsyncChannelWrapper_GetDestCtxEx( /*++ Routine Description: Gets an asynchronous call context. Arguments: Return Value: S_OK E_NOINTERFACE --*/ IAsyncRpcChannelBuffer * This, RPCOLEMESSAGE * pMessage, DWORD * pdw, void ** ppv ) { HRESULT hr; IRpcChannelBuffer * pChannel; IAsyncRpcChannelBuffer * pAsChannel; pChannel = ((ChannelWrapper *)This)->pChannel; hr = pChannel->lpVtbl->QueryInterface( pChannel, IID_IAsyncRpcChannelBuffer, (void**)&pAsChannel); if (S_OK == hr) { hr = pAsChannel->lpVtbl->GetDestCtxEx( pAsChannel, pMessage, pdw, ppv ); pAsChannel->lpVtbl->Release(pAsChannel); } return hr; } HRESULT STDMETHODCALLTYPE ChannelWrapper_GetDestCtxEx( /*++ Routine Description: Gets the new destination context. Arguments: Return Value: S_OK E_NOINTERFACE --*/ IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, DWORD * pdwDestContext, void ** ppvDestContext ) { HRESULT hr; IRpcChannelBuffer * pChannel; IRpcChannelBuffer3 * pChannel3; pChannel = ((ChannelWrapper *)This)->pChannel; hr = pChannel->lpVtbl->QueryInterface(pChannel, IID_IRpcChannelBuffer3, (void**)&pChannel3); if (S_OK == hr) { hr = pChannel3->lpVtbl->GetDestCtxEx( pChannel3, pMessage, pdwDestContext, ppvDestContext ); pChannel3->lpVtbl->Release(pChannel3); } return hr; } HRESULT STDMETHODCALLTYPE ChannelWrapper_GetState( /*++ Routine Description: Gets the call state. Arguments: Return Value: S_OK E_NOINTERFACE --*/ IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, DWORD * pState ) { HRESULT hr; IRpcChannelBuffer * pChannel; IRpcChannelBuffer3 * pChannel3; pChannel = ((ChannelWrapper *)This)->pChannel; hr = pChannel->lpVtbl->QueryInterface(pChannel, IID_IRpcChannelBuffer3, (void**)&pChannel3); if (S_OK == hr) { hr = pChannel3->lpVtbl->GetState( pChannel3, pMessage, pState ); pChannel3->lpVtbl->Release(pChannel3); } return hr; } HRESULT STDMETHODCALLTYPE ChannelWrapper_RegisterAsync( /*++ Routine Description: Registers the async manager object and call with the channel. Arguments: Return Value: S_OK E_NOINTERFACE --*/ IRpcChannelBuffer3 * This, RPCOLEMESSAGE * pMessage, IAsyncManager * pAsyncMgr ) { HRESULT hr; IRpcChannelBuffer * pChannel; IRpcChannelBuffer3 * pChannel3; pChannel = ((ChannelWrapper *)This)->pChannel; hr = pChannel->lpVtbl->QueryInterface(pChannel, IID_IRpcChannelBuffer3, (void**)&pChannel3); if (S_OK == hr) { hr = pChannel3->lpVtbl->RegisterAsync( pChannel3, pMessage, pAsyncMgr ); pChannel3->lpVtbl->Release(pChannel3); } return hr; }