1302 lines
36 KiB
C++
1302 lines
36 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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_) && !defined(_CHICAGO_)
|
|
#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;
|
|
|
|
// 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)
|
|
{
|
|
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;
|
|
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;
|
|
|
|
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;
|
|
};
|