|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1999.
//
// File: scminfo.cxx
//
// Contents: Definitions/objects for use by scm-level activators
//
// History: 05-Sep-99 JSimmons Created
//
//--------------------------------------------------------------------------
#include "act.hxx"
#include "scminfo.hxx"
#include "initguid.h"
// Macros to index into special members of the SCMProcessInfo struct
#define SPI_TO_SIZE(pSPI) (ULONG*)(((BYTE*)pSPI) + sizeof(SCMProcessInfo))
#define SPI_TO_REFCOUNT(pSPI) (LONG*)(((BYTE*)pSPI) + sizeof(SCMProcessInfo) + sizeof(ULONG))
#define SPI_TO_CPROCESS(pSPI) (CProcess**)(((BYTE*)pSPI) + sizeof(SCMProcessInfo) + sizeof(ULONG) + sizeof(ULONG))
#define SPI_TO_WINSTA(pSPI) (WCHAR*)(((BYTE*)pSPI) + sizeof(SCMProcessInfo) + sizeof(ULONG) + sizeof(ULONG) + sizeof(CProcess*))
// Rounding constant for ptr sizes
#if defined(_X86_)
#define MEM_ALIGN_SIZE 4
#else
#ifdef _WIN64
#define MEM_ALIGN_SIZE 16
#else
#define MEM_ALIGN_SIZE 8
#endif
#endif
//+-------------------------------------------------------------------------
//
// Implementation of CSCMProcessControl begins here
//
//--------------------------------------------------------------------------
// Constructor
CSCMProcessControl::CSCMProcessControl() : _lRefs(0), _bInitializedEnum(FALSE) { }
// Destructor
CSCMProcessControl::~CSCMProcessControl() { ASSERT(_lRefs == 0); }
//+-------------------------------------------------------------------------
//
// Function: FindApplication
//
// Synopsis: Creates an enumerator for enumerating over all running com+
// processes that have registered for the specified application.
//
// Arguments: rappid -- the appid they want to know about
// ppESPI -- out param to store the resulting IEnumSCMProcessInfo
//
// Returns: S_OK - life is good; *ppESPI will be non-NULL if at least
// one suitable server was found
// E_INVALIDARG -- one or more parameters was incorrect
// E_OUTOFMEMORY
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessControl::FindApplication(REFGUID rappid, IEnumSCMProcessInfo** ppESPI) { return FindAppOrClass(rappid, gpProcessTable, ppESPI); }
//+-------------------------------------------------------------------------
//
// Function: FindClass
//
// Synopsis: Creates an enumerator for enumerating over all running
// processes that have registered a class factory for the
// specified clsid.
//
// Arguments: rclsid -- the clsid they want to know about
// ppESPI -- out param to store the resulting IEnumSCMProcessInfo
//
// Returns: S_OK - life is good; *ppESPI will be non-NULL if at least
// one suitable server was found
// E_INVALIDARG -- one or more parameters was incorrect
// E_OUTOFMEMORY
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessControl::FindClass(REFCLSID rclsid, IEnumSCMProcessInfo **ppESPI) { return FindAppOrClass((GUID&)rclsid, gpClassTable, ppESPI); }
//+-------------------------------------------------------------------------
//
// Function: FindProcess
//
// Synopsis: Tries to find the specified process (by pid) in the the process
// list; if found, then calls FillInSCMProcessInfo.
//
// Arguments: pid -- process id of the process they're interested in
// ppSPI -- out param to store a ptr to new SCMProcessInfo struct
//
// Returns: S_OK - life is good; *ppSPI will be non-NULL if the process was found
// E_INVALIDARG -- didn't find that pid
// E_OUTOFMEMORY
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessControl::FindProcess(DWORD pid, SCMProcessInfo** ppSPI) { HRESULT hr = S_OK; if (!ppSPI) return E_INVALIDARG; *ppSPI = NULL; //if (pid == gRPCSSPid) // we don't talk about ourselves?
//return E_INVALIDARG;
gpProcessListLock->LockShared(); // look through list of processes
CBListIterator all_procs(gpProcessList); CProcess* pprocess; while (pprocess = (CProcess*)all_procs.Next()) { if (pprocess->GetPID() == pid) { // found it
pprocess->ClientReference(); break; } } gpProcessListLock->UnlockShared(); if (pprocess) { // REVIEW: we assume blindly here that the process in question has
// finished all registration activities. However, it is possible I
// guess for an activator to query about a process before it had
// finished registration. This would not be a very smart activator.
hr = FillInSCMProcessInfo(pprocess, TRUE, ppSPI); ReleaseProcess(pprocess); } return hr; }
//+-------------------------------------------------------------------------
//
// Function: SuspendApplication
//
// Synopsis: Marks as suspended all applications that match the specified
// appid. No other applications of this type will be started
// by RPCSS. If any applications of this type are started
// manually, they also will be marked as suspended.
//
// Arguments: rappid -- appid to suspend
//
// Returns: S_OK
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessControl::SuspendApplication(REFGUID rappid) { CServerTableEntry *pProcessEntry; pProcessEntry = gpProcessTable->Lookup( (GUID&)rappid ); if (pProcessEntry) { pProcessEntry->SuspendApplication(); pProcessEntry->Release(); } return S_OK; }
//+-------------------------------------------------------------------------
//
// Function: SuspendClass
//
// Synopsis: Marks as suspended all class factories that have been
// registered for the specified clsid. If any new class
// factory registrations are encountered after the suspend has
// been issued, the new registrations will also be suspended.
// No new servers will be launched by RPCSS on behalf of this
// clsid.
//
// Arguments: rclsid -- clsid to suspend
//
// Returns: S_OK
// E_INVALIDARG
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessControl::SuspendClass(REFCLSID rclsid) { CServerTableEntry *pClassEntry; pClassEntry = gpClassTable->Lookup( (GUID&)rclsid ); if (pClassEntry) { pClassEntry->SuspendClass(); pClassEntry->Release(); } return S_OK; }
//+-------------------------------------------------------------------------
//
// Function: SuspendProcess
//
// Synopsis: Tries to find the specified process (by pid) in the the process
// list; if found, then marks that process as suspended (unavailable
// for further activations).
//
// Arguments: pid -- process id of the process callers wants to suspend
//
// Returns: S_OK - process was suspended
// E_INVALIDARG -- didn't find that pid
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessControl::SuspendProcess(DWORD pid) { HRESULT hr = E_INVALIDARG; //if (pid == gRPCSSPid) // we don't talk about ourselves?
//return E_INVALIDARG;
gpProcessListLock->LockShared(); // look through list of processes
CBListIterator all_procs(gpProcessList); CProcess* pprocess; while (pprocess = (CProcess*)all_procs.Next()) { if (pprocess->GetPID() == pid) { // found it
pprocess->Suspend(); hr = S_OK; break; } } gpProcessListLock->UnlockShared(); return hr; }
//+-------------------------------------------------------------------------
//
// Function: ResumeApplication
//
// Synopsis: Marks as available for activations all applications previously
// suspended.
//
// Arguments: rappid -- application id the caller wants to un-suspend
//
// Returns: S_OK
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessControl::ResumeApplication(REFGUID rappid) { CServerTableEntry *pProcessEntry; pProcessEntry = gpProcessTable->Lookup( (GUID&)rappid ); if (pProcessEntry) { pProcessEntry->UnsuspendApplication(); pProcessEntry->Release(); } return S_OK; }
//+-------------------------------------------------------------------------
//
// Function: ResumeClass
//
// Synopsis: Marks all servers supporting the specified clsid as available
// for activation.
//
// Arguments: rclsid -- clsid of the object the caller wants to un-suspend
//
// Returns: S_OK
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessControl::ResumeClass(REFCLSID rclsid) { CServerTableEntry *pClassEntry; pClassEntry = gpClassTable->Lookup( (GUID&)rclsid ); if (pClassEntry) { pClassEntry->UnsuspendClass(); pClassEntry->Release(); } return S_OK; }
//+-------------------------------------------------------------------------
//
// Function: ResumeProcess
//
// Synopsis: Tries to find the specified process (by pid) in the the process
// list; if found, then marks that process as unsuspended (ie,
// available for further activations).
//
// Arguments: pid -- process id of the process callers wants to suspend
//
// Returns: S_OK - process was suspended
// E_INVALIDARG -- didn't find that pid
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessControl::ResumeProcess(DWORD pid) { HRESULT hr = E_INVALIDARG; //if (pid == gRPCSSPid) // we don't talk about ourselves?
//return E_INVALIDARG;
gpProcessListLock->LockShared(); // look through list of processes
CBListIterator all_procs(gpProcessList); CProcess* pprocess; while (pprocess = (CProcess*)all_procs.Next()) { if (pprocess->GetPID() == pid) { // found it
pprocess->ClientReference(); break; } } gpProcessListLock->UnlockShared(); if (pprocess) { pprocess->Unsuspend(); ReleaseProcess(pprocess); hr = S_OK; } return hr; }
//+-------------------------------------------------------------------------
//
// Function: RetireApplication
//
// Synopsis: Marks as "retired" all currently running applications with
// the specified appid.
//
// Arguments: appid -- appid to retire
//
// Returns: S_OK - all running applications that matched the appid were
// retired
// E_INVALIDARG
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessControl::RetireApplication(REFGUID rappid) { CServerTableEntry *pProcessEntry; pProcessEntry = gpProcessTable->Lookup( (GUID&)rappid ); if (pProcessEntry) { pProcessEntry->RetireApplication(); pProcessEntry->Release(); } return S_OK; }
//+-------------------------------------------------------------------------
//
// Function: RetireClass
//
// Synopsis: Marks as "retired" all currently running processes which
// have registered a class factory for the specified clsid.
//
// Arguments: rclsid -- clsid to retire
//
// Returns: S_OK
// E_INVALIDARG
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessControl::RetireClass(REFCLSID rclsid) { CServerTableEntry *pClassEntry; pClassEntry = gpClassTable->Lookup( (GUID&)rclsid ); if (pClassEntry) { pClassEntry->RetireClass(); pClassEntry->Release(); } return S_OK; }
//+-------------------------------------------------------------------------
//
// Function: RetireProcess
//
// Synopsis: Tries to find the specified process (by pid) in the the process
// list; if found, then marks that process as retired (ie,
// unavailable for further activations until the end of time).
//
// Arguments: pid -- process id of the process callers wants to retire
//
// Returns: S_OK - process was suspended
// E_INVALIDARG -- didn't find that pid
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessControl::RetireProcess(DWORD pid) { HRESULT hr = E_INVALIDARG; //if (pid == gRPCSSPid) // we don't talk about ourselves
//return E_INVALIDARG;
gpProcessListLock->LockShared(); // look through list of processes
CBListIterator all_procs(gpProcessList); CProcess* pprocess; while (pprocess = (CProcess*)all_procs.Next()) { if (pprocess->GetPID() == pid) { // found it
pprocess->Retire(); hr = S_OK; break; } } gpProcessListLock->UnlockShared(); return hr; }
//+-------------------------------------------------------------------------
//
// Function: FreeSCMProcessInfo
//
// Synopsis: Method that knows how to free a SCMProcessInfo structure,
// including of course its constituent members.
//
// Arguments: ppSPI -- ptr-ptr to the SCMProcessInfo struct
//
// Returns: S_OK - life is good
// E_INVALIDARG -- bad parameter
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessControl::FreeSCMProcessInfo(SCMProcessInfo** ppSPI) { return CSCMProcessControl::FreeSCMProcessInfoPriv(ppSPI); }
//+-------------------------------------------------------------------------
//
// Private CSCMProcessControl methods below here
//
//--------------------------------------------------------------------------
//+-------------------------------------------------------------------------
//
// Function: FillInSCMProcessInfo
//
// Synopsis: Allocates and fills in a SCMProcessInfo structure for the
// given CProcess object.
//
// Arguments: pprocess -- ptr to the CProcess object
// bProcessReady -- whether the process in question is ready to
// receive activations
// ppSPI -- out param to store a ptr to new SCMProcessInfo struct
//
// Returns: S_OK - life is good
// E_OUTOFMEMORY
//
// Notes: assumes that at least a read lock is held by the caller for
// the duration of the call.
//
// The SCMProcessInfo memory is layed out as follows:
//
// <SCMProcessInfo>
// <size of entire allocation>
// <ref count on this struct>
// <CProcess*>
// <winsta string if any>
// <array of clsids if any>
//
// (note that the size and refcount combined make 8 bytes, thus maintaining ptr alignment on Win64)
// (the winsta string is also padded out to a multiple of the platform ptr size)
//
// The pointer members of the SCMProcessInfo struct point beyond the
// SCMProcessInfo struct proper to the appropriate data. The saved CProcess*
// object has an added refcount. The # of users using the struct is counted
// by the ref count field. We don't free the struct until this falls to zero
// (done in FreeSCMProcessInfoPriv below). Use the macros in scminfo.hxx to
// access these undoc'd members.
//
// If you modify this layout watch out for Win64 alignment issues.
//
HRESULT CSCMProcessControl::FillInSCMProcessInfo(CProcess* pprocess, BOOL bProcessReady, SCMProcessInfo** ppSPI) { HRESULT hr = S_OK; ULONG ulWinstaStrlen = 0; SCMProcessInfo* pSPI = NULL; ASSERT(pprocess); ASSERT(ppSPI); *ppSPI = NULL; // Try to take fast path. We can do this if the process in question has not added or
// removed any class registrations.
gpServerLock->LockShared(); if (!pprocess->SPIDirty()) { // great; make a copy of the struct that we previously cached in the process
// object; this struct won't be messed with while we're holding the read lock
hr = CopySCMProcessInfo((SCMProcessInfo*)pprocess->GetSCMProcessInfo(), ppSPI); gpServerLock->UnlockShared(); return hr; } gpServerLock->UnlockShared(); // Darn, the process changed its set of registrations, or this is the first time we've ever
// done this. Take a write lock and do it the hard way
gpServerLock->LockExclusive(); if (!pprocess->SPIDirty()) { // we got beat to the lock
hr = CopySCMProcessInfo((SCMProcessInfo*)pprocess->GetSCMProcessInfo(), ppSPI); gpServerLock->UnlockExclusive(); return hr; } // Find length of the winsta string
if (pprocess->_pwszWinstaDesktop) { ulWinstaStrlen = lstrlenW(pprocess->_pwszWinstaDesktop) + sizeof(WCHAR); // Need for the string buffer to be a even multiple of the ptr size
ulWinstaStrlen = (ulWinstaStrlen + MEM_ALIGN_SIZE - 1) & ~(MEM_ALIGN_SIZE - 1); } // Allocate one buffer to hold the struct, the winsta string, and the CLSIDs:
ULONG ulBufSizeNeeded = sizeof(SCMProcessInfo) + sizeof(ULONG) + sizeof(ULONG) + sizeof(CProcess*) + (ulWinstaStrlen * sizeof(WCHAR)) + (pprocess->_ulClasses * sizeof(CLSID)); pSPI = (SCMProcessInfo*) new BYTE[ ulBufSizeNeeded ]; if (!pSPI) { gpServerLock->UnlockExclusive(); return E_OUTOFMEMORY; } ZeroMemory(pSPI, ulBufSizeNeeded); // Store the allocation size. This takes up an extra dword , but saves
// a lot of time when we have to copy the struct
*SPI_TO_SIZE(pSPI)= ulBufSizeNeeded; // Store a pointer to the CProcess* object itself and take a reference on it
*SPI_TO_CPROCESS(pSPI) = pprocess; pprocess->Reference(); // Mark the initial refcount as one. This refcount belongs to the CProcess object
// when we cache it below
*SPI_TO_REFCOUNT(pSPI) = 1; CLSID* pCLSIDs; WCHAR* pwszWinSta = NULL; // Copy the winsta string
if (ulWinstaStrlen > 0) { pwszWinSta = SPI_TO_WINSTA(pSPI); lstrcpyW(pwszWinSta, pprocess->_pwszWinstaDesktop); pSPI->pwszWinstaDesktop = pwszWinSta; } // Copy the clsids
ULONG ulCLSID = 0; if (pprocess->_ulClasses > 0) { Assert (pwszWinSta); pSPI->ulNumClasses = pprocess->_ulClasses; pSPI->pCLSIDs = (CLSID*) (pwszWinSta + ulWinstaStrlen); CClassReg* pReg = (CClassReg*)pprocess->_listClasses.First(); while (pReg) { pSPI->pCLSIDs[ulCLSID] = pReg->_Guid; pReg = (CClassReg*)pReg->Next(); ulCLSID++; } } ASSERT(ulCLSID == pprocess->_ulClasses); pSPI->pidProcess = pprocess->GetPID(); // We hold a reference on the CProcess object, which owns the process handle until
// it goes away. So it's safe to store the handle directly like this.
// The handle may be NULL if we didn't launch the process, callers have the responsibility
// of checking for this.
pSPI->hProcess = pprocess->GetProcessHandle(); // We hold a reference on the CProcess object, which holds a reference on it's CToken
// object. So it's safe to store the token directly like this, it won't go away.
pSPI->hImpersonationToken = pprocess->GetToken()->GetToken(); // The process will only have a ScmProcessReg if it is a COM+ app
if (pprocess->_pScmProcessReg) { pSPI->dwState |= SPIF_COMPLUS; pSPI->AppId = pprocess->_pScmProcessReg->ProcessGUID; // flip the ready bit
if (pprocess->_pScmProcessReg->ReadinessStatus & SERVERSTATE_READY) { pSPI->dwState |= SPIF_READY; } } else { // Legacy-style server. We consider the process to be "ready" if it's
// not in the midst of doing class registrations. The caller tells us this.
if (bProcessReady) { pSPI->dwState |= SPIF_READY; } } if (pprocess->IsSuspended()) pSPI->dwState |= SPIF_SUSPENDED; if (pprocess->IsRetired()) pSPI->dwState |= SPIF_RETIRED; if (pprocess->IsPaused()) pSPI->dwState |= SPIF_PAUSED; pSPI->ftCreated = *(pprocess->GetFileTimeCreated()); // UNDONE: server type and identity. Still working on the exact details of this
//pSPI->ServerType =
//if (pSPI->ServerType != SET_SERVICE_
// pSPI->ServerIdent =
// Before we leave the lock, we need to replace the cached struct in the process object
// with the new one; this also clears the dirty bit on the process
pprocess->SetSCMProcessInfo((void*)pSPI); // Lastly, make a new copy to return to the caller
hr = CopySCMProcessInfo(pSPI, ppSPI); gpServerLock->UnlockExclusive(); return hr; }
//+-------------------------------------------------------------------------
//
// Function: FreeSCMProcessInfoPriv
//
// Synopsis: Method that knows how to free a SCMProcessInfo structure,
// including of course its constituent members.
//
// Arguments: ppSCMProcessInfo -- ptr-ptr to the SCMProcessInfo struct
//
// Returns: S_OK - life is good
// E_INVALIDARG -- bad parameter
//
// Note: refer to the header comments for FillInSCMProcessInfo for info
// on the extended layout of a SCMProcessInfo struct.
//
//--------------------------------------------------------------------------
HRESULT CSCMProcessControl::FreeSCMProcessInfoPriv(SCMProcessInfo** ppSCMProcessInfo) { if (!ppSCMProcessInfo) return E_INVALIDARG; if (*ppSCMProcessInfo) { // Decrement the struct ref count; it will not fall to zero until the CProcess*
// object releases its reference, which will not happen unless it is either
// a) rundown; or b) replacing a previous dirty SPI with a new one
LONG lRefs = InterlockedDecrement(SPI_TO_REFCOUNT(*ppSCMProcessInfo)); if (lRefs == 0) { (*SPI_TO_CPROCESS(*ppSCMProcessInfo))->Release(); delete (*ppSCMProcessInfo); } *ppSCMProcessInfo = NULL; } return S_OK; }
//+-------------------------------------------------------------------------
//
// Function: CopySCMProcessInfo
//
// Synopsis: Allocates and fills in a SCMProcessInfo structure for the
// given CProcess server.
//
// Arguments: pSPISrc -- ptr to the SCMProcessInfo struct that is to be copied
// ppSPIDest -- ptrptr to store the copied struct
//
// Returns: S_OK - success
// E_OUTOFMEMORY
//
//--------------------------------------------------------------------------
HRESULT CSCMProcessControl::CopySCMProcessInfo(SCMProcessInfo* pSPISrc, SCMProcessInfo** ppSPIDest) { ASSERT(pSPISrc && ppSPIDest); if (!pSPISrc || !ppSPIDest) return E_INVALIDARG; LONG lNewRefs = InterlockedIncrement(SPI_TO_REFCOUNT(pSPISrc)); *ppSPIDest = pSPISrc; return S_OK; };
//+-------------------------------------------------------------------------
//
// Function: FindAppOrClass
//
// Synopsis: This is a generic helper function used by the FindApplication
// and FindClass methods. The logic is the same for either.
//
// Arguments: rguid -- the appid or clsid to use in the query
// pServerTable - the table to use in the query
// ppESPI -- the place to store the resulting enumerator object
//
// Returns: S_OK - success
// E_OUTOFMEMORY
//
//--------------------------------------------------------------------------
HRESULT CSCMProcessControl::FindAppOrClass(const GUID& rguid, CServerTable* pServerTable, IEnumSCMProcessInfo** ppESPI) { HRESULT hr = S_OK; CSCMProcessEnumerator* pSPEnum = NULL; CServerTableEntry* pSTE = NULL; if (!ppESPI) return E_INVALIDARG; *ppESPI = NULL; pSTE = pServerTable->Lookup((GUID&)rguid); if (!pSTE) { return S_OK; } pSPEnum = new CSCMProcessEnumerator(); if (!pSPEnum) { pSTE->Release(); return E_OUTOFMEMORY; } CServerList* pServerList = pSTE->GetServerListWithSharedLock(); ASSERT(pServerList && "unexpected NULL pServerList"); // For each server that has registered for this appid/clsid, add a
// SCMProcessInfo to the enumerator object
CServerListEntry* pSLE = (CServerListEntry*)pServerList->First(); while (pSLE) { SCMProcessInfo* pSPI; CProcess* pprocess = pSLE->GetProcess(); // not refcounted
ASSERT(pprocess); hr = FillInSCMProcessInfo(pprocess, pSLE->IsReadyForActivations(), &pSPI); if (SUCCEEDED(hr)) { // add it to the enumerator; on success, the enumerator owns it
hr = pSPEnum->AddProcess(pSPI); if (FAILED(hr)) { FreeSCMProcessInfoPriv(&pSPI); // we still own it, so free the memory
break; } } else break; pSLE = (CServerListEntry*) pSLE->Next(); } pSTE->ReleaseSharedListLock(); if (SUCCEEDED(hr)) { hr = pSPEnum->QueryInterface(__uuidof(IEnumSCMProcessInfo), (void**)ppESPI); } pSPEnum->Release(); pSTE->Release(); return hr; }
//+-------------------------------------------------------------------------
//
// Function: InitializeEnumerator
//
// Synopsis: Initializes the aggregated enumerator object for use. Mainly
// this consists of adding SCMProcessInfo's for all known servers
// to the enumerator.
//
// Arguments: none
//
// Returns: S_OK
// E_OUTOFMEMORY
//
//--------------------------------------------------------------------------
HRESULT CSCMProcessControl::InitializeEnumerator() { return E_NOTIMPL; }
// IUnknown implementation for CSCMProcessControl
STDMETHODIMP CSCMProcessControl::QueryInterface(REFIID riid, void** ppv) { HRESULT hr = S_OK; if (!ppv) return E_POINTER; *ppv = NULL; if (riid == IID_IUnknown || riid == IID_ISCMProcessControl) { *ppv = (void*)this; AddRef(); return S_OK; } /*
else if (riid == IID_IEnumSCMProcessInfo) { if (!_bInitializedEnum) { // First time we've been QI'd for this interface; create an
// enumerator object to aggregate over.
hr = InitializeEnumerator(); _bInitializedEnum = TRUE; } if (SUCCEEDED(hr)) { hr = _SPEnum.QueryInterface(riid, ppv); } return hr; } */ return E_NOINTERFACE; }
STDMETHODIMP_(ULONG) CSCMProcessControl::AddRef() { return InterlockedIncrement(&_lRefs); }
STDMETHODIMP_(ULONG) CSCMProcessControl::Release() { LONG lRefs = InterlockedDecrement(&_lRefs); if (lRefs == 0) { delete this; } return lRefs; }
//+-------------------------------------------------------------------------
//
// Implementation of CSCMProcessEnumerator begins here
//
//--------------------------------------------------------------------------
//
// ctor used by the CSCMProcessControl object
//
CSCMProcessEnumerator::CSCMProcessEnumerator() : _lRefs(1), _dwNumSPInfos(0), _dwMaxSPInfos(SPENUM_INITIAL_SIZE), _dwCurSPInfo(0), _ppSPInfos(NULL), _ppSPInfosForReal(_pSPInfosInitial), _pOuterUnk(NULL) { ZeroMemory(_pSPInfosInitial, sizeof(SCMProcessInfo*) * SPENUM_INITIAL_SIZE); }
//
// ctor used by the Clone method to create new copies of an enumerator
//
CSCMProcessEnumerator::CSCMProcessEnumerator(CSCMProcessEnumerator* pCSPEOrig, HRESULT* phrInit) : _lRefs(1), _dwNumSPInfos(0), // this gets adjusted in the loop below
_dwMaxSPInfos(pCSPEOrig->_dwMaxSPInfos), _dwCurSPInfo(pCSPEOrig->_dwCurSPInfo), _pOuterUnk(NULL) { ZeroMemory(_pSPInfosInitial, sizeof(SCMProcessInfo*) * SPENUM_INITIAL_SIZE); if (_dwMaxSPInfos == SPENUM_INITIAL_SIZE) { // The src enumerator did not grown beyond SPENUM_INITIAL_SIZE
_ppSPInfosForReal = _pSPInfosInitial; } else { // The src enumerator did grow, so we need to create an array
// to hold everything
_ppSPInfos = new SCMProcessInfo*[_dwMaxSPInfos]; if (!_ppSPInfos) { *phrInit = E_OUTOFMEMORY; return; } ZeroMemory(_ppSPInfos, sizeof(SCMProcessInfo*) * _dwMaxSPInfos); _ppSPInfosForReal = _ppSPInfos; } // Make copies of each of the original enumerator's SCMProcessInfo structs
DWORD dwNumSPInfosInOriginal = pCSPEOrig->_dwNumSPInfos; for (DWORD i = 0; i < dwNumSPInfosInOriginal; i++) { *phrInit = CSCMProcessControl::CopySCMProcessInfo(pCSPEOrig->_ppSPInfos[i], &(_ppSPInfosForReal[i])); if (FAILED(*phrInit)) return; _dwNumSPInfos++; } }
//
// ctor used when we are aggregated by the CSCMProcessControl object
//
CSCMProcessEnumerator::CSCMProcessEnumerator(CSCMProcessControl* pOuterUnk) : _lRefs(-1), // don't use refcount when we are aggregated
_dwNumSPInfos(0), _dwMaxSPInfos(SPENUM_INITIAL_SIZE), _dwCurSPInfo(0), _ppSPInfosForReal(_pSPInfosInitial), _pOuterUnk(pOuterUnk) // not refcounted!
{ }
//
// dtor
//
CSCMProcessEnumerator::~CSCMProcessEnumerator() { #ifdef DBG
if (_pOuterUnk) ASSERT(_lRefs == -1); else ASSERT(_lRefs == 0); #endif
for (DWORD i = 0; i < _dwNumSPInfos; i++) { CSCMProcessControl::FreeSCMProcessInfoPriv(&(_ppSPInfosForReal[i])); } #ifdef DBG
for (DWORD j = i; j < _dwMaxSPInfos; j++) { ASSERT(_ppSPInfosForReal[j] == NULL); } #endif
if (_ppSPInfos) { ASSERT(_dwMaxSPInfos > SPENUM_INITIAL_SIZE); delete _ppSPInfos; } }
//+-------------------------------------------------------------------------
//
// Function: Next
//
// Synopsis: Returns to the caller the requested # of SCMProcessInfo
// ptrs.
//
// Arguments: cElems -- # of requested structs
// ppSPI -- ptr to an array of size cElems
// pcFetched -- out param containg # of elements actually
// fetched; can be NULL.
//
// Returns: S_OK - the requested # of elements were returned
// S_FALSE -- only some of the requested # of elements were returned
// E_INVALIDARG -- one or more parameters were bogus
//
// Notes: the caller's ppSPI array, on success, will contain ptrs to the
// enumerator's SPI structs. The caller may only use his ptrs while
// he holds a reference on the enumerator.
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessEnumerator::Next(ULONG cElems, SCMProcessInfo** ppSPI, ULONG* pcFetched) { if (!ppSPI) return E_INVALIDARG; ZeroMemory(ppSPI, sizeof(SCMProcessInfo*) * cElems); DWORD dwFetched = 0; for (DWORD i = _dwCurSPInfo; (i < _dwNumSPInfos) && (dwFetched < cElems); i++, dwFetched++) { ppSPI[dwFetched] = _ppSPInfosForReal[i]; } // tell the caller how many he's getting, if he cared
if (pcFetched) *pcFetched = dwFetched; // Advance the cursor
_dwCurSPInfo += dwFetched; return (dwFetched == cElems) ? S_OK : S_FALSE; }
//+-------------------------------------------------------------------------
//
// Function: Skip
//
// Synopsis: Advances the enumerator's "cursor"/ptr by the specified #
// of elements
//
// Arguments: cElems -- the # of elements to advance the cursor by
//
// Returns: S_OK - success
// S_FALSE - there were not a sufficient # of elements to advance
// that many by. The cursor now points to the last element.
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessEnumerator::Skip(ULONG cElems) { _dwCurSPInfo += cElems; if (_dwCurSPInfo > _dwNumSPInfos) { _dwCurSPInfo = _dwNumSPInfos; return S_FALSE; } else return S_OK; }
//+-------------------------------------------------------------------------
//
// Function: Reset
//
// Synopsis: Resets the enumerator "cursor"/ptr to the initial element
//
// Arguments: none
//
// Returns: S_OK
//
STDMETHODIMP CSCMProcessEnumerator::Reset() { _dwCurSPInfo = 0; return S_OK; }
//+-------------------------------------------------------------------------
//
// Function: Clone
//
// Synopsis: Creates a copy of this enumerator and returns it.
//
// Arguments: ppESPI -- out-param for newly created copy
//
// Returns: S_OK - life is good
// E_INVALIDARG - bad input parameter
// E_OUTOFMEMORY
//
//--------------------------------------------------------------------------
STDMETHODIMP CSCMProcessEnumerator::Clone(IEnumSCMProcessInfo **ppESPI) { HRESULT hr = S_OK; if (!ppESPI) return E_INVALIDARG; *ppESPI = NULL; CSCMProcessEnumerator* pNewEnum = new CSCMProcessEnumerator(this, &hr); if (!pNewEnum) return E_OUTOFMEMORY; if (SUCCEEDED(hr)) { hr = pNewEnum->QueryInterface(IID_IEnumSCMProcessInfo, (void**)ppESPI); } pNewEnum->Release(); return hr; }
//+-------------------------------------------------------------------------
//
// Function: AddProcess
//
// Synopsis: Adds the supplied SCMProcessInfo struct to the list managed
// by this enumerator.
//
// Arguments: pSPI -- SCMProcessInfo struct to be added
//
// Returns: S_OK - new struct was successfully added
// E_OUTOFMEMORY
//
// Notes: the list of SCMProcessInfo's managed by this enumerator is
// implemented as a fixed-size array which is grown on demand.
// This enumerator owns freeing the pSPI struct once added.
//
//--------------------------------------------------------------------------
HRESULT CSCMProcessEnumerator::AddProcess(SCMProcessInfo* pSPI) { ASSERT(pSPI); if (!pSPI) return E_INVALIDARG; // Time to grow the array?
if (_dwNumSPInfos == _dwMaxSPInfos) { DWORD dwNewArraySize = _dwMaxSPInfos + SPENUM_GROWTH_SIZEADD; // 10,20,30, etc
SCMProcessInfo** ppSPInfosNew = new SCMProcessInfo*[dwNewArraySize]; if (!ppSPInfosNew) return E_OUTOFMEMORY; // Zero everything out
ZeroMemory(ppSPInfosNew, sizeof(SCMProcessInfo*) * dwNewArraySize); // Copy over the contents of the old array
CopyMemory(ppSPInfosNew, _ppSPInfosForReal, sizeof(SCMProcessInfo*) * _dwMaxSPInfos); #ifdef DBG
// Fill in the old array with a dummy value
FillMemory(_pSPInfosInitial, sizeof(SCMProcessInfo*) * _dwMaxSPInfos, 0xba); #endif
if (_dwMaxSPInfos > SPENUM_INITIAL_SIZE) { // We're growing larger than a previous dynamic array; cleanup
// the old memory
ASSERT(_ppSPInfos); delete _ppSPInfos; } _ppSPInfos = ppSPInfosNew; _ppSPInfosForReal = _ppSPInfos; _dwMaxSPInfos = dwNewArraySize; } // Store the new SCMProcessInfo struct
_ppSPInfosForReal[_dwNumSPInfos] = pSPI; _dwNumSPInfos++; return S_OK; }
// IUnknown implementation for CSCMProcessEnumerator
STDMETHODIMP CSCMProcessEnumerator::QueryInterface(REFIID riid, void** ppv) { if (!ppv) return E_POINTER; if (riid == IID_IUnknown || riid == IID_IEnumSCMProcessInfo) { if (_pOuterUnk && riid == IID_IUnknown) return _pOuterUnk->QueryInterface(riid, ppv); *ppv = (void*)this; AddRef(); return S_OK; } else if (_pOuterUnk) { // Unknown interface, let punkouter take care of it
return _pOuterUnk->QueryInterface(riid, ppv); } return E_NOINTERFACE; }
STDMETHODIMP_(ULONG) CSCMProcessEnumerator::AddRef() { if (_pOuterUnk) return _pOuterUnk->AddRef(); return InterlockedIncrement(&_lRefs); }
STDMETHODIMP_(ULONG) CSCMProcessEnumerator::Release() { if (_pOuterUnk) return _pOuterUnk->Release(); LONG lRefs = InterlockedDecrement(&_lRefs); if (lRefs == 0) { delete this; } return lRefs; }
//+-------------------------------------------------------------------------
//
// Function: FreeSPIFromCProcess
//
// Synopsis: CProcess's don't know about CSCMProcessControl stuff. This is
// helper function which CProcess extern's in order to call
//
//--------------------------------------------------------------------------
HRESULT FreeSPIFromCProcess(void** ppSCMProcessInfo) { return CSCMProcessControl::FreeSCMProcessInfoPriv((SCMProcessInfo**)ppSCMProcessInfo); }
//+-------------------------------------------------------------------------
//
// Function: PrivGetRPCSSInfo
//
// Synopsis: Activators that call GetRPCSSInfo (exported from rpcss.dll)
// end up in this function; they call here in order to get an
// interface on which they can query & adjust the scm activation state.
//
// History: 05-Sep-99 JSimmons Created
//
//--------------------------------------------------------------------------
HRESULT PrivGetRPCSSInfo(REFCLSID rclsid, REFIID riid, void** ppv) { HRESULT hr = E_INVALIDARG; if (!ppv) return E_POINTER;
if (rclsid == CLSID_RPCSSInfo) { CSCMProcessControl* pSPC = NULL; pSPC = new CSCMProcessControl(); if (pSPC) { hr = pSPC->QueryInterface(riid, ppv); if (FAILED(hr)) delete pSPC; } else { hr = E_OUTOFMEMORY; } }
return hr; };
|