2011 lines
61 KiB
C++
2011 lines
61 KiB
C++
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1997
|
|
//
|
|
// File: pipes.cxx
|
|
//
|
|
// History:
|
|
// RichN 10/30/97 Created.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
#include <ole2int.h>
|
|
#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<BYTE,
|
|
&IID_IPipeByte,
|
|
&IID_AsyncIPipeByte,
|
|
IPipeByte,
|
|
AsyncIPipeByte>
|
|
(pUnkOuter, pNDRPipeProxy);
|
|
}
|
|
else if( IID_IPipeLong == riid )
|
|
{
|
|
*ppv = new CPipeProxy<LONG,
|
|
&IID_IPipeLong,
|
|
&IID_AsyncIPipeLong,
|
|
IPipeLong,
|
|
AsyncIPipeLong>
|
|
(pUnkOuter, pNDRPipeProxy);
|
|
}
|
|
else if( IID_IPipeDouble == riid )
|
|
{
|
|
*ppv = new CPipeProxy<DOUBLE,
|
|
&IID_IPipeDouble,
|
|
&IID_AsyncIPipeDouble,
|
|
IPipeDouble,
|
|
AsyncIPipeDouble>
|
|
(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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// CPipeProxy( void * pProxy ):
|
|
//
|
|
// Description:CTOR
|
|
//
|
|
// History:
|
|
// Date: Time: Developer: Action:
|
|
// 11/11/97 11:43:00 AM RichN Created.
|
|
//
|
|
// Notes:
|
|
//
|
|
//-**************************************************************************
|
|
CPipeProxy<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::~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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
STDMETHODIMP CPipeProxy<T, ID, AsyncID, I, AsyncI>
|
|
::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
|
|
{
|
|
return m_pUnkOuter->QueryInterface(riid, ppvObj);
|
|
}
|
|
|
|
template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
STDMETHODIMP_(ULONG) CPipeProxy<T, ID, AsyncID, I, AsyncI>
|
|
::AddRef()
|
|
{
|
|
m_cRef++;
|
|
return m_pUnkOuter->AddRef();
|
|
}
|
|
|
|
template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
STDMETHODIMP_(ULONG) CPipeProxy<T, ID, AsyncID, I, AsyncI>
|
|
::Release()
|
|
{
|
|
m_cRef--;
|
|
return m_pUnkOuter->Release();
|
|
}
|
|
|
|
template<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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<class T, const IID* ID, const IID *AsyncID, class I, class AsyncI>
|
|
//+**************************************************************************
|
|
// 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<T, ID, AsyncID, I, AsyncI>
|
|
::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;
|
|
}
|
|
|