admin
activec
admt
burnslib
cmdline
consoles
controls
cys
darwin
dcpromo
display
dsadminlib
dsclientnt4
dscmd
dsutils
dsweb
eelvewer
extens
hmonitor
netid
netui
pchealth
published
select
services
sms
snapin
wizards
wmi
wbem
adapters
bvt
common
consumers
copyright
cppunit
embedded
policman
providers
scripting
sdk
setup
shell
test
tools
valuadd
winmgmt
a51
a512rosw
adap
baseprov
comlib
contprov
coredll
coretest
dbgsignal
egg
ess3
esscli
esscomp
eventconsshell
eventprovshell
heaptrak
hiperstress
kernel33
marshalers
addrrslv
conscript
coreprox
dcomsec
fastprox
cloadhpenum.cpp
cloadhpenum.h
context.cpp
context.h
enummrsh.cpp
enummrsh.h
fastprox.cpp
fastprox.h
makefile
makefile.all
makefile.inc
makefile.sms
mrshbase.cpp
mrshbase.h
mtgtmrsh.cpp
mtgtmrsh.h
precomp.h
proxmain.cpp
proxy.src
refrcli.cpp
refrcli.h
refrmrsh.cpp
refrmrsh.h
sinkmrsh.cpp
sinkmrsh.h
sources
ubskmrsh.cpp
ubskmrsh.h
ubskpckt.cpp
ubskpckt.h
ver.rc
kerbtest
proxy
server
server2
shared
stub
trantest
wbemprox
dirs
localloc.cpp
makefile.sms
mc
minimfc
mofcomp_dll
mofcomp_tool
mofcompiler
mofs
msg
ntperf
ntperfclient
ntperfshell
ntsdext
provshell
provsubsys
queries
redirect
repdrvr
roswell
secobj
security
specs
stdprov
wbemcomn
wbemtest
winmgmt2
wmicooker
wmiexts
wmiperf
wmitest
wql
wqlscan
xfiles
dirs
filelist.xls
makefile.inc
makefile.sms
xmltransport
coverage_cleanbuild.bat
coverage_postbuild.bat
dirs
icecap_cleanbuild.bat
dirs
wmiprov
wmiscmgr
dirs
makefile.inc
project.mk
base
com
developer
drivers
ds
enduser
inetcore
inetsrv
loc
mergedcomponents
multimedia
net
printscan
public
published
sdktools
shell
termsrv
tools
windows
dirs
makefil0
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)
|
|
{
|
|
}
|
|
|