2025-04-27 07:49:33 -04:00

591 lines
16 KiB
C++

/*++
Copyright (C) 1998-2001 Microsoft Corporation
Module Name:
SINKMRSH.CPP
Abstract:
IWbemObjectSink marshaling
History:
--*/
#include "precomp.h"
#include <stdio.h>
#include "sinkmrsh.h"
#include <fastall.h>
#define WBEM_S_NEW_STYLE 0x400FF
//****************************************************************************
//****************************************************************************
// PS FACTORY
//****************************************************************************
//****************************************************************************
//***************************************************************************
//
// CSinkFactoryBuffer::XSinkFactory::CreateProxy
//
// DESCRIPTION:
//
// Creates a facelet. Also sets the outer unknown since the proxy is going to be
// aggregated.
//
// RETURN VALUE:
//
// S_OK all is well
//
//***************************************************************************
STDMETHODIMP CSinkFactoryBuffer::XSinkFactory::CreateProxy(IN IUnknown* pUnkOuter,
IN REFIID riid, OUT IRpcProxyBuffer** ppProxy, void** ppv)
{
if(riid != IID_IWbemObjectSink)
{
*ppProxy = NULL;
*ppv = NULL;
return E_NOINTERFACE;
}
CSinkProxyBuffer* pProxy = new CSinkProxyBuffer(m_pObject->m_pLifeControl, pUnkOuter);
SCODE sc = E_OUTOFMEMORY;
if ( NULL != pProxy )
{
pProxy->QueryInterface(IID_IRpcProxyBuffer, (void**)ppProxy);
sc = pProxy->QueryInterface(riid, (void**)ppv);
}
return sc;
}
//***************************************************************************
//
// CSinkFactoryBuffer::XSinkFactory::CreateStub
//
// DESCRIPTION:
//
// Creates a stublet. Also passes a pointer to the clients IWbemObjectSink
// interface.
//
// RETURN VALUE:
//
// S_OK all is well
//
//***************************************************************************
STDMETHODIMP CSinkFactoryBuffer::XSinkFactory::CreateStub(IN REFIID riid,
IN IUnknown* pUnkServer, OUT IRpcStubBuffer** ppStub)
{
if(riid != IID_IWbemObjectSink)
{
*ppStub = NULL;
return E_NOINTERFACE;
}
CSinkStubBuffer* pStub = new CSinkStubBuffer(m_pObject->m_pLifeControl, NULL);
if ( NULL != pStub )
{
pStub->QueryInterface(IID_IRpcStubBuffer, (void**)ppStub);
// Pass the pointer to the clients object
if(pUnkServer)
{
HRESULT hres = (*ppStub)->Connect(pUnkServer);
if(FAILED(hres))
{
delete pStub;
*ppStub = NULL;
}
return hres;
}
else
{
return S_OK;
}
}
else
{
return E_OUTOFMEMORY;
}
}
//***************************************************************************
//
// void* CSinkFactoryBuffer::GetInterface(REFIID riid)
//
// DESCRIPTION:
//
// CSinkFactoryBuffer is derived from CUnk. Since CUnk handles the QI calls,
// all classes derived from it must support this function.
//
// RETURN VALUE:
//
// S_OK all is well
//
//***************************************************************************
void* CSinkFactoryBuffer::GetInterface(REFIID riid)
{
if(riid == IID_IPSFactoryBuffer)
return &m_XSinkFactory;
else return NULL;
}
//****************************************************************************
//****************************************************************************
// PROXY
//****************************************************************************
//****************************************************************************
//***************************************************************************
//
// CSinkProxyBuffer::CSinkProxyBuffer
// ~CSinkProxyBuffer::CSinkProxyBuffer
//
// DESCRIPTION:
//
// Constructor and destructor. The main things to take care of are the
// old style proxy, and the channel
//
// RETURN VALUE:
//
// S_OK all is well
//
//***************************************************************************
CSinkProxyBuffer::CSinkProxyBuffer(CLifeControl* pControl, IUnknown* pUnkOuter)
: CBaseProxyBuffer( pControl, pUnkOuter, IID_IWbemObjectSink ),
m_XSinkFacelet(this), m_pOldProxySink( NULL )
{
m_StubType = UNKNOWN;
}
CSinkProxyBuffer::~CSinkProxyBuffer()
{
// This should be cleaned up here
if ( NULL != m_pOldProxySink )
{
m_pOldProxySink->Release();
}
}
void* CSinkProxyBuffer::GetInterface( REFIID riid )
{
if(riid == IID_IWbemObjectSink)
return &m_XSinkFacelet;
else return NULL;
}
void** CSinkProxyBuffer::GetOldProxyInterfacePtr( void )
{
return (void**) &m_pOldProxySink;
}
void CSinkProxyBuffer::ReleaseOldProxyInterface( void )
{
// We only keep a single reference to this
if ( NULL != m_pOldProxySink )
{
m_pOldProxySink->Release();
m_pOldProxySink = NULL;
}
}
//***************************************************************************
//
// HRESULT STDMETHODCALLTYPE CSinkProxyBuffer::XSinkFacelet::
// QueryInterface(REFIID riid, void** ppv)
//
// DESCRIPTION:
//
// Supports querries for interfaces. The only thing unusual is that
// this object is aggregated by the proxy manager and so some interface
// requests are passed to the outer IUnknown interface.
//
// RETURN VALUE:
//
// S_OK all is well
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CSinkProxyBuffer::XSinkFacelet::
QueryInterface(REFIID riid, void** ppv)
{
// All other interfaces are delegated to the UnkOuter
if( riid == IID_IRpcProxyBuffer )
{
// Trick #2: this is an internal interface that should not be delegated!
// ===================================================================
return m_pObject->QueryInterface(riid, ppv);
}
else
{
return m_pObject->m_pUnkOuter->QueryInterface(riid, ppv);
}
}
//***************************************************************************
//
// HRESULT STDMETHODCALLTYPE CSinkProxyBuffer::XSinkFacelet::
// Indicate( LONG lObjectCount, IWbemClassObject** ppObjArray )
//
// DESCRIPTION:
//
// Proxies the IWbemObjectSink::Indicate calls. Note that if the stub is an
// old style, then the old proxy/stub pair in wbemsvc.dll is used for backward
// compatibility.
//
// RETURN VALUE:
//
// S_OK all is well
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CSinkProxyBuffer::XSinkFacelet::
Indicate( LONG lObjectCount, IWbemClassObject** ppObjArray )
{
HRESULT hr = S_OK;
// Make sure the lObjectCount parameter and the array pointer make sense
if ( lObjectCount < 0 )
{
return WBEM_E_INVALID_PARAMETER;
}
else if ( lObjectCount == 0 && NULL != ppObjArray )
{
return WBEM_E_INVALID_PARAMETER;
}
else if ( lObjectCount > 0 && NULL == ppObjArray )
{
return WBEM_E_INVALID_PARAMETER;
}
CInCritSec ics(&m_cs);
// If the stublet is an old style, just let the old proxy handle it
if(m_pObject->m_StubType == OLD)
return m_pObject->m_pOldProxySink->Indicate( lObjectCount, ppObjArray );
// If the stublet is unknown, send just the first object and check the return
// code to determine what is on the other side.
if(m_pObject->m_StubType == UNKNOWN)
{
hr = m_pObject->m_pOldProxySink->Indicate( 1, ppObjArray );
// bump up pointer to the next object so that it isnt sent more than once
lObjectCount--;
ppObjArray++;
if(FAILED(hr))
return hr;
if(hr == WBEM_S_NEW_STYLE)
{
m_pObject->m_StubType = NEW;
}
else
{
// We have an old client, set the stub type and send any remaining objects
m_pObject->m_StubType = OLD;
if(lObjectCount > 0)
hr = m_pObject->m_pOldProxySink->Indicate( lObjectCount, ppObjArray );
return hr;
}
}
if(lObjectCount < 1)
return S_OK; // if all done, then just return.
// Create a packet and some data for it to use. Then calculate
// the length of the packet
DWORD dwLength;
GUID* pguidClassIds = new GUID[lObjectCount];
BOOL* pfSendFullObject = new BOOL[lObjectCount];
// arrays will be deleted when we drop out of scope.
CVectorDeleteMe<GUID> delpguidClassIds( pguidClassIds );
CVectorDeleteMe<BOOL> delpfSendFullObject( pfSendFullObject );
if ( NULL == pguidClassIds || NULL == pfSendFullObject )
{
return WBEM_E_OUT_OF_MEMORY;
}
CWbemObjSinkIndicatePacket packet;
hr = packet.CalculateLength(lObjectCount, ppObjArray, &dwLength,
m_pObject->m_ClassToIdMap, pguidClassIds, pfSendFullObject );
// Declare the message structure
RPCOLEMESSAGE msg;
memset(&msg, 0, sizeof(msg));
msg.cbBuffer = dwLength;
// This is the id of the Invoke function. This MUST be set before calling GetBuffer, or
// it will fail.
msg.iMethod = 3;
// allocate the channel buffer and marshal the data into it
HRESULT hres = m_pObject->GetChannel()->GetBuffer(&msg, IID_IWbemObjectSink);
if(FAILED(hres)) return hres;
// Setup the packet for marshaling
hr = packet.MarshalPacket( (LPBYTE)msg.Buffer, dwLength, lObjectCount, ppObjArray,
pguidClassIds, pfSendFullObject);
// Send the data to the stub only if the marshaling was successful
if ( SUCCEEDED( hr ) )
{
DWORD dwRes;
hr = m_pObject->GetChannel()->SendReceive(&msg, &dwRes);
if(FAILED(hr))
{
if(msg.Buffer)
m_pObject->GetChannel()->FreeBuffer(&msg);
return dwRes;
}
// We appear to be ok, so get HRESULT
LPBYTE pbData = (LPBYTE) msg.Buffer;
hr = *((HRESULT*) pbData);
m_pObject->GetChannel()->FreeBuffer(&msg);
}
else
{
// Clean up the buffer -- Marshaling the packet failed
if(msg.Buffer)
m_pObject->GetChannel()->FreeBuffer(&msg);
}
return hr;
}
//***************************************************************************
//
// HRESULT STDMETHODCALLTYPE CSinkProxyBuffer::XSinkFacelet::
// SetStatus( LONG lFlags, HRESULT hResult, BSTR strParam, IWbemClassObject* pObjParam )
//
// DESCRIPTION:
//
// Proxies the IWbemObjectSink::SetStatus calls. Note that if the stub is an
// old style, then the old proxy/stub pair in wbemsvc.dll is used for backward
// compatibility.
//
// RETURN VALUE:
//
// S_OK all is well
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CSinkProxyBuffer::XSinkFacelet::
SetStatus( LONG lFlags, HRESULT hResult, BSTR strParam, IWbemClassObject* pObjParam )
{
// Just pass through to the old sink.
return m_pObject->m_pOldProxySink->SetStatus( lFlags, hResult, strParam, pObjParam );
}
//****************************************************************************
//****************************************************************************
// STUB
//****************************************************************************
//****************************************************************************
//***************************************************************************
//
// void* CSinkFactoryBuffer::GetInterface(REFIID riid)
//
// DESCRIPTION:
//
// CSinkFactoryBuffer is derived from CUnk. Since CUnk handles the QI calls,
// all classes derived from this must support this function.
//
// RETURN VALUE:
//
// S_OK all is well
//
//***************************************************************************
void* CSinkStubBuffer::GetInterface(REFIID riid)
{
if(riid == IID_IRpcStubBuffer)
return &m_XSinkStublet;
else
return NULL;
}
CSinkStubBuffer::XSinkStublet::XSinkStublet(CSinkStubBuffer* pObj)
: CBaseStublet(pObj, IID_IWbemObjectSink), m_pServer(NULL)
{
m_bFirstIndicate = true;
}
CSinkStubBuffer::XSinkStublet::~XSinkStublet()
{
if(m_pServer)
m_pServer->Release();
}
IUnknown* CSinkStubBuffer::XSinkStublet::GetServerInterface( void )
{
return m_pServer;
}
void** CSinkStubBuffer::XSinkStublet::GetServerPtr( void )
{
return (void**) &m_pServer;
}
void CSinkStubBuffer::XSinkStublet::ReleaseServerPointer( void )
{
// We only keep a single reference to this
if ( NULL != m_pServer )
{
m_pServer->Release();
m_pServer = NULL;
}
}
//***************************************************************************
//
// STDMETHODIMP CSinkStubBuffer::XSinkStublet::Invoke(RPCOLEMESSAGE* pMessage,
// IRpcChannelBuffer* pChannel)
//
// DESCRIPTION:
//
// Called when a method reaches the stublet. This checks the method id and
// then branches to specific code for the Indicate, or SetStatus calls.
//
// RETURN VALUE:
//
// S_OK all is well
//
//***************************************************************************
STDMETHODIMP CSinkStubBuffer::XSinkStublet::Invoke(RPCOLEMESSAGE* pMessage,
IRpcChannelBuffer* pChannel)
{
// SetStatus is a pass through to the old layer
if ( pMessage->iMethod == 3 )
return Indicate_Stub( pMessage, pChannel );
else if ( pMessage->iMethod == 4 )
return GetOldStub()->Invoke( pMessage, pChannel );
else
return RPC_E_SERVER_CANTUNMARSHAL_DATA;
}
//***************************************************************************
//
// HRESULT CSinkStubBuffer::XSinkStublet::Indicate_Stub( RPCOLEMESSAGE* pMessage,
// IRpcChannelBuffer* pBuffer )
//
// DESCRIPTION:
//
// Handles the Indicate function in the stublet.
//
// RETURN VALUE:
//
// S_OK all is well
//
//***************************************************************************
HRESULT CSinkStubBuffer::XSinkStublet::Indicate_Stub( RPCOLEMESSAGE* pMessage, IRpcChannelBuffer* pBuffer )
{
HRESULT hr = RPC_E_SERVER_CANTUNMARSHAL_DATA;
SCODE sc;
// Determine if an old style, or new style packet has arrived
CWbemObjSinkIndicatePacket packet( (LPBYTE) pMessage->Buffer, pMessage->cbBuffer);
sc = packet.IsValid();
bool bOldStyle = (S_OK != packet.IsValid());
if(bOldStyle)
{
// Pass the call in using the old style stub
hr = GetOldStub()->Invoke( pMessage, pBuffer );
if(hr == S_OK && m_bFirstIndicate)
{
// Let proxy know that we can handle the new style by returning a special return code.
*(( HRESULT __RPC_FAR * )pMessage->Buffer) = WBEM_S_NEW_STYLE;
m_bFirstIndicate = false;
return hr;
}
return hr;
}
m_bFirstIndicate = false;
// Got some new style data. Unmarshall it.
long lObjectCount;
IWbemClassObject ** pObjArray;
sc = packet.UnmarshalPacket( lObjectCount, pObjArray, m_ClassCache );
// Only continue if the Unmarshaling succeeded. If it failed, we still want
// the sc to go back to the other side
if ( SUCCEEDED( sc ) )
{
// Call the acual sink
sc = m_pServer->Indicate( lObjectCount, pObjArray );
for ( int nCtr = 0; nCtr < lObjectCount; nCtr++ )
{
pObjArray[nCtr]->Release();
}
delete [] pObjArray;
}
// Send the results back
pMessage->cbBuffer = sizeof(HRESULT);
hr = pBuffer->GetBuffer( pMessage, IID_IWbemObjectSink );
if ( SUCCEEDED( hr ) )
{
((HRESULT*)pMessage->Buffer)[0] = sc;
}
else
{
hr = sc;
}
return hr;
}