|
|
//--------------------------------------------------------------
//
// 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; }
|