1010 lines
31 KiB
C++
1010 lines
31 KiB
C++
/*++
|
|
|
|
Copyright (C) 1998-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
MTGTMRSH.CPP
|
|
|
|
Abstract:
|
|
|
|
Multi Target Marshaling.
|
|
|
|
History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include <stdio.h>
|
|
#include "mtgtmrsh.h"
|
|
#include <fastall.h>
|
|
#include <cominit.h>
|
|
|
|
//****************************************************************************
|
|
//****************************************************************************
|
|
// PS FACTORY
|
|
//****************************************************************************
|
|
//****************************************************************************
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CMultiTargetFactoryBuffer::XEnumFactory::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 CMultiTargetFactoryBuffer::XEnumFactory::CreateProxy(IN IUnknown* pUnkOuter,
|
|
IN REFIID riid, OUT IRpcProxyBuffer** ppProxy, void** ppv)
|
|
{
|
|
if(riid != IID_IWbemMultiTarget)
|
|
{
|
|
*ppProxy = NULL;
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
CMultiTargetProxyBuffer* pProxy = new CMultiTargetProxyBuffer(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;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CMultiTargetFactoryBuffer::XEnumFactory::CreateStub
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Creates a stublet. Also passes a pointer to the clients IWbemMultiTarget
|
|
// interface.
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// S_OK all is well
|
|
//
|
|
//***************************************************************************
|
|
|
|
STDMETHODIMP CMultiTargetFactoryBuffer::XEnumFactory::CreateStub(IN REFIID riid,
|
|
IN IUnknown* pUnkServer, OUT IRpcStubBuffer** ppStub)
|
|
{
|
|
if(riid != IID_IWbemMultiTarget)
|
|
{
|
|
*ppStub = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
CMultiTargetStubBuffer* pStub = new CMultiTargetStubBuffer(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* CMultiTargetFactoryBuffer::GetInterface(REFIID riid)
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// CMultiTargetFactoryBuffer 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* CMultiTargetFactoryBuffer::GetInterface(REFIID riid)
|
|
{
|
|
if(riid == IID_IPSFactoryBuffer)
|
|
return &m_XEnumFactory;
|
|
else return NULL;
|
|
}
|
|
|
|
//****************************************************************************
|
|
//****************************************************************************
|
|
// PROXY
|
|
//****************************************************************************
|
|
//****************************************************************************
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CMultiTargetProxyBuffer::CMultiTargetProxyBuffer
|
|
// ~CMultiTargetProxyBuffer::CMultiTargetProxyBuffer
|
|
//
|
|
// 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
|
|
//
|
|
//***************************************************************************
|
|
|
|
CMultiTargetProxyBuffer::CMultiTargetProxyBuffer(CLifeControl* pControl, IUnknown* pUnkOuter)
|
|
: m_pControl(pControl), m_pUnkOuter(pUnkOuter), m_lRef(0),
|
|
m_XMultiTargetFacelet(this), m_pChannel(NULL), m_pOldProxy( NULL ), m_pOldProxyMultiTarget( NULL ),
|
|
m_fTriedSmartEnum( FALSE ), m_fUseSmartMultiTarget( FALSE ), m_hSmartNextMutex( INVALID_HANDLE_VALUE ),
|
|
m_pSmartMultiTarget( NULL ), m_fRemote( false )
|
|
{
|
|
m_pControl->ObjectCreated(this);
|
|
InitializeCriticalSection( &m_cs );
|
|
// m_StubType = UNKNOWN;
|
|
|
|
}
|
|
|
|
CMultiTargetProxyBuffer::~CMultiTargetProxyBuffer()
|
|
{
|
|
if ( NULL != m_pSmartMultiTarget )
|
|
{
|
|
m_pSmartMultiTarget->Release();
|
|
}
|
|
|
|
// This MUST be released before releasing
|
|
// the Proxy pointer
|
|
if ( NULL != m_pOldProxyMultiTarget )
|
|
{
|
|
m_pOldProxyMultiTarget->Release();
|
|
}
|
|
|
|
if ( NULL != m_pOldProxy )
|
|
{
|
|
m_pOldProxy->Release();
|
|
}
|
|
|
|
if(m_pChannel)
|
|
m_pChannel->Release();
|
|
|
|
// Cleanup the mutex
|
|
if ( INVALID_HANDLE_VALUE != m_hSmartNextMutex )
|
|
{
|
|
CloseHandle( m_hSmartNextMutex );
|
|
}
|
|
|
|
m_pControl->ObjectDestroyed(this);
|
|
|
|
DeleteCriticalSection( &m_cs );
|
|
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CMultiTargetProxyBuffer::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_lRef);
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CMultiTargetProxyBuffer::Release()
|
|
{
|
|
long lRef = InterlockedDecrement(&m_lRef);
|
|
if(lRef == 0)
|
|
delete this;
|
|
return lRef;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CMultiTargetProxyBuffer::QueryInterface(REFIID riid, void** ppv)
|
|
{
|
|
if(riid == IID_IUnknown || riid == IID_IRpcProxyBuffer)
|
|
{
|
|
*ppv = (IRpcProxyBuffer*)this;
|
|
}
|
|
else if(riid == IID_IWbemMultiTarget)
|
|
{
|
|
*ppv = (IWbemMultiTarget*)&m_XMultiTargetFacelet;
|
|
}
|
|
else return E_NOINTERFACE;
|
|
|
|
((IUnknown*)*ppv)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// HRESULT STDMETHODCALLTYPE CMultiTargetProxyBuffer::XMultiTargetFacelet::
|
|
// 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 CMultiTargetProxyBuffer::XMultiTargetFacelet::
|
|
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 if ( riid == IID_IClientSecurity )
|
|
{
|
|
// We handle this here in the facelet
|
|
AddRef();
|
|
*ppv = (IClientSecurity*) this;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return m_pObject->m_pUnkOuter->QueryInterface(riid, ppv);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////
|
|
// IClientSecurity Methods //
|
|
//////////////////////////////
|
|
|
|
HRESULT STDMETHODCALLTYPE CMultiTargetProxyBuffer::XMultiTargetFacelet::
|
|
QueryBlanket( IUnknown* pProxy, DWORD* pAuthnSvc, DWORD* pAuthzSvc,
|
|
OLECHAR** pServerPrincName, DWORD* pAuthnLevel, DWORD* pImpLevel,
|
|
void** pAuthInfo, DWORD* pCapabilities )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Return our security as stored in the pUnkOuter.
|
|
|
|
IClientSecurity* pCliSec;
|
|
|
|
// We pass through to the PUNKOuter
|
|
hr = m_pObject->m_pUnkOuter->QueryInterface( IID_IClientSecurity, (void**) &pCliSec );
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
hr = pCliSec->QueryBlanket( pProxy, pAuthnSvc, pAuthzSvc, pServerPrincName,
|
|
pAuthnLevel, pImpLevel, pAuthInfo, pCapabilities );
|
|
pCliSec->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CMultiTargetProxyBuffer::XMultiTargetFacelet::
|
|
SetBlanket( IUnknown* pProxy, DWORD AuthnSvc, DWORD AuthzSvc,
|
|
OLECHAR* pServerPrincName, DWORD AuthnLevel, DWORD ImpLevel,
|
|
void* pAuthInfo, DWORD Capabilities )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
IClientSecurity* pCliSec;
|
|
|
|
// This will enable us to make calls to QueryInterface(), AddRef()/Release() that
|
|
// may have to go remote
|
|
|
|
// Only set the IUnknown blanket if we are remoting and it appears that the authinfo contains
|
|
// credentials
|
|
if ( m_pObject->m_fRemote &&
|
|
DoesContainCredentials( (COAUTHIDENTITY*) pAuthInfo ) )
|
|
{
|
|
// This will enable us to make calls to QueryInterface(), AddRef()/Release() that
|
|
// may have to go remote
|
|
|
|
hr = CoSetProxyBlanket( m_pObject->m_pUnkOuter, AuthnSvc, AuthzSvc, pServerPrincName,
|
|
AuthnLevel, ImpLevel, pAuthInfo, Capabilities );
|
|
|
|
}
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
// We pass through to the PUNKOuter
|
|
hr = m_pObject->m_pUnkOuter->QueryInterface( IID_IClientSecurity, (void**) &pCliSec );
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
hr = pCliSec->SetBlanket( pProxy, AuthnSvc, AuthzSvc, pServerPrincName,
|
|
AuthnLevel, ImpLevel, pAuthInfo, Capabilities );
|
|
pCliSec->Release();
|
|
}
|
|
|
|
// Make sure we have a smart enumerator and that we are going to
|
|
// be using it. If so, make sure the values applied to us are also
|
|
// applied to it's proxy
|
|
|
|
if ( SUCCEEDED( m_pObject->InitSmartMultiTarget( TRUE, AuthnSvc, AuthzSvc, pServerPrincName,
|
|
AuthnLevel, ImpLevel, pAuthInfo, Capabilities ) ) && m_pObject->m_fUseSmartMultiTarget )
|
|
{
|
|
// Now repeat the above operation for the smart enumerator
|
|
// Ignore the IUnknown if we are not remoting
|
|
hr = WbemSetProxyBlanket( m_pObject->m_pSmartMultiTarget, AuthnSvc, AuthzSvc, pServerPrincName,
|
|
AuthnLevel, ImpLevel, pAuthInfo, Capabilities, !m_pObject->m_fRemote );
|
|
|
|
} // If initialized smart enumerator
|
|
|
|
} // If Set Blanket on IUnknown
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CMultiTargetProxyBuffer::XMultiTargetFacelet::
|
|
CopyProxy( IUnknown* pProxy, IUnknown** ppCopy )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
IClientSecurity* pCliSec;
|
|
|
|
// We pass through to the PUNKOuter
|
|
hr = m_pObject->m_pUnkOuter->QueryInterface( IID_IClientSecurity, (void**) &pCliSec );
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
hr = pCliSec->CopyProxy( pProxy, ppCopy );
|
|
pCliSec->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//////////////////////////////////////////////
|
|
//////////////////////////////////////////////
|
|
|
|
// IWbemMultiTarget Methods -- Pass Thrus for now
|
|
|
|
//////////////////////////////////////////////
|
|
//////////////////////////////////////////////
|
|
|
|
HRESULT STDMETHODCALLTYPE CMultiTargetProxyBuffer::XMultiTargetFacelet::
|
|
DeliverEvent(DWORD dwNumEvents, IWbemClassObject** apEvents, WBEM_REM_TARGETS* aTargets,
|
|
long lSDLength, BYTE* pSD)
|
|
{
|
|
// Also, we will need to queue calls into this proxy, preserving timeouts,
|
|
// so I'm thinking a mutex would come in handy about now...
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
// Make sure we have a smart enumerator if we can get one
|
|
m_pObject->InitSmartMultiTarget();
|
|
|
|
// If we have a smart enumerator, go behind everyone's back and use this guy (nobody
|
|
// will be the wiser...
|
|
|
|
if ( m_pObject->m_fUseSmartMultiTarget && NULL != m_pObject->m_pSmartMultiTarget )
|
|
{
|
|
|
|
// Function MUST be thread safe
|
|
CInCritSec ics(&m_pObject->m_cs);
|
|
|
|
// Calculate data length first
|
|
DWORD dwLength;
|
|
|
|
GUID* pGUIDs = NULL;
|
|
BOOL* pfSendFullObject = NULL;
|
|
|
|
try
|
|
{
|
|
// Allocate arrays for the guid and the flags
|
|
pGUIDs = new GUID[dwNumEvents];
|
|
pfSendFullObject = new BOOL[dwNumEvents];
|
|
|
|
CWbemMtgtDeliverEventPacket packet;
|
|
hr = packet.CalculateLength(dwNumEvents, apEvents, &dwLength,
|
|
m_ClassToIdMap, pGUIDs, pfSendFullObject );
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
|
|
// As we could be going cross process/machine, use the
|
|
// COM memory allocator
|
|
LPBYTE pbData = (LPBYTE) CoTaskMemAlloc( dwLength );
|
|
|
|
if ( NULL != pbData )
|
|
{
|
|
|
|
// Write the objects out to the buffer
|
|
hr = packet.MarshalPacket( pbData, dwLength, dwNumEvents,
|
|
apEvents, pGUIDs, pfSendFullObject);
|
|
|
|
// Copy the values, we're golden.
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
// Now we can send the data to the stub
|
|
hr = m_pObject->m_pSmartMultiTarget->DeliverEvent( dwNumEvents, dwLength, pbData, aTargets, lSDLength, pSD );
|
|
}
|
|
|
|
// Because the buffer is an [in] parameter, it lies on our heads
|
|
// to free it up.
|
|
CoTaskMemFree( pbData );
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
} // IF CalculateLength()
|
|
}
|
|
catch (CX_MemoryException)
|
|
{
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
catch(...)
|
|
{
|
|
hr = WBEM_E_FAILED;
|
|
}
|
|
|
|
// Cleanup the arrays
|
|
if ( NULL != pGUIDs )
|
|
{
|
|
delete [] pGUIDs;
|
|
}
|
|
|
|
if ( NULL != pfSendFullObject )
|
|
{
|
|
delete pfSendFullObject;
|
|
}
|
|
|
|
} // IF using Smart Enumeration
|
|
else
|
|
{
|
|
// No Smart enumerator (doh!), so use the old one
|
|
hr = m_pObject->m_pOldProxyMultiTarget->DeliverEvent(dwNumEvents, apEvents, aTargets, lSDLength, pSD );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CMultiTargetProxyBuffer::XMultiTargetFacelet::
|
|
DeliverStatus( long lFlags, HRESULT hresStatus, LPCWSTR wszStatus, IWbemClassObject* pErrorObj,
|
|
WBEM_REM_TARGETS* pTargets, long lSDLength, BYTE* pSD)
|
|
{
|
|
// Just pass through to the old sink.
|
|
return m_pObject->m_pOldProxyMultiTarget->DeliverStatus( lFlags, hresStatus, wszStatus, pErrorObj, pTargets, lSDLength, pSD );
|
|
}
|
|
|
|
/*
|
|
HRESULT STDMETHODCALLTYPE CMultiTargetProxyBuffer::XMultiTargetFacelet::
|
|
Next(long lTimeout, ULONG uCount, IWbemClassObject** apObj, ULONG FAR* puReturned)
|
|
{
|
|
|
|
// At this point we will Query for the new, improved IEnumWCOSmartNext interface.
|
|
// If we get it, we will maintain a pointer to that interface and
|
|
// pass through to that interface. We will also call CoCreateGuid() so
|
|
// we get a unique identifier on the other end for sending wbem objects
|
|
// back and forth cleanly.
|
|
|
|
// The interface will have a single method IEnumWCOSmartNext::Next
|
|
// This will take a GUID identifying this proxy, lTimeout, uCount,
|
|
// puReturned, then dwBuffSize and BYTE**.
|
|
|
|
// The other end will allocate memory via CoTaskMemAlloc and this side will
|
|
// Free it via CoTaskMemFree.
|
|
|
|
// The other side will Marshal returned objects into the memory block.
|
|
// This side will Unmarshal it (and then free the block).
|
|
|
|
//
|
|
// SAMPLE IDL:
|
|
// IEnumWCOSmartNext::Next( [in] GUID proxyGUID,
|
|
// [in] LONG lTimeout,
|
|
// [in] unsigned long uCount,
|
|
// [in, out] DWORD* puReturned,
|
|
// [in, out] DWORD* pdwBuffSize,
|
|
// [in, out, size_is[,*pdwBuffSize] BYTE** pBuffer
|
|
//
|
|
|
|
// Also, we will need to queue calls into this proxy, preserving timeouts,
|
|
// so I'm thinking a mutex would come in handy about now...
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
// Make sure the timeout value makes sense
|
|
if ( lTimeout < 0 && lTimeout != WBEM_INFINITE )
|
|
{
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Make sure we have a smart enumerator if we can get one
|
|
m_pObject->InitSmartMultiTarget();
|
|
|
|
// If we have a smart enumerator, go behind everyone's back and use this guy (nobody
|
|
// will be the wiser...
|
|
|
|
if ( m_pObject->m_fUseSmartMultiTarget && NULL != m_pObject->m_pSmartMultiTarget )
|
|
{
|
|
DWORD dwOldTick = GetTickCount();
|
|
DWORD dwReturn = WaitForSingleObject( m_pObject->m_hSmartNextMutex, lTimeout );
|
|
|
|
if ( WAIT_OBJECT_0 == dwReturn )
|
|
{
|
|
BYTE* pBuffer = NULL;
|
|
ULONG uSizeOfBuffer = 0;
|
|
|
|
// Adjust timeout (if it was > 0) for any milliseconds we may
|
|
// have just been waiting.
|
|
|
|
if ( lTimeout > 0 )
|
|
{
|
|
// Get the current tick count. Be aware that a tick count will
|
|
// rollover every 30 some odd days, so trap for this case by
|
|
// checking that the new tick count >= the old one
|
|
|
|
DWORD dwCurrTick = GetTickCount();
|
|
dwCurrTick = ( dwCurrTick >= dwOldTick ? dwCurrTick : dwOldTick );
|
|
|
|
// Adjust the timeout, but don't let it fall below 0
|
|
lTimeout -= ( dwCurrTick - dwOldTick );
|
|
lTimeout = ( lTimeout < 0 ? 0 : lTimeout );
|
|
}
|
|
|
|
// Ask the server for objects
|
|
hr = m_pObject->m_pSmartMultiTarget->Next( m_pObject->m_guidSmartEnum, lTimeout, uCount, puReturned, &uSizeOfBuffer, &pBuffer );
|
|
|
|
// Only need to unmarshal if objects are in the buffer
|
|
if ( SUCCEEDED( hr ) && *puReturned > 0 )
|
|
{
|
|
|
|
CWbemSmartEnumNextPacket packet( (LPBYTE) pBuffer, uSizeOfBuffer );
|
|
long lObjectCount;
|
|
IWbemClassObject ** pObjArray;
|
|
hr = packet.UnmarshalPacket( lObjectCount, pObjArray, m_ClassCache );
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
// Copy *puReturned pointers from the allocated pObjArray into apObj.
|
|
CopyMemory( apObj, pObjArray, ( *puReturned * sizeof(IWbemClassObject*) ) );
|
|
|
|
// Clean up pObjArray It is the caller's responsibility to free
|
|
// the IWbemClassObject* pointers.
|
|
delete [] pObjArray;
|
|
|
|
} // IF UnmarshalPacket
|
|
|
|
// Free the memory buffer (allocated by WinMgmt via CoTaskMemAlloc)
|
|
CoTaskMemFree( pBuffer );
|
|
|
|
} // IF Next
|
|
|
|
ReleaseMutex( m_pObject->m_hSmartNextMutex );
|
|
|
|
} // IF WAIT_OBJECT_0
|
|
else if ( WAIT_TIMEOUT == dwReturn )
|
|
{
|
|
// Timed out on the mutex
|
|
hr = WBEM_S_TIMEDOUT;
|
|
}
|
|
else
|
|
{
|
|
hr = WBEM_E_FAILED;
|
|
}
|
|
|
|
} // IF using Smart Enumeration
|
|
else
|
|
{
|
|
// No Smart enumerator (doh!), so use the old one
|
|
hr = m_pObject->m_pOldProxyMultiTarget->Next( lTimeout, uCount, apObj, puReturned );
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
*/
|
|
|
|
//***************************************************************************
|
|
//
|
|
// STDMETHODIMP CMultiTargetProxyBuffer::Connect(IRpcChannelBuffer* pChannel)
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Called during the initialization of the proxy. The channel buffer is passed
|
|
// to this routine.
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// S_OK all is well
|
|
//
|
|
//***************************************************************************
|
|
|
|
STDMETHODIMP CMultiTargetProxyBuffer::Connect(IRpcChannelBuffer* pChannel)
|
|
{
|
|
|
|
// get a pointer to the old sink which is in WBEMSVC.DLL this allows
|
|
// for backward compatibility
|
|
|
|
IPSFactoryBuffer* pIPS;
|
|
|
|
// Establish the marshaling context
|
|
DWORD dwCtxt = 0;
|
|
pChannel->GetDestCtx( &dwCtxt, NULL );
|
|
|
|
m_fRemote = ( dwCtxt == MSHCTX_DIFFERENTMACHINE );
|
|
|
|
// This is tricky --- The old proxys/stub stuff is actually registered under the
|
|
// IID_IWbemObjectSink in wbemcli_p.cpp. This single class id, is backpointered
|
|
// by ProxyStubClsId32 entries for all the standard WBEM interfaces.
|
|
|
|
HRESULT hr = CoGetClassObject( IID_IWbemObjectSink, CLSCTX_INPROC_HANDLER | CLSCTX_INPROC_SERVER,
|
|
NULL, IID_IPSFactoryBuffer, (void**) &pIPS );
|
|
|
|
// We aggregated it --- WE OWN IT!
|
|
|
|
hr = pIPS->CreateProxy( this, IID_IWbemMultiTarget, &m_pOldProxy, (void**) &m_pOldProxyMultiTarget );
|
|
pIPS->Release();
|
|
|
|
// Connect the old proxy to the channel
|
|
hr = m_pOldProxy->Connect( pChannel );
|
|
|
|
// Save an internal reference to the channel
|
|
if(m_pChannel)
|
|
return E_UNEXPECTED;
|
|
|
|
m_pChannel = pChannel;
|
|
if(m_pChannel)
|
|
m_pChannel->AddRef();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// HRESULT CMultiTargetProxyBuffer::InitSmartMultiTarget(void)
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Called during the initialization of the proxy. This function sets up
|
|
// the smart enumerator pointer so we can perform intelligent marshaling.
|
|
// This cannot be called during a Connect operation.
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// S_OK all is well
|
|
//
|
|
//***************************************************************************
|
|
|
|
HRESULT CMultiTargetProxyBuffer::InitSmartMultiTarget( BOOL fSetBlanket, DWORD AuthnSvc, DWORD AuthzSvc,
|
|
OLECHAR* pServerPrincName, DWORD AuthnLevel, DWORD ImpLevel,
|
|
void* pAuthInfo, DWORD Capabilities )
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
// Function MUST be thread safe
|
|
CInCritSec ics(&m_cs);
|
|
|
|
// If we haven't tried to estalish smart enumeration, do so now
|
|
|
|
// If we haven't tried to get a smart enumerator, try to get one. If
|
|
// we are able to get one, initialize member data we will use in all
|
|
// operations from this proxy.
|
|
|
|
if ( NULL == m_pSmartMultiTarget )
|
|
{
|
|
|
|
// We'll only get this interface pointer if the server is a new
|
|
// version that understands this interface. If it does, the pointer
|
|
// will be marshaled through for us. To get to this pointer,
|
|
// we go directly through our punkOuter. From the "fetcher" interface
|
|
// we will then get the actual smart enumerator. We can then free up
|
|
// the fetcher and release it's lock on the proxy manager. The
|
|
// smart enumerator will be handled on its own.
|
|
|
|
IWbemFetchSmartMultiTarget* pFetchSmartMultiTarget;
|
|
|
|
hr = m_pUnkOuter->QueryInterface( IID_IWbemFetchSmartMultiTarget, (void**) &pFetchSmartMultiTarget );
|
|
|
|
// Generate a GUID to identify us when we call the smart enumerator
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
|
|
// If we need to, set the blanket on the proxy, otherwise, the call to GetSmartEnum
|
|
// may fail.
|
|
if ( fSetBlanket )
|
|
{
|
|
// Ignore the IUnknown if we are not remoting
|
|
hr = WbemSetProxyBlanket( pFetchSmartMultiTarget, AuthnSvc, AuthzSvc, pServerPrincName,
|
|
AuthnLevel, ImpLevel, pAuthInfo, Capabilities, !m_fRemote );
|
|
}
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
|
|
hr = pFetchSmartMultiTarget->GetSmartMultiTarget( &m_pSmartMultiTarget );
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
// We need a GUID
|
|
hr = CoCreateGuid( &m_guidSmartEnum );
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
// We'll also need a Mutex (so we can timeout) here
|
|
|
|
m_hSmartNextMutex = CreateMutex( NULL, FALSE, NULL );
|
|
|
|
if ( INVALID_HANDLE_VALUE != m_hSmartNextMutex )
|
|
{
|
|
// We have everything we need to do things smartly
|
|
m_fUseSmartMultiTarget = TRUE;
|
|
}
|
|
} // IF CoCreateGuid
|
|
|
|
} // IF got Smart MultiTarget
|
|
|
|
} // IF security OK
|
|
|
|
// Done with the fetcher interface
|
|
pFetchSmartMultiTarget->Release();
|
|
|
|
} // IF QueryInterface
|
|
else
|
|
{
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
} // IF NULL == m_pSmartMultiTarget
|
|
|
|
return hr;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// STDMETHODIMP CMultiTargetProxyBuffer::Disconnect(IRpcChannelBuffer* pChannel)
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Called when the proxy is being disconnected. It just frees various pointers.
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// S_OK all is well
|
|
//
|
|
//***************************************************************************
|
|
|
|
void STDMETHODCALLTYPE CMultiTargetProxyBuffer::Disconnect()
|
|
{
|
|
// Old Proxy code
|
|
|
|
if(m_pOldProxy)
|
|
m_pOldProxy->Disconnect();
|
|
|
|
// Complete the Disconnect by releasing our references to the
|
|
// old proxy pointers. The old Proxy Enum MUST be released first.
|
|
|
|
if ( NULL != m_pOldProxyMultiTarget )
|
|
{
|
|
m_pOldProxyMultiTarget->Release();
|
|
m_pOldProxyMultiTarget = NULL;
|
|
}
|
|
|
|
if ( NULL != m_pOldProxy )
|
|
{
|
|
m_pOldProxy->Release();
|
|
m_pOldProxy = NULL;
|
|
}
|
|
|
|
if(m_pChannel)
|
|
m_pChannel->Release();
|
|
m_pChannel = NULL;
|
|
}
|
|
|
|
//****************************************************************************
|
|
//****************************************************************************
|
|
// STUB
|
|
//****************************************************************************
|
|
//****************************************************************************
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// void* CMultiTargetFactoryBuffer::GetInterface(REFIID riid)
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// CMultiTargetFactoryBuffer 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* CMultiTargetStubBuffer::GetInterface(REFIID riid)
|
|
{
|
|
if(riid == IID_IRpcStubBuffer)
|
|
return &m_XMultiTargetStublet;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
CMultiTargetStubBuffer::XMultiTargetStublet::XMultiTargetStublet(CMultiTargetStubBuffer* pObj)
|
|
: CImpl<IRpcStubBuffer, CMultiTargetStubBuffer>(pObj), m_pServer(NULL), m_lConnections( 0 )
|
|
{
|
|
}
|
|
|
|
CMultiTargetStubBuffer::XMultiTargetStublet::~XMultiTargetStublet()
|
|
{
|
|
if(m_pServer)
|
|
m_pServer->Release();
|
|
|
|
if ( NULL != m_pObject->m_pOldStub )
|
|
{
|
|
m_pObject->m_pOldStub->Release();
|
|
m_pObject->m_pOldStub = NULL;
|
|
}
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// STDMETHODIMP CMultiTargetStubBuffer::Connect(IUnknown* pUnkServer)
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Called during the initialization of the stub. The pointer to the
|
|
// IWbemObject sink object is passed in.
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// S_OK all is well
|
|
//
|
|
//***************************************************************************
|
|
|
|
STDMETHODIMP CMultiTargetStubBuffer::XMultiTargetStublet::Connect(IUnknown* pUnkServer)
|
|
{
|
|
if(m_pServer)
|
|
return E_UNEXPECTED;
|
|
|
|
HRESULT hres = pUnkServer->QueryInterface(IID_IWbemMultiTarget,
|
|
(void**)&m_pServer);
|
|
if(FAILED(hres))
|
|
return E_NOINTERFACE;
|
|
|
|
// get a pointer to the old stub which is in WBEMSVC.DLL this allows
|
|
// for backward compatibility
|
|
|
|
IPSFactoryBuffer* pIPS;
|
|
|
|
// This is tricky --- The old proxys/stub stuff is actually registered under the
|
|
// IID_IWbemObjectSink in wbemcli_p.cpp. This single class id, is backpointered
|
|
// by ProxyStubClsId32 entries for all the standard WBEM interfaces.
|
|
|
|
HRESULT hr = CoGetClassObject( IID_IWbemObjectSink, CLSCTX_INPROC_HANDLER | CLSCTX_INPROC_SERVER,
|
|
NULL, IID_IPSFactoryBuffer, (void**) &pIPS );
|
|
|
|
hr = pIPS->CreateStub( IID_IWbemMultiTarget, m_pServer, &m_pObject->m_pOldStub );
|
|
|
|
pIPS->Release();
|
|
|
|
// Successful connection
|
|
|
|
m_lConnections++;
|
|
return S_OK;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// void STDMETHODCALLTYPE CMultiTargetStubBuffer::XMultiTargetStublet::Disconnect()
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Called when the stub is being disconnected. It frees the IWbemMultiTarget
|
|
// pointer.
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// S_OK all is well
|
|
//
|
|
//***************************************************************************
|
|
|
|
void STDMETHODCALLTYPE CMultiTargetStubBuffer::XMultiTargetStublet::Disconnect()
|
|
{
|
|
// Inform the listener of the disconnect
|
|
// =====================================
|
|
|
|
HRESULT hres = S_OK;
|
|
|
|
if(m_pObject->m_pOldStub)
|
|
m_pObject->m_pOldStub->Disconnect();
|
|
|
|
if(m_pServer)
|
|
{
|
|
m_pServer->Release();
|
|
m_pServer = NULL;
|
|
}
|
|
|
|
// Successful disconnect
|
|
m_lConnections--;
|
|
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// STDMETHODIMP CMultiTargetStubBuffer::XMultiTargetStublet::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 CMultiTargetStubBuffer::XMultiTargetStublet::Invoke(RPCOLEMESSAGE* pMessage,
|
|
IRpcChannelBuffer* pChannel)
|
|
{
|
|
// SetStatus is a pass through to the old layer
|
|
return m_pObject->m_pOldStub->Invoke( pMessage, pChannel );
|
|
}
|
|
|
|
IRpcStubBuffer* STDMETHODCALLTYPE CMultiTargetStubBuffer::XMultiTargetStublet::IsIIDSupported(
|
|
REFIID riid)
|
|
{
|
|
if(riid == IID_IWbemMultiTarget)
|
|
{
|
|
// Don't AddRef(). At least that's what the sample on
|
|
// Inside DCOM p.341 does.
|
|
//AddRef(); // ?? not sure
|
|
return this;
|
|
}
|
|
else return NULL;
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CMultiTargetStubBuffer::XMultiTargetStublet::CountRefs()
|
|
{
|
|
// See Page 340-41 in Inside DCOM
|
|
return m_lConnections;
|
|
}
|
|
|
|
STDMETHODIMP CMultiTargetStubBuffer::XMultiTargetStublet::DebugServerQueryInterface(void** ppv)
|
|
{
|
|
if(m_pServer == NULL)
|
|
return E_UNEXPECTED;
|
|
|
|
*ppv = m_pServer;
|
|
return S_OK;
|
|
}
|
|
|
|
void STDMETHODCALLTYPE CMultiTargetStubBuffer::XMultiTargetStublet::DebugServerRelease(void* pv)
|
|
{
|
|
}
|
|
|