|
//#define BUG2 // Undefine to fix BUG2
#include "stdafx.h"
#include <stdexcept>
#include <tlhelp32.h>
#include "resource.h"
#include "Tools\Exception.h"
#include "ProcessList.h"
#include "VirtualMemory.h"
#include "HeapMemory.h"
#include "atlcom2.h"
CProcessList::CProcessList()
{
}
// CProcessList
HRESULT CProcessList::FinalConstruct()
{
return S_OK;
}
void CProcessList::FinalRelease()
{
}
STDMETHODIMP CProcessList::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_IProcessList
};
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
int CProcessList::Filter(unsigned int code, struct _EXCEPTION_POINTERS *ep)
{
if (code == EXCEPTION_ACCESS_VIOLATION)
{
return EXCEPTION_EXECUTE_HANDLER;
} else
{
return EXCEPTION_CONTINUE_SEARCH;
};
}
bool CProcessList::DoUpdate()
{
// Make sure this happens thread-safe
Windows::AutoCriticalSection lock(m_lock);
#ifdef DEBUG
if (m_listOfProcesses.size() > 0)
{
ULONG m = m_listOfProcesses[0]->AddRef();
ULONG n = m_listOfProcesses[0]->Release();
}
#endif
bool ok = false;
HANDLE snapShot = INVALID_HANDLE_VALUE;
// Need to use __try __except on ToolHelp API.
// If a process is being destroyed (shutdown), the API crashes (AV on NULL pointer)
// Can use try catch if /EHa compiler settings is used
// __try
try
{
snapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0);
if (snapShot != INVALID_HANDLE_VALUE)
{
// Clear previous list
m_listOfProcesses.clear();
// Build new list
PROCESSENTRY32 processEntry;
processEntry.dwSize = sizeof(PROCESSENTRY32);
BOOL ret = Process32First(snapShot, &processEntry);
while (ret == TRUE)
{
VirtualMemory virtualMemory(
#if defined(UNDER_CE)
processEntry.th32ProcessID, processEntry.th32MemoryBase
#else
processEntry.th32ProcessID, 0
#endif
);
HeapMemory heapMemory(processEntry.th32ProcessID);
// We construct our own Process object
CComObjectNoLock<CProcess>* processItem = new CComObjectNoLock<CProcess>();
processItem->Init(_bstr_t(processEntry.szExeFile),
processEntry.th32ProcessID,
processEntry.cntThreads,
#if defined(UNDER_CE)
processEntry.th32MemoryBase,
#else
0,
#endif
heapMemory.GetHeapMemory(),
virtualMemory.GetTotalMemory(),
virtualMemory.GetCommittedMemory(),
virtualMemory.GetReservedMemory(),
0);
m_listOfProcesses.insert(m_listOfProcesses.end(), IProcessPtr(processItem));
ret = Process32Next(snapShot, &processEntry);
}
#if defined(UNDER_CE)
CloseToolhelp32Snapshot(snapShot);
#endif
} else
{
DWORD err = GetLastError();
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
0, // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL);
lpMsgBuf = lpMsgBuf;
}
ok = true;
// } __except ( Filter(GetExceptionCode(), GetExceptionInformation()) )
} catch (...)
{
ok = false;
if (snapShot != INVALID_HANDLE_VALUE)
{
#if defined(UNDER_CE)
CloseToolhelp32Snapshot(snapShot);
#endif
}
}
#ifdef DEBUG
if (m_listOfProcesses.size() > 0)
{
ULONG m = m_listOfProcesses[0]->AddRef();
ULONG n = m_listOfProcesses[0]->Release();
}
#endif
return ok;
}
STDMETHODIMP CProcessList::Update(/*[out, retval]*/ VARIANT_BOOL *value)
{
// Make sure this happens thread-safe
Windows::AutoCriticalSection lock(m_lock);
bool ret = DoUpdate();
*value = (ret == true) ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
STDMETHODIMP CProcessList::get_Count(/*[out, retval]*/ LONG *value)
{
// Make sure this happens thread-safe
Windows::AutoCriticalSection lock(m_lock);
*value = m_listOfProcesses.size();
return S_OK;
}
STDMETHODIMP CProcessList::get__NewEnum(/*[out, retval]*/ IUnknown** retval)
{
HRESULT hr = S_OK;
VARIANT *processes = NULL;
if (retval == NULL)
return E_POINTER;
// Init in case we bail out prematurely
*retval = NULL;
// Make sure this happens thread-safe
Windows::AutoCriticalSection lock(m_lock);
// Make temporary variant vector needed to initialize the IEnumVARIANT
size_t size = m_listOfProcesses.size();
processes = new VARIANT[size];
for (size_t i = 0; i < size; i++)
{
IProcess *process = m_listOfProcesses[i];
::VariantInit(&processes[i]);
hr = process->QueryInterface (IID_IDispatch, reinterpret_cast<void**>(&processes[i].pdispVal));
if (FAILED(hr))
{
size = 0;
break; // We interrupt and return an empty EnumVariant
}
processes[i].vt = VT_DISPATCH;
process->Release();
}
// Assign it to a IEnumVARIANT COM object
#if defined(BUG2)
typedef CComObject< CComEnum< IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _Copy<VARIANT> > > t_ComEnumVariant;
#else
typedef CComObject< CComEnum2< IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _Copy<VARIANT> > > t_ComEnumVariant;
#endif
t_ComEnumVariant *enumVariant = new t_ComEnumVariant;
hr = enumVariant->Init (&processes[0], &processes[size], NULL, AtlFlagCopy); // Init will do a VariantCopy(), hence AddRef()
delete [] processes;
if (SUCCEEDED (hr))
hr = enumVariant->QueryInterface (IID_IEnumVARIANT, reinterpret_cast<void**>(retval));
if (FAILED (hr))
delete enumVariant;
return hr;
}
STDMETHODIMP CProcessList::Item (/*[in]*/ VARIANT index, /*[out, retval]*/ IProcess **retval)
{
IProcess *process = NULL;
HRESULT hr = S_OK;
_variant_t vtLong;
if (::VariantChangeType (&vtLong, &index, 0, VT_I4) == S_OK)
{
// Make sure this happens thread-safe
Windows::AutoCriticalSection lock(m_lock);
size_t i = vtLong.lVal; // 0-based index.
if ((i >= 0) && (i < m_listOfProcesses.size ()))
{
process = m_listOfProcesses[i];
hr = process->AddRef ();
if (FAILED (hr))
{
process = NULL; // Do not trust process.
return hr;
}
}
}
// Check if we have a hit
if (process == NULL)
{
Tools::Exception exception(CLSID_Process, IDS_ITEM_NOT_FOUND);
return exception.GetException();
}
*retval = process;
return S_OK;
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.