//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1997 // // File: pipes.cxx // // History: // RichN 10/30/97 Created. // //--------------------------------------------------------------------------- #include #include "pipes.hxx" ///////////////////////////////////////////////////////////////////////////// // Externals EXTERN_C HRESULT PrxDllGetClassObject(REFCLSID clsid, REFIID iid, void **ppv); extern HRESULT RemUnkPSGetClassObject(REFIID riid, PVOID* ppv); ////////////////////////////////////////////////////////////////////////////// // Constants const DWORD WAIT_INFINITE = DWORD(-1); const ULONG FRAGMENT_SIZE = 1300; typedef struct { const char *key; const char *value; } RegistryKeyValue; const RegistryKeyValue REG_CONST_KEY[] = { "CLSID\\{0000032E-0000-0000-C000-000000000046}", "PipePSFactory", "CLSID\\{0000032E-0000-0000-C000-000000000046}\\InprocServer32", "ole32.dll", "Interface\\{DB2F3ACA-2F86-11d1-8E04-00C04FB9989A}", "IPipeByte", "Interface\\{DB2F3ACA-2F86-11d1-8E04-00C04FB9989A}\\ProxyStubClsid32", "{0000032E-0000-0000-C000-000000000046}", "Interface\\{DB2F3ACC-2F86-11d1-8E04-00C04FB9989A}", "IPipeLong", "Interface\\{DB2F3ACC-2F86-11d1-8E04-00C04FB9989A}\\ProxyStubClsid32", "{0000032E-0000-0000-C000-000000000046}", "Interface\\{DB2F3ACE-2F86-11d1-8E04-00C04FB9989A}", "IPipeDouble", "Interface\\{DB2F3ACE-2F86-11d1-8E04-00C04FB9989A}\\ProxyStubClsid32", "{0000032E-0000-0000-C000-000000000046}", // Indicates end of list. "", "" }; ///////////////////////////////////////////////////////////////////////////// // Macros inline ULONG MIN( ULONG a, ULONG b ) { return a < b ? a : b; } inline ULONG MAX( ULONG a, ULONG b ) { return a < b ? b : a; } inline HRESULT MAKE_WIN32( HRESULT status ) { return MAKE_SCODE( SEVERITY_ERROR, FACILITY_WIN32, status ); } inline HRESULT FIX_WIN32( HRESULT result ) { if ((ULONG) result > 0xfffffff7 || (ULONG) result < 0x2000) return MAKE_WIN32( result ); else return result; } ///////////////////////////////////////////////////////////////////////////// // Globals #define DISABLEASYNC 0 ///////////////////////////////////////////////////////////////////////////// // Prototypes //+************************************************************************** // FixUpPipeRegistry(void) // // Description: Modifies the registry to have the pipe interface point // to a different class ID for the PSFactory. Adds to the // registry the new ID for the PipePSFactory. // // History: // Date: Time: Developer: Action: // 12/3/97 10:14:48 AM RichN Created. // // Notes: We do not change the async interfaces. They should still // be handled by ole32 directly. Only modify the synchronous varity. // //-************************************************************************** HRESULT FixUpPipeRegistry(void) { HRESULT result = ERROR_SUCCESS; // Create the Pipe interfaces and add the clsid for the PipePSFactory. for (int i = 0; (REG_CONST_KEY[i].key[0] != '\0') && result == ERROR_SUCCESS; i++) { // Use Ascii so it works on Win95. result = RegSetValueA( HKEY_CLASSES_ROOT, REG_CONST_KEY[i].key, REG_SZ, REG_CONST_KEY[i].value, strlen(REG_CONST_KEY[i].value) ); } if( result != ERROR_SUCCESS ) return FIX_WIN32( result ); return S_OK; } //+************************************************************************** // ProxyDllGetClassObject(REFCLSID clsid, REFIID iid, void **ppv) // // Description: Creates a proxy. Trys PrxDllGetClassObject first since that // is the most likely. If not, then sees if it is the pipe // proxy being created. // // History: // Date: Time: Developer: Action: // 10/30/97 11:43:55 AM RichN Created. // // Notes: // //-************************************************************************** EXTERN_C HRESULT ProxyDllGetClassObject(REFCLSID clsid, REFIID riid, void **ppv) { ComDebOut(( DEB_MARSHAL, "ProxyDllGetClassObject, clsid: %l, riid: %l \n", clsid, riid)); HRESULT hr = PrxDllGetClassObject(clsid, riid, ppv); if( FAILED(hr) ) { // Not a well known one, maybe it is the pipe factory. if( clsid == CLSID_PipePSFactory ) { // Create the pipe proxy/stub class factory CPipePSFactory *pPipePSFactory = new CPipePSFactory(); if( NULL != pPipePSFactory ) { // Get the interface Requested. hr = pPipePSFactory->QueryInterface(riid, ppv); pPipePSFactory->Release(); } else { *ppv = NULL; hr = E_OUTOFMEMORY; } } else if (clsid == CLSID_RemoteUnknownPSFactory) { hr = RemUnkPSGetClassObject(riid, ppv); } } return hr; } //+************************************************************************** // CPipePSFactory() // // Description: CTOR // // History: // Date: Time: Developer: Action: // 10/30/97 12:55:55 PM RichN Created. // // Notes: // //-************************************************************************** CPipePSFactory::CPipePSFactory() : m_cRef(1) { ComDebOut(( DEB_MARSHAL, "CPipePSFactory - ctor, this:%x \n", this)); } //+************************************************************************** // CPipePSFactory() // // Description: DTOR // // History: // Date: Time: Developer: Action: // 10/30/97 12:56:19 PM RichN Created. // // Notes: // //-************************************************************************** CPipePSFactory::~CPipePSFactory() { ComDebOut(( DEB_MARSHAL, "CPipePSFactory - dtor, this:%x \n")); } //+************************************************************************** // QueryInterface(REFIID riid, LPVOID FAR* ppvObj) // // Description: Standard QI // // History: // Date: Time: Developer: Action: // 10/30/97 11:10:58 AM RichN Created. // // Notes: // //-************************************************************************** STDMETHODIMP CPipePSFactory::QueryInterface(REFIID riid, LPVOID FAR* ppvObj) { ComDebOut(( DEB_MARSHAL, "CPipePSFactory::QueryInterface, this:%x, riid:%i \n", this, riid)); if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IPSFactoryBuffer) ) { *ppvObj = (IPSFactoryBuffer *) this; } else { *ppvObj = NULL; return E_NOINTERFACE; } ((IUnknown *)*ppvObj)->AddRef(); return S_OK; } //+************************************************************************** // CPipePSFactory::AddRef() // // Description: Standard AddRef // // History: // Date: Time: Developer: Action: // 10/30/97 11:11:16 AM RichN Created. // // Notes: // //-************************************************************************** STDMETHODIMP_(ULONG) CPipePSFactory::AddRef() { ComDebOut(( DEB_MARSHAL, "CPipePSFactory::AddRef, this:%x, m_cRef:%d \n", this, m_cRef + 1)); return InterlockedIncrement( &m_cRef ); } //+************************************************************************** // CPipePSFactory::Release() // // Description: Standard Release // // History: // Date: Time: Developer: Action: // 10/30/97 11:11:31 AM RichN Created. // // Notes: // //-************************************************************************** STDMETHODIMP_(ULONG) CPipePSFactory::Release() { ComDebOut(( DEB_MARSHAL, "CPipePSFactory::Release, this:%x, m_cRef:%d \n", this, m_cRef - 1)); ULONG lRef; if( (lRef = InterlockedDecrement( &m_cRef )) == 0) { delete this; return 0; } return lRef; } //+************************************************************************** // CreateProxy // // Description: Creates a pipe proxy. // // History: // Date: Time: Developer: Action: // 10/30/97 11:11:45 AM RichN Created. // // Notes: We will pass back to the call a ptr to our object and we will // hold a pointer to the real proxy. When the client calls us, we // can do whatever we want/need to do and then call the real proxy. // //-************************************************************************** STDMETHODIMP CPipePSFactory::CreateProxy( IUnknown *pUnkOuter, REFIID riid, IRpcProxyBuffer **ppProxy, void **ppv ) { ComDebOut(( DEB_MARSHAL, "CreateProxy, pUnkOuter:%x riid:%I \n", pUnkOuter, riid)); if( NULL == ppv || NULL == ppProxy ) return E_INVALIDARG; *ppProxy = NULL; *ppv = NULL; IPSFactoryBuffer *pPSFactory; // Create the real PSFactory for the pipe interface. HRESULT hr = PrxDllGetClassObject( riid, IID_IPSFactoryBuffer, (void **) &pPSFactory); IUnknown *pNDRPipeProxy = NULL; IRpcProxyBuffer *pInternalProxyBuffer = NULL; if( SUCCEEDED(hr) ) { // Create the real proxy. hr = pPSFactory->CreateProxy( pUnkOuter, riid, &pInternalProxyBuffer, (void **)&pNDRPipeProxy); pPSFactory->Release(); } if( FAILED(hr) ) return hr; if( IID_IPipeByte == riid ) { *ppv = new CPipeProxy (pUnkOuter, pNDRPipeProxy); } else if( IID_IPipeLong == riid ) { *ppv = new CPipeProxy (pUnkOuter, pNDRPipeProxy); } else if( IID_IPipeDouble == riid ) { *ppv = new CPipeProxy (pUnkOuter, pNDRPipeProxy); } else { hr = E_NOINTERFACE; } if( SUCCEEDED(hr) && NULL == *ppv) hr = E_OUTOFMEMORY; // Create the object that contains the IRpcProxyBuffer // and the pipe interface. Created with refcount of 1. if( SUCCEEDED(hr) ) { CPipeProxyImp *pProxyImp = new CPipeProxyImp(pUnkOuter, pInternalProxyBuffer, pNDRPipeProxy, (IUnknown*) *ppv, riid); if( NULL == pProxyImp ) { hr = E_OUTOFMEMORY; } else *ppProxy = (IRpcProxyBuffer *) pProxyImp; } // Clean up failure. if( FAILED(hr) ) { if( NULL != *ppv ) { delete *ppv; *ppv = NULL; } pNDRPipeProxy->Release(); pInternalProxyBuffer->Release(); } return hr; } //+************************************************************************** // CreateStub // // Description: Creates a pipe stub. // // History: // Date: Time: Developer: Action: // 10/30/97 11:12:46 AM RichN Created. // // Notes: // //-************************************************************************** STDMETHODIMP CPipePSFactory::CreateStub( REFIID riid, IUnknown *pUnkServer, IRpcStubBuffer **ppStub ) { ComDebOut(( DEB_MARSHAL, "CreateStub, riid:%x pUnkServer:%x \n", riid, pUnkServer )); HRESULT hr = S_OK; IPSFactoryBuffer *pPSFactory; // Create the real PSFactory for the pipe interface. hr = PrxDllGetClassObject( riid, IID_IPSFactoryBuffer, (void **) &pPSFactory); // Call real factory to get stub. if( SUCCEEDED(hr) ) { hr = pPSFactory->CreateStub(riid, pUnkServer, ppStub); pPSFactory->Release(); } return hr; } //+************************************************************************** // CPipePoxyImp(IRpcProxyBuffer *pInternalPB, IUnknown *pPipe) // // Description: CTOR // // History: // Date: Time: Developer: Action: // 11/11/97 11:31:43 AM RichN Created. // // Notes: // //-************************************************************************** CPipeProxyImp::CPipeProxyImp(IUnknown *pUnkOuter, IRpcProxyBuffer *pInternalPB, IUnknown *pRealPipeProxy, IUnknown *pInternalPipeProxy, IID iid) : m_cRef (1), m_pInternalPipeProxy(pInternalPipeProxy), m_pInternalPB (pInternalPB), m_pRealPipeProxy (pRealPipeProxy), m_pUnkOuter (pUnkOuter), m_IidOfPipe (iid) { ComDebOut(( DEB_MARSHAL, "CPipeProxyImp ctor, this:%x \n")); Win4Assert(NULL != m_pInternalPB); Win4Assert(NULL != m_pRealPipeProxy); Win4Assert(NULL != m_pInternalPipeProxy); } //+************************************************************************** // CPipeProxyImp() // // Description: DTOR // // History: // Date: Time: Developer: Action: // 11/11/97 11:32:02 AM RichN Created. // // Notes: // //-************************************************************************** CPipeProxyImp::~CPipeProxyImp() { ComDebOut(( DEB_MARSHAL, "~CPipeProxyImp, this:%x \n", this)); // AddRef the outer because we are aggregated. m_pUnkOuter->AddRef(); // Delete the internal proxy. if( NULL != m_pInternalPipeProxy ) { delete m_pInternalPipeProxy; m_pInternalPipeProxy = NULL; } // Release the real proxy. if( NULL != m_pRealPipeProxy ) { m_pRealPipeProxy->Release(); m_pRealPipeProxy = NULL; } // Release the pointer to the IRpcProxyBuffer if( NULL != m_pInternalPB ) m_pInternalPB->Release(); } //+************************************************************************** // QueryInterface(REFIID riid, LPVOID FAR* ppvObj) // // Description: QI // // History: // Date: Time: Developer: Action: // 11/11/97 11:36:15 AM RichN Created. // // Notes: // //-************************************************************************** STDMETHODIMP CPipeProxyImp::QueryInterface(REFIID riid, LPVOID FAR* ppvObj) { ComDebOut(( DEB_MARSHAL, "QueryInterface, this:%x \n", this)); HRESULT hr = S_OK; if( NULL == ppvObj ) return E_INVALIDARG; if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IRpcProxyBuffer) ) { *ppvObj = (IUnknown *) this; } else if( IsEqualIID(riid, m_IidOfPipe) ) { *ppvObj = m_pInternalPipeProxy; } else { return m_pInternalPB->QueryInterface(riid, ppvObj); } ((IUnknown *)(*ppvObj))->AddRef(); return hr; } //+************************************************************************** // CPipeProxyImp::AddRef() // // Description: AddRef // // History: // Date: Time: Developer: Action: // 11/11/97 11:36:34 AM RichN Created. // // Notes: // //-************************************************************************** STDMETHODIMP_(ULONG) CPipeProxyImp::AddRef() { return InterlockedIncrement( &m_cRef ); } //+************************************************************************** // CPipeProxyImp::Release() // // Description: // // History: // Date: Time: Developer: Action: // 11/11/97 11:36:48 AM RichN Created. // // Notes: // //-************************************************************************** STDMETHODIMP_(ULONG) CPipeProxyImp::Release() { ULONG lRef; if( (lRef = InterlockedDecrement( &m_cRef )) == 0) { delete this; return 0; } return lRef; } //+************************************************************************** // Connect(IRpcChannelBuffer *pRpcChannelBuffer) // // Description: Simple pass through. // // History: // Date: Time: Developer: Action: // 11/11/97 11:36:59 AM RichN Created. // // Notes: // //-************************************************************************** STDMETHODIMP CPipeProxyImp::Connect(IRpcChannelBuffer *pRpcChannelBuffer) { return m_pInternalPB->Connect(pRpcChannelBuffer); } //+************************************************************************** // Disconnect( void ) // // Description: Simple pass through. // // History: // Date: Time: Developer: Action: // 11/11/97 11:37:25 AM RichN Created. // // Notes: // //-************************************************************************** STDMETHODIMP_(void) CPipeProxyImp::Disconnect( void ) { m_pInternalPB->Disconnect(); } template //+************************************************************************** // CPipeProxy( void * pProxy ): // // Description:CTOR // // History: // Date: Time: Developer: Action: // 11/11/97 11:43:00 AM RichN Created. // // Notes: // //-************************************************************************** CPipeProxy ::CPipeProxy(IUnknown *pUnkOuter, void * pProxy ): m_cFreeSpace (0), m_cKeepBufferSize (0), m_cKeepDataSize (0), m_cLastRead (0), m_cPushBufferSize (0), m_cReadAhead (0), m_cRef (0), m_pAsyncPullPipe (NULL), m_pAsyncPushPipe (NULL), m_pFreeSpace (NULL), m_pISyncPull (NULL), m_pISyncPush (NULL), m_pKeepBuffer (NULL), m_pKeepData (NULL), m_pRealProxy ((I *)pProxy), m_pUnkOuter (pUnkOuter), m_pPushBuffer (NULL), m_PullState (PULLSTATE0_ENTRY), m_PushState (PUSHSTATE0_ENTRY) { ComDebOut(( DEB_MARSHAL, "CPipeProxy, pUnkOuter:%x pProxy:%x p \n", pUnkOuter, pProxy)); Win4Assert(NULL != m_pUnkOuter); Win4Assert(NULL != m_pRealProxy); // Fill in the array of functions for the pull states. PullStateFunc[0] = NULL; // Should never execute in state zero. PullStateFunc[1] = NbNaRgtRA1; // No Buffer, No async outstanding, Request > Read ahead PullStateFunc[2] = NbaRltRA2; // No Buffer, async call outstanding, Request < Read Ahead PullStateFunc[3] = NbaRgtRA3; // No Buffer, async, Req >= Read ahead PullStateFunc[4] = baRltB4; // Buffer, async, Request < Buffer size PullStateFunc[5] = baRgtB5; // Buffer, async, Request >= Buffer size PullStateFunc[6] = PullDone6; // done. // Fill in the array of functions for the push states. PushStateFunc[0] = NULL; // Should never execute in state zero. PushStateFunc[1] = NbNf1; // No Buffer, No free buffer space PushStateFunc[2] = bfPgtF2; // Buffer, free space in buffer, push size >= free size PushStateFunc[3] = bfPltF3; // Buffer, free, push < free PushStateFunc[4] = bPSz4; // Buffer, push size zero PushStateFunc[5] = PushDone5; // Done #if DBG==1 for(int i = 1; i < MAX_PULL_STATES; i++) Win4Assert(PullStateFunc[i] != NULL); for(i = 1; i < MAX_PUSH_STATES; i++) Win4Assert(PushStateFunc[i] != NULL); #endif return; } template //+************************************************************************** // CPipeProxy( void ) // // Description: DTOR // // History: // Date: Time: Developer: Action: // 11/11/97 11:43:20 AM RichN Created. // // Notes: Addref the outer unknown and then release the pointer to the // real proxy. // //-************************************************************************** CPipeProxy ::~CPipeProxy( void ) { Win4Assert(NULL != m_pUnkOuter); Win4Assert(NULL != m_pRealProxy); } //+************************************************************************** // QueryInterface(REFIID riid, LPVOID FAR* ppvObj) // // Description: IUnknown implementation. All delegate to outer unknown. // // History: // Date: Time: Developer: Action: // 11/11/97 11:48:42 AM RichN Created. // // Notes: // //-************************************************************************** template STDMETHODIMP CPipeProxy ::QueryInterface(REFIID riid, LPVOID FAR* ppvObj) { return m_pUnkOuter->QueryInterface(riid, ppvObj); } template STDMETHODIMP_(ULONG) CPipeProxy ::AddRef() { m_cRef++; return m_pUnkOuter->AddRef(); } template STDMETHODIMP_(ULONG) CPipeProxy ::Release() { m_cRef--; return m_pUnkOuter->Release(); } template //+************************************************************************** // Pull( T *Buf, ULONG Request, ULONG *Received) // // Description: Pull the data from the server. // // History: // Date: Time: Developer: Action: // 11/11/97 11:49:18 AM RichN Created. // // Notes: We read data ahead by using async calls. The size of the // read ahead can be controled by the user by implementing // the IPipeHueristic and setting it on the interface. // //-************************************************************************** STDMETHODIMP CPipeProxy ::Pull( T *Buf, ULONG Request, ULONG *Received) { ComDebOut(( DEB_MARSHAL, "Pull, this:%x, Buf:%x, Request:%d, Received:%x \n", this, Buf, Request, Received)); if( 0 == Request ) return E_UNEXPECTED; HRESULT hr; // For debugging it is sometimes useful to disable // the async read ahead. #if DISABLEASYNC==1 hr = m_pRealProxy->Pull(Buf, Request, Received); return hr; #endif *Received = 0; // Transition to the next state. hr = PullStateTransition( Request ); // Should never see state 0. Win4Assert(0 != m_PullState); // Call the function for the new state. if( SUCCEEDED(hr) ) { hr = (this->*(PullStateFunc[m_PullState]))( Buf, Request, Received ); } return hr; } template //+************************************************************************** // Push( T *Buf, ULONG count) // // Description: Pushes data to the server. // // History: // Date: Time: Developer: Action: // 11/11/97 11:49:39 AM RichN Created. // // Notes: // //-************************************************************************** STDMETHODIMP CPipeProxy ::Push( T *Buf, ULONG Count) { ComDebOut(( DEB_MARSHAL, "Push, this:%x, Buf:%x, Count:%u \n", this, Buf, Count)); HRESULT hr; // For debugging it is sometimes useful to disable // write behind. #if DISABLEASYNC==1 hr = m_pRealProxy->Push(Buf, Count); return hr; #endif // Transition to the next state. hr = PushStateTransition( Count ); // Should never see state 0. Win4Assert(0 != m_PushState); // Call the function for the new state. if( SUCCEEDED(hr) ) { hr = (this->*(PushStateFunc[m_PushState]))( Buf, Count ); } return hr; } template //+************************************************************************** // InitAsync(void) // // Description: Initializes, gets, the pointers to the async parts. // // History: // Date: Time: Developer: Action: // 12/8/97 4:45:22 PM RichN Created. // // Notes: // //-************************************************************************** HRESULT CPipeProxy ::InitAsync(IUnknown** ppCallObj, AsyncI** ppAsyncPipe, ISynchronize** ppISync) { ComDebOut(( DEB_MARSHAL, "InitAsync, this:%x \n", this)); Win4Assert(NULL != m_pRealProxy); Win4Assert(NULL == (*ppAsyncPipe)); Win4Assert(NULL == (*ppISync)); HRESULT hr; ICallFactory *pCF = NULL; hr = m_pRealProxy->QueryInterface(IID_ICallFactory, (void **) &pCF); if( FAILED(hr) ) return hr; hr = pCF->CreateCall(*AsyncID, NULL, IID_IUnknown, ppCallObj); pCF->Release(); if( FAILED(hr) ) return hr; hr = (*ppCallObj)->QueryInterface(*AsyncID, (void **) ppAsyncPipe); if( FAILED(hr) ) goto ErrorCallObj; hr = (*ppCallObj)->QueryInterface(IID_ISynchronize, (void **) ppISync); if( FAILED(hr) ) goto ErrorAsyncPipe; return S_OK; ErrorAsyncPipe: (*ppAsyncPipe)->Release(); (*ppAsyncPipe) = NULL; ErrorCallObj: (*ppCallObj)->Release(); (*ppCallObj) = NULL; return hr; } template //+************************************************************************** // CleanupProxy(IUnknown* pCallObj, IUnknown* pAsyncPipe, ISynchronize* pISync) // // Description: Cleans up all the async interfaces acquired. // // History: // Date: Time: Developer: Action: // 12/16/97 11:42:42 AM RichN Created. // // Notes: // //-************************************************************************** void CPipeProxy ::CleanupProxy(T ** ppBuffer, IUnknown** ppCallObj, AsyncI** ppAsyncPipe, ISynchronize** ppISync) { if( *ppBuffer ) { delete (*ppBuffer); (*ppBuffer) = NULL; } if( NULL != (*ppISync) ) { (*ppISync)->Release(); *ppISync = NULL; } if( NULL != (*ppAsyncPipe) ) { (*ppAsyncPipe)->Release(); *ppAsyncPipe = NULL; } if( NULL != (*ppCallObj) ) { (*ppCallObj)->Release(); *ppCallObj = NULL; } } template //+************************************************************************** // CancelTheCall(DWORD delay) // // Description: Cancel the currently outstanding call. // // History: // Date: Time: Developer: Action: // 12/9/97 10:59:54 AM RichN Created. // // Notes: // //-************************************************************************** void CPipeProxy ::CancelTheCall(IUnknown *pCallObj, DWORD delay) { ComDebOut(( DEB_MARSHAL, "CancelTheCall, this:%x \n", this)); ICancelMethodCalls *pICancel; HRESULT hr = pCallObj->QueryInterface(IID_ICancelMethodCalls, (void **) &pICancel); if( FAILED(hr) ) return; pICancel->Cancel(delay); pICancel->Release(); return; } template //+************************************************************************** // SetReadAhead(ULONG Request) // // Description: Determine the size of the read ahead. // // History: // Date: Time: Developer: Action: // 11/20/97 10:01:10 AM RichN Created. // // Notes: // //-************************************************************************** void CPipeProxy ::SetReadAhead(ULONG Request) { ComDebOut(( DEB_MARSHAL, "SetReadAhead, this:%x Request:%u \n", this, Request)); Win4Assert(Request != 0); switch(m_PullState) { case PULLSTATE1_FIRST_CALL : // On the first call just set the read ahead to the request. // This assumes that the request will be constant and // we will be one call ahead all the time. m_cReadAhead = Request; break; case PULLSTATE2_NS_RQlsRA : // We haven't had a zero read or we wouldn't be here Win4Assert(m_cLastRead != 0); // Set the read ahead to the lesser of the request and the // amount last read. We are trying to match the read ahead with // the request by assuming a constant request, but the server // may only return a given amount regardless of what we // request. m_cReadAhead = MIN(Request, m_cLastRead); break; case PULLSTATE3_NS_RQgeRA : case PULLSTATE5_S_RQgeBS : // No zero read Win4Assert(m_cLastRead != 0); // The request is greater than what was asked for last time. So // we increase the read ahead to the max of the request or what // was actually read last time. m_cReadAhead = MAX(Request, m_cLastRead); break; default : // For all other states we should not be making read ahead calls. // Mostly because we read zero elements last time which indicates // the end of the data. The PULLSTATE4_S_RQlsBS doesn't do a read // ahead so we shouldn't be here while in that state. Win4Assert(FALSE && "Request read ahead in wrong state."); } Win4Assert( 0 != m_cReadAhead ); } template //+************************************************************************** // CheckAndSetKeepBuffer() // // Description: Check to see if the Buffer is the correct size and if not // make it the correct size. // // History: // Date: Time: Developer: Action: // 11/19/97 3:27:25 PM RichN Created. // // Notes: The buffer will never get smaller. // //-************************************************************************** HRESULT CPipeProxy ::CheckAndSetKeepBuffer(void) { Win4Assert(0 != m_cReadAhead); // Create a keep buffer the size of the read ahead. // We assume here that the user will not change the // request size and that the amount of data on hand // will never be larger. When it is we will re-allocate. // The buffer will never get smaller. Something to look at. if( m_cKeepBufferSize >= m_cReadAhead ) return S_OK; T *temp = new T[m_cReadAhead]; if( NULL == temp ) { delete[] m_pKeepBuffer; m_pKeepBuffer = NULL; return E_OUTOFMEMORY; } if( m_pKeepBuffer != NULL ) { // Copy the data into the new buffer memcpy(temp, m_pKeepBuffer, m_cKeepDataSize * sizeof(T)); // Delete the old buffer and reset the bookkeeping. delete[] m_pKeepBuffer; } m_pKeepBuffer = temp; m_cKeepBufferSize = m_cReadAhead; m_pKeepData = m_pKeepBuffer + m_cKeepDataSize; return S_OK; } template //+************************************************************************** // PullStateTransition(ULONG Request) // // Description: Transition from one state to the next. See pipes document // for a description of the state machine. // // History: // Date: Time: Developer: Action: // 11/11/97 4:20:19 PM RichN Created. // // Notes: // //-************************************************************************** HRESULT CPipeProxy ::PullStateTransition(ULONG Request) { ComDebOut(( DEB_MARSHAL, "PullStateTransition \n")); Win4Assert(Request > 0); switch( m_PullState ) { case PULLSTATE0_ENTRY: // Transition to the first call state. m_PullState = PULLSTATE1_FIRST_CALL; break; case PULLSTATE1_FIRST_CALL: // If the last read was zero we are done. We have no stored // data so go to the state that handles request // that are either less than or greater than or // equal to the last read ahead. Realize the amount of // data returned from the last read ahead may // not equal the requeat and could be greater than or less than. if( 0 == m_cLastRead ) m_PullState = PULLSTATE6_DONE; else m_PullState = (Request < m_cReadAhead) ? PULLSTATE2_NS_RQlsRA : PULLSTATE3_NS_RQgeRA; break; case PULLSTATE2_NS_RQlsRA: // In this state, either the last read is not zero or // the amount of data remaining is zero. Whatever state // we get to this one from does not go here on a last read // of zero nor if there is any data in the buffer (kept data). // Possible we where in this state and got a last // read of zero, in which case the amount of held data will // be = zero. We are in a state with no held data and got // a zero read of data, there can't be any kept data. Win4Assert(!( m_cLastRead == 0 && m_cKeepDataSize > 0)); // If we had a zero read, we cleaned up in // this state and go to the state that just returns zero. if( 0 == m_cLastRead) { Win4Assert( 0 == m_cKeepDataSize ); m_PullState = PULLSTATE6_DONE; } else { // If the kept data is zero, then we need to go to a state // that understands an empty buffer. Determine which one // by the request and the read ahead. // If there is kept data then go to a state that understands // a non empty buffer. This time the correct one depends on // the amount of data in the buffer. if( 0 == m_cKeepDataSize ) m_PullState = ( Request < m_cReadAhead ) ? PULLSTATE2_NS_RQlsRA : PULLSTATE3_NS_RQgeRA; else m_PullState = ( Request < m_cKeepDataSize) ? PULLSTATE4_S_RQlsBS : PULLSTATE5_S_RQgeBS; } break; case PULLSTATE3_NS_RQgeRA: // We can never leave this state with data in the buffer. The // request is greater than the read ahead and the returned amount // of data can never be greater than the requested data, but it // could be less. Win4Assert(m_cKeepDataSize == 0); // If the last read was zero go to the done state. // else go to the state that understands empty buffers depending // on the request and the read ahead. if( 0 == m_cLastRead ) m_PullState = PULLSTATE6_DONE; else m_PullState = ( Request < m_cReadAhead ) ? PULLSTATE2_NS_RQlsRA : PULLSTATE3_NS_RQgeRA; break; case PULLSTATE4_S_RQlsBS: // When this state was entered there was data in the buffer. The // request was for less than the buffer size so when we returned // there should have still been data in the buffer. No read is done. Win4Assert(m_cKeepDataSize > 0); Win4Assert(m_cLastRead > 0); // Go to the state that handles data in the buffer // depending on the request and the amount of data in the buffer. m_PullState = ( Request < m_cKeepDataSize ) ? PULLSTATE4_S_RQlsBS : PULLSTATE5_S_RQgeBS; break; case PULLSTATE5_S_RQgeBS: // Because we can fulfill at aleast part of the request from // the buffer, we don't wait on the async call to finish. If it // did finish (wait 0 tells us that) then there is data in the // buffer (assuming it returned data) otherwise it is empty. // So when the call finished last time the buffer // could be empty or not. If the read was zero the buffer is empty. Win4Assert( (m_cLastRead == 0 && m_cKeepDataSize == 0) || m_cLastRead != 0 ); // If the buffer is empty then on a zero last read go to done. // Otherwise go to a state that understands empty buffers depending // on the request size and the read ahead. if( 0 == m_cKeepDataSize ) if( 0 == m_cLastRead ) m_PullState = PULLSTATE6_DONE; else m_PullState = ( Request < m_cReadAhead ) ? PULLSTATE2_NS_RQlsRA : PULLSTATE3_NS_RQgeRA; else // Otherwise go to one that understands having data in the // buffer depending on the request and the amount of data in // the buffer. m_PullState = ( Request < m_cKeepDataSize ) ? PULLSTATE4_S_RQlsBS : PULLSTATE5_S_RQgeBS; break; case PULLSTATE6_DONE: // When in this state there better not be any data left and // the last read must be zero. Win4Assert(m_cKeepDataSize == 0); Win4Assert(m_cLastRead == 0); m_PullState = PULLSTATE1_FIRST_CALL; break; default: return E_UNEXPECTED; } return S_OK; } template //+************************************************************************** // NbNaRgtRA1 // // Description: Pull, No data in buffer, no async call outstanding and // request is >= read ahead. State 1. // // History: // Date: Time: Developer: Action: // 11/19/97 2:30:11 PM RichN Created. // // Notes: Make a sync call to get some data and then make an async call to // read ahead. // //-************************************************************************** HRESULT CPipeProxy ::NbNaRgtRA1(T *Buf, ULONG Request, ULONG *Received) { ComDebOut(( DEB_MARSHAL, "NbNaRgtRA1 Request:%d\n", Request)); Win4Assert(1 == m_PullState); Win4Assert(NULL != Buf); // State conditions Win4Assert(0 == m_cLastRead ); Win4Assert(0 == m_cKeepDataSize); HRESULT hr = S_OK; // We are only in this state one time. There will always be // an out standing async call, so we init async here. hr = InitAsync(&m_pPullCallObj, &m_pAsyncPullPipe, &m_pISyncPull); if( FAILED(hr) ) return hr; // make a sync call to get started. hr = m_pRealProxy->Pull(Buf, Request, Received); m_cLastRead = *Received; if( m_cLastRead > 0 && SUCCEEDED(hr)) { SetReadAhead(Request); // Make the async call. hr = m_pAsyncPullPipe->Begin_Pull(m_cReadAhead); } else { CleanupProxy(&m_pKeepBuffer, &m_pPullCallObj, &m_pAsyncPullPipe, &m_pISyncPull); } // Post condition // Wouldn't expect the last read to be zero here, but no reason // it couldn't be. Win4Assert( 0 == m_cKeepDataSize ); return hr; } template //+************************************************************************** // NbaRltRA2 (T *Buf, ULONG Request, ULONG *Received) // // Description: Pull, No Buffer, read ahead call outstanding. // State 2. We have to be prepared // for the amount returned to be greater than, less than or equal // to the amount requested. This works for both states 2 and 3. // // History: // Date: Time: Developer: Action: // 11/19/97 2:32:13 PM RichN Created. // // Notes: wait on the sync object, // Finish the async call, // Copy the data into the user Buffer // make another async call // //-************************************************************************** HRESULT CPipeProxy ::NbaRltRA2 (T *Buf, ULONG Request, ULONG *Received) { ComDebOut(( DEB_MARSHAL, "NbaRltRA2 Request:%d\n", Request)); Win4Assert(2 == m_PullState); Win4Assert(NULL != Buf); // State conditions. Win4Assert(0 == m_cKeepDataSize); // No data in keep Buffer. Win4Assert(0 < m_cLastRead); Win4Assert(Request < m_cReadAhead); HRESULT hr = S_OK; bool bDoCleanup = false; // There might be a Bug here. Bug! // We should just be able to call the finish method, but the // bug requires us to wait first. hr = m_pISyncPull->Wait(0, WAIT_INFINITE); if( SUCCEEDED(hr) ) { hr = CheckAndSetKeepBuffer(); if( SUCCEEDED(hr) ) { // Get the data requested last time. Remember the amount returned // could be less than we requested. hr = m_pAsyncPullPipe->Finish_Pull(m_pKeepBuffer, &m_cLastRead); // We can't return more than requested, the buffer may not be // large enough. *Received = MIN(Request, m_cLastRead); if( SUCCEEDED(hr) && m_cLastRead > 0 ) { // Copy the data to the users Buffer and updata bookkeeping. memcpy(Buf, m_pKeepBuffer, (*Received) * sizeof(T)); m_pKeepData = m_pKeepBuffer + *Received; m_cKeepDataSize = m_cLastRead - *Received; SetReadAhead(Request); // Make another read ahead hr = m_pAsyncPullPipe->Begin_Pull(m_cReadAhead); } else { // If the call failed or we received no data, we // need to clean up since we won't be called again. bDoCleanup = true; } } else { //Cancel the call here. CancelTheCall(m_pPullCallObj, 0); } } if( FAILED(hr) || bDoCleanup ) CleanupProxy(&m_pKeepBuffer, &m_pPullCallObj, &m_pAsyncPullPipe, &m_pISyncPull); // Post condition Win4Assert(!(m_cLastRead == 0 && m_cKeepDataSize > 0)); return hr; } template //+************************************************************************** // NbaRgtRA3 (T *Buf, ULONG Request, ULONG *Received) // // Description: Pull, No Buffered data, async call outstanding and request // is greater than read ahead. // // History: // Date: Time: Developer: Action: // 11/20/97 10:50:22 AM RichN Created. // // Notes: Difference between this and the previous state: we know // we don't need a keep Buffer here. // wait on the sync object, // Finish the async call, // Copy the data into the user Buffer // make another async call // //-************************************************************************** HRESULT CPipeProxy ::NbaRgtRA3 (T *Buf, ULONG Request, ULONG *Received) { ComDebOut(( DEB_MARSHAL, "NbaRgtRA3, Request:%d \n", Request)); Win4Assert(3 == m_PullState); Win4Assert(NULL != Buf); // State conditions. Win4Assert(0 == m_cKeepDataSize); // No data in keep Buffer. Win4Assert(0 < m_cLastRead); Win4Assert(Request >= m_cReadAhead); bool bDoCleanup = false; HRESULT hr = m_pISyncPull->Wait(0, WAIT_INFINITE); if( SUCCEEDED(hr)) { // Get the data requested last time. hr = m_pAsyncPullPipe->Finish_Pull(Buf, &m_cLastRead); *Received = m_cLastRead; if( SUCCEEDED(hr) && m_cLastRead > 0 ) { // Reset the amount of data remaining. m_cKeepDataSize = 0; m_pKeepData = NULL; SetReadAhead(Request); // Make another read ahead hr = m_pAsyncPullPipe->Begin_Pull(m_cReadAhead); } else { // If the call failed or we received no data, we // need to clean up since we won't be called again. bDoCleanup = TRUE; } } if( FAILED(hr) || bDoCleanup ) CleanupProxy(&m_pKeepBuffer, &m_pPullCallObj, &m_pAsyncPullPipe, &m_pISyncPull); // Post condition Win4Assert( 0 < m_cReadAhead); Win4Assert(0 == m_cKeepDataSize); return hr; } template //+************************************************************************** // baRltB4 (T *Buf, ULONG Request, ULONG *Received) // // Description: Pull, Data in Buffer, async call outstanding and Request is // less than the data in the keep Buffer. // // History: // Date: Time: Developer: Action: // 11/20/97 1:22:41 PM RichN Created. // // Notes: Copy data from the keep Buffer to the users Buffer. // Update state variables. // //-************************************************************************** HRESULT CPipeProxy ::baRltB4 (T *Buf, ULONG Request, ULONG *Received) { ComDebOut(( DEB_MARSHAL, "baRltB4 \n")); Win4Assert(NULL != Buf); Win4Assert(4 == m_PullState); // State conditions. Win4Assert(0 < m_cKeepDataSize); // Data in keep Buffer. Win4Assert(0 < m_cLastRead); Win4Assert(Request < m_cKeepDataSize); memcpy(Buf, m_pKeepData, Request * (sizeof(T))); m_cKeepDataSize -= Request; m_pKeepData += Request; // Post condition Win4Assert(m_cKeepDataSize > 0); Win4Assert(m_cLastRead > 0); // Post condition Win4Assert(0 < m_cKeepDataSize); // Data in keep Buffer. Win4Assert(0 < m_cLastRead); return S_OK; } template //+************************************************************************** // baRgtB5 (T *Buf, ULONG Request, ULONG *Received) // // Description: Pull, Data in Buffer, async call outstanding and Request is // greater than or equal the data in the keep Buffer. // // History: // Date: Time: Developer: Action: // 11/20/97 1:24:25 PM RichN Created. // // Notes: Copy the keep Buffer data to the users Buffer. // Wait 0 // if the call has completed. // Finish the async call (keep Buffer, RA) // Copy data into users Buffer to fill request // Update keep data size. // if we didn't read zero // set read ahead // Begin async call(RA) // //-************************************************************************** HRESULT CPipeProxy ::baRgtB5 (T *Buf, ULONG Request, ULONG *Received) { ComDebOut(( DEB_MARSHAL, "baRgtB5 \n")); Win4Assert(NULL != Buf); Win4Assert(5 == m_PullState); // State conditions. Win4Assert(0 < m_cKeepDataSize); // Data in keep buffer. Win4Assert(0 < m_cLastRead); Win4Assert(Request >= m_cKeepDataSize); HRESULT hr = S_OK; // Give whatever data we already have. T *tempBuf = Buf; memcpy(tempBuf, m_pKeepData, m_cKeepDataSize * (sizeof(T)) ); // Remainder of the request. ULONG Remainder = Request - m_cKeepDataSize; tempBuf += m_cKeepDataSize; m_cKeepDataSize = 0; m_pKeepData = NULL; hr = m_pISyncPull->Wait(0, 0); // If the call is finished get the data and // copy up to the total request or as much as // we have into the buffer. if( SUCCEEDED(hr) && RPC_S_CALLPENDING != hr) { hr = CheckAndSetKeepBuffer(); if( SUCCEEDED(hr) ) { hr = m_pAsyncPullPipe->Finish_Pull(m_pKeepBuffer, &m_cLastRead); if( SUCCEEDED(hr) ) { // Copy the smaller of the remainder of the // request or what was actually received. ULONG CopySize = MIN(Remainder, m_cLastRead); memcpy(tempBuf, m_pKeepBuffer, CopySize * sizeof(T)); m_cKeepDataSize = m_cLastRead - CopySize; m_pKeepData = m_pKeepBuffer + CopySize; if( m_cLastRead > 0 ) { SetReadAhead(Request); hr = m_pAsyncPullPipe->Begin_Pull(m_cReadAhead); } } } else CancelTheCall(m_pPullCallObj, 0); } else { if( RPC_S_CALLPENDING == hr ) hr = S_OK; else CancelTheCall(m_pPullCallObj, 0); } *Received = (ULONG) (tempBuf - Buf); if( FAILED(hr) ) CleanupProxy(&m_pKeepBuffer, &m_pPullCallObj, &m_pAsyncPullPipe, &m_pISyncPull); // Post condition Win4Assert( (m_cLastRead == 0 && m_cKeepDataSize == 0) || m_cLastRead != 0 ); return hr; } template //+************************************************************************** // PullDone6 (T *Buf, ULONG Request, ULONG *Received) // // Description: Pull Done, no data in the Buffer and no outstanding calls. // // History: // Date: Time: Developer: Action: // 11/20/97 3:30:14 PM RichN Created. // // Notes: // //-************************************************************************** HRESULT CPipeProxy ::PullDone6 (T *Buf, ULONG Request, ULONG *Received) { ComDebOut(( DEB_MARSHAL, "PullDone6 \n")); Win4Assert(6 == m_PullState); CleanupProxy(&m_pKeepBuffer, &m_pPullCallObj, &m_pAsyncPullPipe, &m_pISyncPull); HRESULT hr = S_OK; if (Request > 0) { m_PullState = PULLSTATE1_FIRST_CALL; hr = (this->*(PullStateFunc[m_PullState]))( Buf, Request, Received ); } else { *Received = 0; // Post condition Win4Assert( 0 == m_cKeepDataSize ); Win4Assert( 0 == m_cLastRead ); } return hr; } template //+************************************************************************** // SetPushBuffer(ULONG PushSize) // // Description: Allocates a buffer for push, or reallocates if it // needs to grow. // // History: // Date: Time: Developer: Action: // 11/21/97 10:10:50 AM RichN Created. // // Notes: The buffer will never get smaller. We might want // to reduce it by some algorithm, but not this time. // //-************************************************************************** HRESULT CPipeProxy ::SetPushBuffer(ULONG PushSize) { ComDebOut(( DEB_MARSHAL, "SetPushBuffer, PushSize:%l \n")); // If it is already big enough just return. if( m_cPushBufferSize >= PushSize ) return S_OK; ULONG NewSize = MAX(PushSize, (FRAGMENT_SIZE / sizeof(T)) + 1); T *pTtemp = new T[NewSize]; if( NULL == pTtemp ) { delete[] m_pPushBuffer; m_pPushBuffer = NULL; return E_OUTOFMEMORY; } ULONG BufferedDataSize = m_cPushBufferSize - m_cFreeSpace; if( m_pPushBuffer != NULL ) { // Copy data over and reset bookkeeping. memcpy(pTtemp, m_pPushBuffer, BufferedDataSize * sizeof(T)); delete[] m_pPushBuffer; } m_pPushBuffer = pTtemp; m_cPushBufferSize = NewSize; m_pFreeSpace = m_pPushBuffer + BufferedDataSize; m_cFreeSpace = m_cPushBufferSize - BufferedDataSize; return S_OK; } template //+************************************************************************** // PushStateTransition(ULONG Request) // // Description: Implements the transition table for push. See the pipes // document for a description of the state machine. // // History: // Date: Time: Developer: Action: // 11/13/97 4:36:43 PM RichN Created. // // 02/05/99 JohnStra Modified Push state machine to // allow multiple Push operations // on a pipe. // Notes: // //-************************************************************************** HRESULT CPipeProxy ::PushStateTransition(ULONG PushSize) { ComDebOut(( DEB_MARSHAL, "PushStateTransition, PushSize:%l \n")); switch( m_PushState ) { case PUSHSTATE0_ENTRY: // From the entry state we always go to the first call state. m_PushState = PUSHSTATE1_FIRSTCALL; break; case PUSHSTATE1_FIRSTCALL: case PUSHSTATE2_FS_PSgeFS: case PUSHSTATE3_FS_PSltFS: // If the push size is zero transition to state that // does a zero send. if( 0 == PushSize ) m_PushState = PUSHSTATE4_FS_PSZERO; else // Go to state that either puts the data in free space // or one that handles a push greater than the free space. m_PushState = (PushSize < m_cFreeSpace) ? PUSHSTATE3_FS_PSltFS : PUSHSTATE2_FS_PSgeFS; break; case PUSHSTATE4_FS_PSZERO: // If we are in the state that handles a zero push we may // be called again with a positive buffer size to execute // another push. If we are called with any other // buffer size, go to the state that returns an error. if( 0 < PushSize ) m_PushState = PUSHSTATE1_FIRSTCALL; else m_PushState = PUSHSTATE5_DONE_ERROR; break; case PUSHSTATE5_DONE_ERROR: // Stay in state PUSHSTATE_DONE_ERROR. break; default: return E_UNEXPECTED; } return S_OK; } template //+************************************************************************** // NbNf1(T *Buf, ULONG PushSize) // // Description: Push, No buffer, no free, state 1. // // History: // Date: Time: Developer: Action: // 11/21/97 9:42:57 AM RichN Created. // // Notes: // //-************************************************************************** HRESULT CPipeProxy ::NbNf1(T *Buf, ULONG PushSize) { ComDebOut(( DEB_MARSHAL, "NbNf1, PushSize:%l \n", PushSize)); Win4Assert(1 == m_PushState); // This is the first call to push so PushSize shouldn't be zero. if( PushSize == 0 || NULL == Buf) return E_INVALIDARG; HRESULT hr; // We are only in this state one time so init the async stuff. hr = InitAsync(&m_pPushCallObj, &m_pAsyncPushPipe, &m_pISyncPush); if( FAILED(hr) ) return hr; hr = m_pAsyncPushPipe->Begin_Push(Buf, PushSize); if( FAILED(hr) ) CleanupProxy(&m_pPushBuffer, &m_pPushCallObj, &m_pAsyncPushPipe, &m_pISyncPush); return hr; } template //+************************************************************************** // bfPgtF2(T *Buf, ULONG PushSize) // // Description: Push, Have a buffer with free space and the push size // is greater than or equal to the free space. State 2. // // History: // Date: Time: Developer: Action: // 11/21/97 10:52:41 AM RichN Created. // // Notes: This may grow the buffer, look at reducing it in the next method. // //-************************************************************************** HRESULT CPipeProxy ::bfPgtF2(T *Buf, ULONG PushSize) { ComDebOut(( DEB_MARSHAL, "bfPgtF2, PushSize:%l \n", PushSize)); Win4Assert(2 == m_PushState); Win4Assert( PushSize >= m_cFreeSpace ); Win4Assert( PushSize > 0 ); Win4Assert( (LONG) m_cFreeSpace >= 0 ); if( PushSize == 0 || NULL == Buf) return E_INVALIDARG; // There might be a BUG here. BUG! Shouldn't have to wait. HRESULT hr = m_pISyncPush->Wait(0, WAIT_INFINITE); if( SUCCEEDED(hr) ) hr = m_pAsyncPushPipe->Finish_Push(); if( SUCCEEDED(hr) ) { ULONG TotalData = PushSize + (m_cPushBufferSize - m_cFreeSpace); hr = SetPushBuffer( TotalData ); if( SUCCEEDED(hr) ) { // Append the data to the buffer. memcpy(m_pFreeSpace, Buf, PushSize * sizeof(T)); hr = m_pAsyncPushPipe->Begin_Push(m_pPushBuffer, TotalData); m_pFreeSpace = m_pPushBuffer; m_cFreeSpace = m_cPushBufferSize; } } if( FAILED(hr) ) CleanupProxy(&m_pPushBuffer, &m_pPushCallObj, &m_pAsyncPushPipe, &m_pISyncPush); return hr; } template //+************************************************************************** // bfPltF3(T *Buf, ULONG PushSize) // // Description: Push, Have buffer and pushed data is less than free space. // // History: // Date: Time: Developer: Action: // 11/21/97 11:03:19 AM RichN Created. // // Notes: // //-************************************************************************** HRESULT CPipeProxy ::bfPltF3(T *Buf, ULONG PushSize) { ComDebOut(( DEB_MARSHAL, "bfPltF3, PushSize:%l \n", PushSize)); Win4Assert(3 == m_PushState); Win4Assert( m_cFreeSpace > PushSize ); Win4Assert( PushSize > 0 ); Win4Assert( m_cFreeSpace > 0 ); if( NULL == Buf) return E_INVALIDARG; // Copy the data into the buffer. memcpy(m_pFreeSpace, Buf, PushSize * sizeof(T)); m_cFreeSpace -= PushSize; m_pFreeSpace += PushSize; return S_OK; } template //+************************************************************************** // bPSz4(T *Buf, ULONG PushSize) // // Description: Push, Have buffer and push size is zero. // // History: // Date: Time: Developer: Action: // 11/21/97 11:33:32 AM RichN Created. // // Notes: // //-************************************************************************** HRESULT CPipeProxy ::bPSz4(T *Buf, ULONG PushSize) { ComDebOut(( DEB_MARSHAL, "bPSz4, PushSize:$l \n", PushSize)); Win4Assert(4 == m_PushState); Win4Assert( PushSize == 0 ); Win4Assert( (LONG) m_cFreeSpace >= 0 ); // There might be a BUG here. BUG! Shouldn't have to wait. HRESULT hr = m_pISyncPush->Wait(0, WAIT_INFINITE); if( SUCCEEDED(hr) ) hr = m_pAsyncPushPipe->Finish_Push(); if( SUCCEEDED(hr) ) { if( (m_cPushBufferSize - m_cFreeSpace) > 0 ) { // Data in buffer so send it. hr = m_pAsyncPushPipe->Begin_Push(m_pPushBuffer, m_cPushBufferSize - m_cFreeSpace); if( FAILED(hr) ) goto asyncFailed; hr = m_pISyncPush->Wait(0, WAIT_INFINITE); if( FAILED(hr) ) goto asyncFailed; hr = m_pAsyncPushPipe->Finish_Push(); } if( SUCCEEDED(hr) ) { // Push a zero size buffer to signal end of data. hr = m_pAsyncPushPipe->Begin_Push(Buf, PushSize); if( FAILED(hr) ) goto asyncFailed; hr = m_pISyncPush->Wait(0, WAIT_INFINITE); if( FAILED(hr) ) goto asyncFailed; hr = m_pAsyncPushPipe->Finish_Push(); } } asyncFailed: // Last call regardless of success or failure so clean async up. CleanupProxy(&m_pPushBuffer, &m_pPushCallObj, &m_pAsyncPushPipe, &m_pISyncPush); return hr; } template //+************************************************************************** // PushDone5(T *Buf, ULONG PushSize) // // Description: Push Done, so this should never be called. // // History: // Date: Time: Developer: Action: // 11/21/97 11:42:08 AM RichN Created. // // Notes: // //-************************************************************************** HRESULT CPipeProxy ::PushDone5(T *Buf, ULONG PushSize) { ComDebOut(( DEB_MARSHAL, "PushDone5, PushSize:%u \n")); Win4Assert(FALSE && "Push call after completion."); Win4Assert(5 == m_PushState); return E_UNEXPECTED; }