windows-nt/Source/XPSP1/NT/com/oleutest/channel/async/async.cxx
2020-09-26 16:20:57 +08:00

1686 lines
46 KiB
C++

//--------------------------------------------------------------
//
// File: async.cxx
//
// Contents: Test proxy and stub for async
//
//---------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <io.h>
#include <malloc.h>
#include <ole2.h>
#include <coguid.h>
#include "async.h"
typedef struct SAsyncData
{
BOOL bLate;
BOOL bSleep;
BOOL bFail;
};
class CProxy;
class CProxyComplete;
class CStubComplete;
class CPCInnerUnknown : public IUnknown
{
public:
// IUnknown methods
STDMETHOD (QueryInterface) ( REFIID riid, LPVOID FAR* ppvObj);
STDMETHOD_(ULONG,AddRef) ( void );
STDMETHOD_(ULONG,Release) ( void );
// Constructor
CPCInnerUnknown( CProxyComplete *pParent );
DWORD _iRef;
CProxyComplete *_pParent;
};
class CProxyComplete : public IAsyncManager, public ICancelMethodCalls
{
public:
STDMETHOD (QueryInterface) ( REFIID riid, LPVOID FAR* ppvObj);
STDMETHOD_(ULONG,AddRef) ( void );
STDMETHOD_(ULONG,Release) ( void );
STDMETHOD (Cancel) ( void );
STDMETHOD (TestCancel) ( void );
STDMETHOD (CompleteCall) ( HRESULT result );
STDMETHOD (GetCallContext) ( REFIID riid, void **pInterface );
STDMETHOD (GetState) ( DWORD *pState );
STDMETHOD (SetCancelTimeout) ( ULONG lSec ) { return E_NOTIMPL; }
CProxyComplete( IUnknown *pControl, BOOL fAutoComplete, HRESULT *hr );
~CProxyComplete();
CPCInnerUnknown _Inner;
IUnknown *_pSyncInner;
IUnknown *_pControl;
RPCOLEMESSAGE _Message;
BOOL _fAutoComplete;
IRpcChannelBuffer3 *_pChannel;
};
class CSCInnerUnknown : public IUnknown
{
public:
// IUnknown methods
STDMETHOD (QueryInterface) ( REFIID riid, LPVOID FAR* ppvObj);
STDMETHOD_(ULONG,AddRef) ( void );
STDMETHOD_(ULONG,Release) ( void );
// Constructor
CSCInnerUnknown( CStubComplete *pParent );
DWORD _iRef;
CStubComplete *_pParent;
};
class CStubComplete : public IAsyncManager, public IAsyncSetup,
public ICancelMethodCalls
{
public:
STDMETHOD (QueryInterface) ( REFIID riid, LPVOID FAR* ppvObj);
STDMETHOD_(ULONG,AddRef) ( void );
STDMETHOD_(ULONG,Release) ( void );
STDMETHOD (Cancel) ( void );
STDMETHOD (CompleteCall) ( HRESULT result );
STDMETHOD (GetCallContext) ( REFIID riid, void **pInterface );
STDMETHOD (GetState) ( DWORD *pState );
STDMETHOD (SetCancelTimeout) ( ULONG lSec ) { return E_NOTIMPL; }
STDMETHOD (TestCancel) ( void );
STDMETHOD (GetAsyncManager) ( REFIID riid,
IUnknown *pOuter,
DWORD dwFlags,
IUnknown **pInner,
IAsyncManager **pComplete );
CStubComplete( IUnknown *pControl, IRpcChannelBuffer3 *, RPCOLEMESSAGE *,
HRESULT *hr );
~CStubComplete();
CSCInnerUnknown _Inner;
IUnknown *_pSyncInner;
IUnknown *_pControl;
RPCOLEMESSAGE _Message;
IRpcChannelBuffer3 *_pChannel;
};
class CAsync : public IAsync
{
public:
STDMETHOD (QueryInterface) ( REFIID riid, LPVOID FAR* ppvObj);
STDMETHOD_(ULONG,AddRef) ( void );
STDMETHOD_(ULONG,Release) ( void );
STDMETHOD (Async) ( IAsyncManager **pCall, BOOL, BOOL, BOOL );
STDMETHOD (RecurseAsync) ( IAsyncManager **pCall, IAsync *, DWORD );
CAsync( IUnknown *pControl, CProxy *pProxy );
~CAsync();
private:
IUnknown *_pControl;
CProxy *_pProxy;
};
class CProxy: public IRpcProxyBuffer, IAsyncSetup
{
public:
STDMETHOD (QueryInterface) ( REFIID riid, LPVOID FAR* ppvObj);
STDMETHOD_(ULONG,AddRef) ( void );
STDMETHOD_(ULONG,Release) ( void );
STDMETHOD (Connect) ( IRpcChannelBuffer *pRpcChannelBuffer );
STDMETHOD_(void,Disconnect)( void );
STDMETHOD (GetAsyncManager)( REFIID riid,
IUnknown *pOuter,
DWORD dwFlags,
IUnknown **pInner,
IAsyncManager **pComplete );
CProxy( IUnknown *pControl );
CAsync _Async;
DWORD _iRef;
IRpcChannelBuffer3 *_pChannel;
};
class CStub : public IRpcStubBuffer
{
public:
STDMETHOD (QueryInterface) ( REFIID riid, LPVOID FAR* ppvObj);
STDMETHOD_(ULONG,AddRef) ( void );
STDMETHOD_(ULONG,Release) ( void );
STDMETHOD (Connect) ( IUnknown *pServer );
STDMETHOD_(void, Disconnect) ( void );
STDMETHOD (Invoke) ( RPCOLEMESSAGE *pMessage,
IRpcChannelBuffer *pChannel );
STDMETHOD_(IRpcStubBuffer *,IsIIDSupported)( REFIID riid );
STDMETHOD_(ULONG,CountRefs) ( void );
STDMETHOD (DebugServerQueryInterface) ( void **ppv );
STDMETHOD_(void,DebugServerRelease) ( void *ppv );
CStub( IAsync *pServer );
private:
DWORD _iRef;
IAsync *_pAsync;
};
class CPSFactory : public IPSFactoryBuffer
{
public:
STDMETHOD (QueryInterface) ( REFIID riid, LPVOID FAR* ppvObj);
STDMETHOD_(ULONG,AddRef) ( void );
STDMETHOD_(ULONG,Release) ( void );
STDMETHOD (CreateProxy) ( IUnknown *pUnkOuter,
REFIID riid,
IRpcProxyBuffer **ppProxy,
void **ppv );
STDMETHOD (CreateStub) ( REFIID riid,
IUnknown *pUnkServer,
IRpcStubBuffer **ppStub );
CPSFactory();
private:
DWORD _iRef;
};
const IID IID_IAsync = {0x70000000,0x76d7,0x11Cf,{0x9a,0xf1,0x00,0x20,0xaf,0x6e,0x72,0xf4}};
//+-------------------------------------------------------------------------
//
// Function: DllCanUnloadNow
//
// Synopsis: Dll entry point
//
//--------------------------------------------------------------------------
STDAPI DllCanUnloadNow()
{
return S_FALSE;
}
//+-------------------------------------------------------------------------
//
// Function: DllGetClassObject
//
// Synopsis: Dll entry point
//
//--------------------------------------------------------------------------
STDAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **ppv)
{
CPSFactory *pFactory;
// Check for IPSFactoryBuffer
if (clsid == IID_IAsync && iid == IID_IPSFactoryBuffer)
{
pFactory = new CPSFactory();
*ppv = pFactory;
if (pFactory == NULL)
return E_OUTOFMEMORY;
else
return S_OK;
}
return E_NOTIMPL;
}
//+-------------------------------------------------------------------
//
// Member: CPSFactory::AddRef, public
//
// Synopsis: Adds a reference to an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CPSFactory::AddRef()
{
InterlockedIncrement( (long *) &_iRef );
return _iRef;
}
//+-------------------------------------------------------------------
//
// Member: CPSFactory::CPSFactory
//
// Synopsis: Constructor
//
//--------------------------------------------------------------------
CPSFactory::CPSFactory()
{
_iRef = 1;
}
//+-------------------------------------------------------------------
//
// Member: CPSFactory::CreateProxy, public
//
// Synopsis: Create an instance of the requested proxy
//
//--------------------------------------------------------------------
STDMETHODIMP CPSFactory::CreateProxy( IUnknown *pUnkOuter, REFIID riid,
IRpcProxyBuffer **ppProxy, void **ppv )
{
CProxy *pProxy;
// Validate the parameters.
if (ppv == NULL || riid != IID_IAsync || pUnkOuter == NULL)
return E_INVALIDARG;
*ppv = NULL;
// Create a proxy.
pProxy = new CProxy( pUnkOuter );
if (pProxy == NULL)
return E_OUTOFMEMORY;
*ppProxy = pProxy;
*ppv = &pProxy->_Async;
return S_OK;
}
//+-------------------------------------------------------------------
//
// Member: CPSFactory::CreateStub, public
//
// Synopsis: Create an instance of the requested stub
//
//--------------------------------------------------------------------
STDMETHODIMP CPSFactory::CreateStub( REFIID riid, IUnknown *pUnkServer,
IRpcStubBuffer **ppStub )
{
IAsync *pAsync;
CStub *pStub;
HRESULT hr;
// Validate the parameters.
if (riid != IID_IAsync)
return E_INVALIDARG;
// Get the IAsync interface.
hr = pUnkServer->QueryInterface( IID_IAsync, (void **) &pAsync );
if (FAILED(hr))
return hr;
// Create a stub.
pStub = new CStub( pAsync );
pAsync->Release();
if (pStub == NULL)
return E_OUTOFMEMORY;
*ppStub = pStub;
return S_OK;
}
//+-------------------------------------------------------------------
//
// Member: CPSFactory::QueryInterface, public
//
// Synopsis: Returns a pointer to the requested interface.
//
//--------------------------------------------------------------------
STDMETHODIMP CPSFactory::QueryInterface( REFIID riid, LPVOID FAR* ppvObj)
{
if (IsEqualIID(riid, IID_IUnknown) ||
IsEqualIID(riid, IID_IPSFactoryBuffer))
*ppvObj = (IPSFactoryBuffer *) this;
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
//+-------------------------------------------------------------------
//
// Member: CPSFactory::Release, public
//
// Synopsis: Releases an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CPSFactory::Release()
{
ULONG lRef = _iRef - 1;
if (InterlockedDecrement( (long*) &_iRef ) == 0)
{
delete this;
return 0;
}
else
return lRef;
}
//+-------------------------------------------------------------------
//
// Member: CProxy::AddRef, public
//
// Synopsis: Adds a reference to an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CProxy::AddRef()
{
InterlockedIncrement( (long *) &_iRef );
return _iRef;
}
//+-------------------------------------------------------------------
//
// Member: CProxy::Connect, public
//
// Synopsis: Connects the proxy to a channel
//
//--------------------------------------------------------------------
STDMETHODIMP CProxy::Connect( IRpcChannelBuffer *pChannel )
{
HRESULT hr;
// Get the other channel buffer interface.
hr = pChannel->QueryInterface( IID_IRpcChannelBuffer3, (void **) &_pChannel );
return hr;
}
//+-------------------------------------------------------------------
//
// Member: CProxy::Disconnect, public
//
// Synopsis: Disconnects the proxy from a channel
//
//--------------------------------------------------------------------
STDMETHODIMP_(void) CProxy::Disconnect()
{
if (_pChannel != NULL)
{
_pChannel->Release();
_pChannel = NULL;
}
}
//+-------------------------------------------------------------------
//
// Member: CProxy::CProxy, public
//
// Synopsis: Constructor
//
//--------------------------------------------------------------------
CProxy::CProxy( IUnknown *pControl ) :
_Async( pControl, this )
{
_iRef = 1;
_pChannel = NULL;
}
//+-------------------------------------------------------------------
//
// Member: CProxy::GetAsyncManager, public
//
// Synopsis: Creates a proxy completion object
//
//--------------------------------------------------------------------
STDMETHODIMP CProxy::GetAsyncManager( REFIID riid,
IUnknown *pOuter,
DWORD dwFlags,
IUnknown **ppInner,
IAsyncManager **ppComplete )
{
HRESULT hr;
CProxyComplete *pComplete;
// Create a new proxy completion object.
pComplete = new CProxyComplete( pOuter, FALSE, &hr );
if (pComplete == NULL)
return E_OUTOFMEMORY;
else if (FAILED(hr))
{
delete pComplete;
return hr;
}
// Get IAsyncManager.
*ppComplete = (IAsyncManager *) pComplete;
*ppInner = (IUnknown *) &pComplete->_Inner;
pComplete->AddRef();
return S_OK;
}
//+-------------------------------------------------------------------
//
// Member: CProxy::QueryInterface, public
//
// Synopsis: Returns a pointer to the requested interface.
//
//--------------------------------------------------------------------
STDMETHODIMP CProxy::QueryInterface( REFIID riid, LPVOID FAR* ppvObj)
{
if (IsEqualIID(riid, IID_IUnknown) ||
IsEqualIID(riid, IID_IRpcProxyBuffer))
*ppvObj = (IRpcProxyBuffer *) this;
else if (IsEqualIID(riid, IID_IAsyncSetup))
*ppvObj = (IAsyncSetup *) this;
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
//+-------------------------------------------------------------------
//
// Member: CProxy::Release, public
//
// Synopsis: Releases an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CProxy::Release()
{
ULONG lRef = _iRef - 1;
if (InterlockedDecrement( (long*) &_iRef ) == 0)
{
delete this;
return 0;
}
else
return lRef;
}
//+-------------------------------------------------------------------
//
// Member: CAsync::AddRef, public
//
// Synopsis: Adds a reference to an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CAsync::AddRef()
{
return _pControl->AddRef();
}
//+-------------------------------------------------------------------
//
// Member: CAsync::Async, public
//
// Synopsis: Marshal parameters for an async call.
//
//--------------------------------------------------------------------
STDMETHODIMP CAsync::Async( IAsyncManager **ppCall, BOOL bLate,
BOOL bSleep, BOOL bFail )
{
HRESULT hr;
CProxyComplete *pComplete;
BOOL fFreeComplete = FALSE;
DWORD lIgnore;
SAsyncData *pData;
DWORD fFlags = RPC_BUFFER_ASYNC;
// If there is no async complete, create one. Aggregate in the
// correct ISignal.
if (ppCall == NULL || *ppCall == NULL)
{
// Initialize the out parameters.
if (ppCall != NULL)
*ppCall = NULL;
else
fFlags |= RPCFLG_AUTO_COMPLETE;
// Create a new proxy complete object.
pComplete = new CProxyComplete( NULL, ppCall == NULL, &hr );
if (pComplete == NULL)
return E_OUTOFMEMORY;
if (FAILED(hr))
{
delete pComplete;
return hr;
}
fFreeComplete = TRUE;
if (ppCall != NULL)
*ppCall = pComplete;
}
// Otherwise the passed in completion object should be one of ours.
else
{
pComplete = (CProxyComplete *) *ppCall;
if (pComplete->_pChannel != NULL)
return E_FAIL;
}
// Get a buffer.
memset( &pComplete->_Message, 0, sizeof(pComplete->_Message) );
pComplete->_Message.cbBuffer = sizeof( SAsyncData );
pComplete->_Message.dataRepresentation = 0x10;
pComplete->_Message.iMethod = 3;
pComplete->_Message.rpcFlags = fFlags;
hr = _pProxy->_pChannel->GetBuffer( &pComplete->_Message, IID_IAsync );
if (FAILED(hr)) goto Done;
// Register async.
hr = _pProxy->_pChannel->RegisterAsync( &pComplete->_Message,
(IAsyncManager *) pComplete );
if (FAILED(hr))
{
// Register async shouldn't fail.
DebugBreak();
}
// Fill in the buffer.
pData = (SAsyncData *) pComplete->_Message.Buffer;
pData->bLate = bLate;
pData->bSleep = bSleep;
pData->bFail = bFail;
// Send the buffer.
pComplete->_pChannel = _pProxy->_pChannel;
_pProxy->_pChannel->AddRef();
hr = _pProxy->_pChannel->Send( &pComplete->_Message, &lIgnore );
Done:
if (FAILED(hr))
{
if (pComplete->_pChannel != NULL)
{
pComplete->_pChannel = NULL;
_pProxy->_pChannel->Release();
}
if (fFreeComplete)
{
delete pComplete;
if (ppCall != NULL)
*ppCall = NULL;
}
}
return hr;
}
//+-------------------------------------------------------------------
//
// Member: CAsync::CAsync, public
//
// Synopsis: Constructor
//
//--------------------------------------------------------------------
CAsync::CAsync( IUnknown *pControl, CProxy *pProxy )
{
_pControl = pControl;
_pProxy = pProxy;
_pControl->AddRef();
}
//+-------------------------------------------------------------------
//
// Member: CAsync::~CAsync, public
//
// Synopsis: Destructor
//
//--------------------------------------------------------------------
CAsync::~CAsync()
{
_pControl->Release();
}
//+-------------------------------------------------------------------
//
// Member: CAsync::QueryInterface, public
//
// Synopsis: Returns a pointer to the requested interface.
//
//--------------------------------------------------------------------
STDMETHODIMP CAsync::QueryInterface( REFIID riid, LPVOID FAR* ppvObj)
{
return _pControl->QueryInterface( riid, ppvObj );
}
//+-------------------------------------------------------------------
//
// Member: CAsync::RecurseAsync, public
//
// Synopsis: Marshal parameters for a RecurseAsync call.
//
//--------------------------------------------------------------------
STDMETHODIMP CAsync::RecurseAsync( IAsyncManager **ppCall, IAsync *pCallback,
DWORD depth )
{
HRESULT hr;
CProxyComplete *pComplete;
BOOL fFreeComplete = FALSE;
DWORD lIgnore;
HANDLE memory = NULL;
ULONG size;
IStream *pStream = NULL;
LARGE_INTEGER pos;
DWORD *pBuffer;
DWORD dwDestCtx;
VOID *pvDestCtx = NULL;
BOOL fFlags = RPC_BUFFER_ASYNC;
// If there is no async complete, create one. Aggregate in the
// correct ISignal.
if (ppCall == NULL || *ppCall == NULL)
{
// Initialize the out parameters.
if (ppCall != NULL)
*ppCall = NULL;
else
fFlags |= RPCFLG_AUTO_COMPLETE;
// Create a new proxy complete object.
pComplete = new CProxyComplete( NULL, ppCall == NULL, &hr );
if (pComplete == NULL)
return E_OUTOFMEMORY;
if (FAILED(hr))
{
delete pComplete;
return hr;
}
fFreeComplete = TRUE;
if (ppCall != NULL)
*ppCall = pComplete;
}
// Otherwise the passed in completion object should be one of ours.
else
{
pComplete = (CProxyComplete *) *ppCall;
if (pComplete->_pChannel != NULL)
return E_FAIL;
}
// Get the destination context.
hr = _pProxy->_pChannel->GetDestCtx( &dwDestCtx, &pvDestCtx );
// Find out how much memory to allocate.
hr = CoGetMarshalSizeMax( &size, IID_IAsync, pCallback, dwDestCtx,
pvDestCtx, MSHLFLAGS_NORMAL );
if (FAILED(hr))
goto Done;
// Allocate memory.
memory = GlobalAlloc( GMEM_FIXED, size );
if (memory == NULL)
{
hr = E_OUTOFMEMORY;
goto Done;
}
// Create a stream.
hr = CreateStreamOnHGlobal( memory, TRUE, &pStream );
if (FAILED(hr))
goto Done;
memory = NULL;
// Marshal the object.
hr = CoMarshalInterface( pStream, IID_IAsync, pCallback, dwDestCtx,
pvDestCtx, MSHLFLAGS_NORMAL );
if (FAILED(hr))
goto Done;
// Seek back to the start of the stream.
pos.QuadPart = 0;
hr = pStream->Seek( pos, STREAM_SEEK_SET, NULL );
if (FAILED(hr))
goto Done;
// Get a buffer.
memset( &pComplete->_Message, 0, sizeof(pComplete->_Message) );
pComplete->_Message.cbBuffer = sizeof(depth) + size;
pComplete->_Message.dataRepresentation = 0x10;
pComplete->_Message.iMethod = 4;
pComplete->_Message.rpcFlags = fFlags;
hr = _pProxy->_pChannel->GetBuffer( &pComplete->_Message, IID_IAsync );
if (FAILED(hr)) goto Done;
// Register async.
hr = _pProxy->_pChannel->RegisterAsync( &pComplete->_Message,
(IAsyncManager *) pComplete );
if (FAILED(hr))
{
// Register async shouldn't fail.
DebugBreak();
}
// Fill in the buffer.
pBuffer = (DWORD *) pComplete->_Message.Buffer;
*pBuffer = depth;
pBuffer += 1;
hr = pStream->Read( (void *) pBuffer, size, NULL );
if (FAILED(hr))
goto Done;
// Send the buffer.
pComplete->_pChannel = _pProxy->_pChannel;
_pProxy->_pChannel->AddRef();
hr = _pProxy->_pChannel->Send( &pComplete->_Message, &lIgnore );
Done:
if (pStream != NULL)
pStream->Release();
if (memory != NULL)
GlobalFree( memory );
if (FAILED(hr))
{
if (pComplete->_pChannel != NULL)
{
pComplete->_pChannel = NULL;
_pProxy->_pChannel->Release();
}
if (fFreeComplete)
{
delete pComplete;
if (ppCall != NULL)
*ppCall = NULL;
}
}
return hr;
}
//+-------------------------------------------------------------------
//
// Member: CAsync::Release, public
//
// Synopsis: Releases an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CAsync::Release()
{
return _pControl->Release();
}
//+-------------------------------------------------------------------
//
// Member: CPCInnerUnknown::AddRef, public
//
// Synopsis: Adds a reference to an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CPCInnerUnknown::AddRef()
{
InterlockedIncrement( (long *) &_iRef );
return _iRef;
}
//+-------------------------------------------------------------------
//
// Member: CPCInnerUnknown::CPCInnerUnknown
//
// Synopsis: Constructor
//
//--------------------------------------------------------------------
CPCInnerUnknown::CPCInnerUnknown( CProxyComplete *pParent )
{
_iRef = 1;
_pParent = pParent;
}
//+-------------------------------------------------------------------
//
// Member: CPCInnerUnknown::QueryInterface, public
//
// Synopsis: Returns a pointer to the requested interface.
//
//--------------------------------------------------------------------
STDMETHODIMP CPCInnerUnknown::QueryInterface( REFIID riid, LPVOID FAR* ppvObj)
{
IUnknown *pUnk;
if (IsEqualIID(riid, IID_IUnknown))
pUnk = (IUnknown *) this;
else if (IsEqualIID(riid, IID_IAsyncManager))
pUnk = (IAsyncManager *) _pParent;
else if (IsEqualIID(riid, IID_ICancelMethodCalls))
pUnk = (ICancelMethodCalls *) _pParent;
else if (_pParent->_pSyncInner != NULL)
return _pParent->_pSyncInner->QueryInterface( riid, ppvObj );
pUnk->AddRef();
*ppvObj = pUnk;
return S_OK;
}
//+-------------------------------------------------------------------
//
// Member: CPCInnerUnknown::Release, public
//
// Synopsis: Releases an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CPCInnerUnknown::Release()
{
ULONG lRef = _iRef - 1;
if (InterlockedDecrement( (long*) &_iRef ) == 0)
{
delete _pParent;
return 0;
}
else
return lRef;
}
//+-------------------------------------------------------------------
//
// Member: CProxyComplete::AddRef, public
//
// Synopsis: Adds a reference to an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CProxyComplete::AddRef()
{
return _pControl->AddRef();
}
//+-------------------------------------------------------------------
//
// Member: CProxyComplete::Cancel, public
//
// Synopsis: Forward cancel to the channel
//
//--------------------------------------------------------------------
STDMETHODIMP CProxyComplete::Cancel()
{
HRESULT hr;
if (_pChannel == NULL)
return RPC_E_CALL_COMPLETE;
hr = _pChannel->Cancel( &_Message );
return hr;
}
//+-------------------------------------------------------------------
//
// Member: CProxyComplete::CompleteCall, public
//
// Synopsis: Receive the reply and parse the out parameters
//
//--------------------------------------------------------------------
STDMETHODIMP CProxyComplete::CompleteCall( HRESULT result )
{
HRESULT hr;
HRESULT temp;
DWORD lIgnore;
// Fail if there is no call.
if (_pChannel == NULL)
return RPC_E_CALL_COMPLETE;
// Call receive.
hr = _pChannel->Receive( &_Message, 0, &lIgnore );
if (hr == RPC_S_CALLPENDING || hr == 0x15)
return hr;
if (FAILED(hr))
goto Done;
// Unmarshal the results.
if (_Message.cbBuffer < sizeof(HRESULT))
{
hr = RPC_E_INVALID_DATAPACKET;
goto Done;
}
temp = *((HRESULT *) _Message.Buffer);
// Free the buffer.
hr = _pChannel->FreeBuffer( &_Message );
if (SUCCEEDED(hr))
hr = temp;
// If auto complete, self release.
Done:
_pChannel->Release();
_pChannel = NULL;
if (_fAutoComplete)
_Inner.Release();
return hr;
}
//+-------------------------------------------------------------------
//
// Member: CProxyComplete::CProxyComplete
//
// Synopsis: Constructor
//
//--------------------------------------------------------------------
CProxyComplete::CProxyComplete( IUnknown *pControl, BOOL fAutoComplete,
HRESULT *hr) :
_Inner( this )
{
// Save the easy fields
_pSyncInner = NULL;
_fAutoComplete = fAutoComplete;
_pChannel = NULL;
if (pControl == NULL)
_pControl = &_Inner;
else
{
_pControl = pControl;
_pControl->AddRef();
}
// Aggregate in an ISynchronize.
if (fAutoComplete)
*hr = CoCreateInstance( CLSID_Synchronize_AutoComplete,
&_Inner,
CLSCTX_INPROC_SERVER, IID_IUnknown,
(void **) &_pSyncInner );
else
*hr = CoCreateInstance( CLSID_Synchronize_ManualResetEvent,
&_Inner,
CLSCTX_INPROC_SERVER, IID_IUnknown,
(void **) &_pSyncInner );
if (SUCCEEDED(*hr))
{
// Aggregation requires some weird reference counting.
Release();
}
}
//+-------------------------------------------------------------------
//
// Member: CProxyComplete::~CProxyComplete
//
// Synopsis: Destructor
//
//--------------------------------------------------------------------
CProxyComplete::~CProxyComplete()
{
// Make sure we don't get deleted twice.
_Inner._iRef = 0xdead;
if (_pSyncInner != NULL)
_pSyncInner->Release();
if (_pChannel != NULL)
_pChannel->Release();
if (_pControl != &_Inner)
_pControl->Release();
}
//+-------------------------------------------------------------------
//
// Member: CProxyComplete::GetCallContext, public
//
// Synopsis: Calls GetCallContext on the channel
//
//--------------------------------------------------------------------
STDMETHODIMP CProxyComplete::GetCallContext( REFIID riid, void **pInterface )
{
if (_pChannel == NULL)
return RPC_E_CALL_COMPLETE;
return _pChannel->GetCallContext( &_Message, riid, pInterface );
}
//+-------------------------------------------------------------------
//
// Member: CProxyComplete::GetState, public
//
// Synopsis: Returns a pointer to the requested interface.
//
//--------------------------------------------------------------------
STDMETHODIMP CProxyComplete::GetState( DWORD *pState )
{
if (_pChannel == NULL)
return RPC_E_CALL_COMPLETE;
return _pChannel->GetState( &_Message, pState );
}
//+-------------------------------------------------------------------
//
// Member: CProxyComplete::QueryInterface, public
//
// Synopsis: Returns a pointer to the requested interface.
//
//--------------------------------------------------------------------
STDMETHODIMP CProxyComplete::QueryInterface( REFIID riid, LPVOID FAR* ppvObj)
{
return _pControl->QueryInterface( riid, ppvObj );
}
//+-------------------------------------------------------------------
//
// Member: CProxyComplete::Release, public
//
// Synopsis: Releases an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CProxyComplete::Release()
{
return _pControl->Release();
}
//+-------------------------------------------------------------------
//
// Member: CProxyComplete::TestCancel, public
//
// Synopsis: Is call canceled?
//
//--------------------------------------------------------------------
STDMETHODIMP CProxyComplete::TestCancel()
{
HRESULT hr;
DWORD state;
// The call is complete is already cleaned up.
if (_pChannel == NULL)
return RPC_E_CALL_COMPLETE;
// Ask the channel about the state of the call.
hr = _pChannel->GetState( &_Message, &state );
if (FAILED(hr))
return hr;
// Convert the flags to error codes.
if (state & DCOM_CALL_CANCELED)
return RPC_E_CALL_CANCELED;
else if (state & DCOM_CALL_COMPLETE)
return RPC_E_CALL_COMPLETE;
else
return RPC_S_CALLPENDING;
}
//+-------------------------------------------------------------------
//
// Member: CStub::AddRef, public
//
// Synopsis: Adds a reference to an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CStub::AddRef()
{
InterlockedIncrement( (long *) &_iRef );
return _iRef;
}
//+-------------------------------------------------------------------
//
// Member: CStub::Connect
//
// Synopsis: Connect the stub to the server
//
//--------------------------------------------------------------------
STDMETHODIMP CStub::Connect( IUnknown *pServer )
{
// Get the IAsync interface.
return pServer->QueryInterface( IID_IAsync, (void **) &_pAsync );
}
//+-------------------------------------------------------------------
//
// Member: CStub::CountRefs
//
// Synopsis: Unused
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CStub::CountRefs()
{
return 0;
}
//+-------------------------------------------------------------------
//
// Member: CStub::CStub
//
// Synopsis: Constructor
//
//--------------------------------------------------------------------
CStub::CStub( IAsync *pAsync )
{
_iRef = 1;
_pAsync = pAsync;
pAsync->AddRef();
}
//+-------------------------------------------------------------------
//
// Member: CStub::DebugServerQueryInterface
//
// Synopsis: Returns a pointer to the server without AddRefing.
//
//--------------------------------------------------------------------
STDMETHODIMP CStub::DebugServerQueryInterface( void **ppv )
{
*ppv = _pAsync;
return S_OK;
}
//+-------------------------------------------------------------------
//
// Member: CStub::DebugServerRelease
//
// Synopsis: Paired with DebugServerQueryInterface. Does nothing.
//
//--------------------------------------------------------------------
STDMETHODIMP_(void) CStub::DebugServerRelease( void *ppv )
{
}
//+-------------------------------------------------------------------
//
// Member: CStub::Disconnect
//
// Synopsis: Releases the server.
//
//--------------------------------------------------------------------
STDMETHODIMP_(void) CStub::Disconnect()
{
if (_pAsync != NULL)
{
_pAsync->Release();
_pAsync = NULL;
}
}
//+-------------------------------------------------------------------
//
// Member: CStub::Invoke
//
// Synopsis: Unmarshals the parameters for IAsync and calls it.
// Creates a completion stub.
//
//--------------------------------------------------------------------
STDMETHODIMP CStub::Invoke( RPCOLEMESSAGE *pMessage,
IRpcChannelBuffer *pChannel )
{
IRpcChannelBuffer3 *pChannel2 = NULL;
CStubComplete *pComplete;
HRESULT hr = S_OK;
SAsyncData *pData;
IAsync *pCallback = NULL;
DWORD depth;
DWORD *pBuffer;
HANDLE memory = NULL;
IStream *pStream = NULL;
LARGE_INTEGER pos;
// Get channel buffer 2.
hr = pChannel->QueryInterface( IID_IRpcChannelBuffer3, (void **)
&pChannel2 );
if (FAILED(hr))
return hr;
// Create completion stub.
pComplete = new CStubComplete( NULL, pChannel2, pMessage, &hr );
if (pComplete == NULL)
{
pChannel2->Release();
return E_OUTOFMEMORY;
}
if (FAILED(hr))
{
delete pComplete;
pChannel2->Release();
return hr;
}
// Register async.
hr = pComplete->_pChannel->RegisterAsync( &pComplete->_Message,
(IAsyncManager *) pComplete );
if (FAILED(hr))
DebugBreak();
// Unmarshal data for a call to Async.
if (pMessage->iMethod == 3)
{
if (pMessage->cbBuffer < sizeof(SAsyncData))
{
hr = RPC_E_INVALID_DATAPACKET;
goto Done;
}
pData = (SAsyncData *) pMessage->Buffer;
}
// Unmarshal data for a call to RecurseAsync.
else if (pMessage->iMethod == 4)
{
/*
if (un pitic)
{
mic mic mic;
}
*/
// Get the depth.
if (pMessage->cbBuffer < sizeof(DWORD))
{
hr = RPC_E_INVALID_DATAPACKET;
goto Done;
}
pBuffer = (DWORD *) pMessage->Buffer;
depth = *pBuffer;
pBuffer += 1;
// Allocate memory.
memory = GlobalAlloc( GMEM_FIXED, pMessage->cbBuffer - sizeof(DWORD) );
if (memory == NULL)
goto Done;
// Create a stream.
hr = CreateStreamOnHGlobal( memory, TRUE, &pStream );
if (FAILED(hr))
goto Done;
memory = NULL;
// Copy the data into the stream.
hr = pStream->Write( (void *) pBuffer,
pMessage->cbBuffer - sizeof(DWORD), NULL );
if (FAILED(hr))
goto Done;
// Seek back to the start of the stream.
pos.QuadPart = 0;
hr = pStream->Seek( pos, STREAM_SEEK_SET, NULL );
if (FAILED(hr))
goto Done;
// Unmarshal the object.
hr = CoUnmarshalInterface( pStream, IID_IAsync,
(void **) &pCallback );
if (FAILED(hr))
goto Done;
}
// Bad packet.
else
{
hr = RPC_E_INVALID_DATAPACKET;
goto Done;
}
// Call server.
if (pMessage->iMethod == 3)
_pAsync->Async( (IAsyncManager **) &pComplete, pData->bLate,
pData->bSleep, pData->bFail );
else
_pAsync->RecurseAsync( (IAsyncManager **) &pComplete, pCallback,
depth );
pComplete->Release();
// Cleanup
Done:
if (pStream != NULL)
pStream->Release();
if (memory != NULL)
GlobalFree( memory );
if (pCallback != NULL)
pCallback->Release();
if (FAILED(hr))
pChannel2->Cancel( &pComplete->_Message );
pChannel2->Release();
return hr;
}
//+-------------------------------------------------------------------
//
// Member: CStub::IsIIDSupported
//
// Synopsis: Indicates which IIDs this stub can unmarshal.
//
//--------------------------------------------------------------------
STDMETHODIMP_(IRpcStubBuffer *) CStub::IsIIDSupported( REFIID riid )
{
return NULL;
}
//+-------------------------------------------------------------------
//
// Member: CStub::QueryInterface, public
//
// Synopsis: Returns a pointer to the requested interface.
//
//--------------------------------------------------------------------
STDMETHODIMP CStub::QueryInterface( REFIID riid, LPVOID FAR* ppvObj)
{
if (IsEqualIID(riid, IID_IUnknown) ||
IsEqualIID(riid, IID_IRpcStubBuffer))
*ppvObj = (IRpcStubBuffer *) this;
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
//+-------------------------------------------------------------------
//
// Member: CStub::Release, public
//
// Synopsis: Releases an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CStub::Release()
{
ULONG lRef = _iRef - 1;
if (InterlockedDecrement( (long*) &_iRef ) == 0)
{
delete this;
return 0;
}
else
return lRef;
}
//+-------------------------------------------------------------------
//
// Member: CSCInnerUnknown::AddRef, public
//
// Synopsis: Adds a reference to an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CSCInnerUnknown::AddRef()
{
InterlockedIncrement( (long *) &_iRef );
return _iRef;
}
//+-------------------------------------------------------------------
//
// Member: CSCInnerUnknown::CSCInnerUnknown
//
// Synopsis: Constructor
//
//--------------------------------------------------------------------
CSCInnerUnknown::CSCInnerUnknown( CStubComplete *pParent )
{
_iRef = 1;
_pParent = pParent;
}
//+-------------------------------------------------------------------
//
// Member: CSCInnerUnknown::QueryInterface, public
//
// Synopsis: Returns a pointer to the requested interface.
//
//--------------------------------------------------------------------
STDMETHODIMP CSCInnerUnknown::QueryInterface( REFIID riid, LPVOID FAR* ppvObj)
{
IUnknown *pUnk;
if (IsEqualIID(riid, IID_IUnknown))
pUnk = (IUnknown *) this;
else if (IsEqualIID(riid, IID_IAsyncManager))
pUnk = (IAsyncManager *) _pParent;
else if (IsEqualIID(riid, IID_ICancelMethodCalls))
pUnk = (ICancelMethodCalls *) _pParent;
else if (IsEqualIID(riid, IID_IAsyncSetup))
pUnk = (IAsyncSetup *) _pParent;
else if (_pParent->_pSyncInner != NULL)
return _pParent->_pSyncInner->QueryInterface( riid, ppvObj );
pUnk->AddRef();
*ppvObj = pUnk;
return S_OK;
}
//+-------------------------------------------------------------------
//
// Member: CSCInnerUnknown::Release, public
//
// Synopsis: Releases an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CSCInnerUnknown::Release()
{
ULONG lRef = _iRef - 1;
if (InterlockedDecrement( (long*) &_iRef ) == 0)
{
delete _pParent;
return 0;
}
else
return lRef;
}
//+-------------------------------------------------------------------
//
// Member: CStubComplete::AddRef, public
//
// Synopsis: Adds a reference to an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CStubComplete::AddRef()
{
return _pControl->AddRef();
}
//+-------------------------------------------------------------------
//
// Member: CStubComplete::Cancel, public
//
// Synopsis: Forward cancel to the channel
//
//--------------------------------------------------------------------
STDMETHODIMP CStubComplete::Cancel()
{
HRESULT hr;
if (_pChannel == NULL)
return RPC_E_CALL_COMPLETE;
hr = _pChannel->Cancel( &_Message );
_pChannel->Release();
_pChannel = NULL;
return hr;
}
//+-------------------------------------------------------------------
//
// Member: CStubComplete::CompleteCall, public
//
// Synopsis: Get a buffer and send the reply.
//
//--------------------------------------------------------------------
STDMETHODIMP CStubComplete::CompleteCall( HRESULT result )
{
HRESULT hr;
DWORD lIgnore;
// Fail if there is no call.
if (_pChannel == NULL)
return RPC_E_CALL_COMPLETE;
// Get a buffer.
_Message.cbBuffer = 4;
hr = _pChannel->GetBuffer( &_Message, IID_IAsync );
if (FAILED(hr))
goto Done;
// Marshal the result.
*((HRESULT *) _Message.Buffer) = result;
// Send the reply.
hr = _pChannel->Send( &_Message, &lIgnore );
Done:
_pChannel->Release();
_pChannel = NULL;
return hr;
}
//+-------------------------------------------------------------------
//
// Member: CStubComplete::CStubComplete
//
// Synopsis: Constructor
//
//--------------------------------------------------------------------
CStubComplete::CStubComplete( IUnknown *pControl,
IRpcChannelBuffer3 *pChannel,
RPCOLEMESSAGE *pMessage,
HRESULT *hr ) :
_Inner( this )
{
_Message = *pMessage;
_pSyncInner = NULL;
_pChannel = pChannel;
pChannel->AddRef();
if (pControl == NULL)
_pControl = &_Inner;
else
{
_pControl = pControl;
_pControl->AddRef();
}
// Aggregate in an ISynchronize.
*hr = CoCreateInstance( CLSID_Synchronize_ManualResetEvent,
&_Inner,
CLSCTX_INPROC_SERVER, IID_IUnknown,
(void **) &_pSyncInner );
if (SUCCEEDED(*hr))
{
// Aggregation requires some weird reference counting.
Release();
}
}
//+-------------------------------------------------------------------
//
// Member: CStubComplete::~CStubComplete
//
// Synopsis: Destructor
//
//--------------------------------------------------------------------
CStubComplete::~CStubComplete()
{
// Make sure we don't get deleted twice.
_Inner._iRef = 0xdead;
if (_pSyncInner != NULL)
_pSyncInner->Release();
if (_pChannel != NULL)
_pChannel->Release();
if (_pControl != &_Inner)
_pControl->Release();
}
//+-------------------------------------------------------------------
//
// Member: CStubComplete::GetAsyncManager, public
//
// Synopsis: Creates a stub completion object and reregisters it
// in place of this one.
//
//--------------------------------------------------------------------
STDMETHODIMP CStubComplete::GetAsyncManager( REFIID riid,
IUnknown *pOuter,
DWORD dwFlags,
IUnknown **ppInner,
IAsyncManager **ppComplete )
{
CStubComplete *pComplete;
HRESULT hr;
// Fail if there is no call.
if (_pChannel == NULL)
return RPC_E_CALL_COMPLETE;
// Create a new stub completion object.
pComplete = new CStubComplete( pOuter, _pChannel, &_Message, &hr );
if (pComplete == NULL)
return E_OUTOFMEMORY;
if (FAILED(hr))
{
delete pComplete;
return hr;
}
// Register the new stub completion object.
hr = _pChannel->RegisterAsync( &pComplete->_Message, pComplete );
if (FAILED(hr))
DebugBreak();
// Disconnect this stub completion object.
_pChannel->Release();
_pChannel = NULL;
*ppComplete = pComplete;
*ppInner = &pComplete->_Inner;
return S_OK;
}
//+-------------------------------------------------------------------
//
// Member: CStubComplete::GetCallContext, public
//
// Synopsis: Calls GetCallContext on the channel
//
//--------------------------------------------------------------------
STDMETHODIMP CStubComplete::GetCallContext( REFIID riid, void **pInterface )
{
if (_pChannel == NULL)
return RPC_E_CALL_COMPLETE;
return _pChannel->GetCallContext( &_Message, riid, pInterface );
}
//+-------------------------------------------------------------------
//
// Member: CStubComplete::GetState, public
//
// Synopsis: Returns a pointer to the requested interface.
//
//--------------------------------------------------------------------
STDMETHODIMP CStubComplete::GetState( DWORD *pState )
{
if (_pChannel == NULL)
return RPC_E_CALL_COMPLETE;
return _pChannel->GetState( &_Message, pState );
}
//+-------------------------------------------------------------------
//
// Member: CStubComplete::QueryInterface, public
//
// Synopsis: Returns a pointer to the requested interface.
//
//--------------------------------------------------------------------
STDMETHODIMP CStubComplete::QueryInterface( REFIID riid, LPVOID FAR* ppvObj)
{
return _pControl->QueryInterface( riid, ppvObj );
}
//+-------------------------------------------------------------------
//
// Member: CStubComplete::Release, public
//
// Synopsis: Releases an interface
//
//--------------------------------------------------------------------
STDMETHODIMP_(ULONG) CStubComplete::Release()
{
return _pControl->Release();
}
//+-------------------------------------------------------------------
//
// Member: CStubComplete::TestCancel, public
//
// Synopsis: Is call canceled?
//
//--------------------------------------------------------------------
STDMETHODIMP CStubComplete::TestCancel()
{
HRESULT hr;
DWORD state;
// The call is complete is already cleaned up.
if (_pChannel == NULL)
return RPC_E_CALL_COMPLETE;
// Ask the channel about the state of the call.
hr = _pChannel->GetState( &_Message, &state );
if (FAILED(hr))
return hr;
// Convert the flags to error codes.
if (state & DCOM_CALL_CANCELED)
return RPC_E_CALL_CANCELED;
else if (state & DCOM_CALL_COMPLETE)
return RPC_E_CALL_COMPLETE;
else
return RPC_S_CALLPENDING;
}