stitch2802
asked on
Background processes enumeration displays only one process - help
Hello,
This method only displays one process name as follows:
[System]
What I want is to see all the processes displayed along with the user id (i.e., [System] Apache.exe and so on). I've run it through the debugger and tried stepping through the method, but to no avail - I can't figure out what could be causing the bug.
Here's my code:
========================== ========== ========== ========== ========== ========== =====
//ProcessInfo.h
#pragma once
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <vdmdbg.h>
#include <ios>
#include <iostream>
#include <limits>
#include "Common.h"
#include "IAcquire.h"
#include <vector>
typedef BOOL (CALLBACK *PROCENUMPROC)(DWORD, WORD, LPSTR, LPARAM);
typedef struct {
DWORD dwPID;
PROCENUMPROC lpProc;
DWORD lParam;
BOOL bEnd;
TCHAR UserName[256];
TCHAR Domain[256];
TCHAR ProcessName[256];
} ProcessInfoEx;
class ProcessInfo : public IAcquire
{
public:
bool Acquire();
ProcessInfoEx &Process(size_t idx);
size_t ProcessInfo::ProcessCount( );
typedef std::vector<ProcessInfoEx> Processes;
private:
Processes processes;
};
========================== ========== ========== ========== ========== ========== =====
//ProcessInfo.cpp
#include "ProcessInfo.h"
BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam);
BOOL GetCurrentUserAndDomain(LP TSTR szUser, PDWORD pcchUser, LPTSTR szDomain, PDWORD pcchDomain, DWORD dwPID);
BOOL WINAPI Enum16(DWORD dwThreadId, WORD HMod16, WORD hTask16, PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined);
BOOL CALLBACK ProcessEnumerator(DWORD dwPID, WORD wTask, LPCSTR szProcess, LPARAM lParam);
bool ProcessInfo::Acquire()
{
return EnumProcs((PROCENUMPROC)Pr ocessEnume rator, reinterpret_cast<LPARAM>(& processes) ) ? true : false;
}
//
// The EnumProcs function takes a pointer to a callback function that
// will be called once per process with the process filename and
// the process id.
// lpProc - address of the callback routine
// lParam - a user-defined LPARAM value to be passed to the callback routine.
// Callback function definition:
// BOOL CALLBACK Proc ( DWORD dw, WORD w, LPCTSTR lpstr, LPARAM lParam);
BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam)
{
OSVERSIONINFO osver;
HINSTANCE hInstLib = NULL;
HINSTANCE hInstLib2 = NULL;
HANDLE hSnapShot = NULL;
LPDWORD lpdwPIDs = NULL;
PROCESSENTRY32 procentry;
BOOL bFlag;
DWORD dwSize;
DWORD dwSize2;
DWORD dwIndex;
HMODULE hMod;
HANDLE hProcess;
char szFileName[MAX_PATH];
// ProcessInfoEx sProcess;
//the container for processes
ProcessInfo::Processes *process = reinterpret_cast<ProcessIn fo::Proces ses *>(lParam);
// ToolHelp Function pointers
HANDLE( WINAPI *lpfCreateToolhelp32Snapsh ot ) (DWORD, DWORD);
BOOL ( WINAPI *lpfProcess32First )( HANDLE, LPPROCESSENTRY32 );
BOOL ( WINAPI *lpfProcess32Next ) ( HANDLE, LPPROCESSENTRY32 );
//PSAPI Function Pointers
BOOL ( WINAPI *lpfEnumProcesses ) (DWORD *, DWORD, DWORD * );
BOOL ( WINAPI *lpfEnumProcessModules ) (HANDLE, HMODULE *, DWORD, LPDWORD );
DWORD ( WINAPI *lpfGetModuleBaseName ) (HANDLE, HMODULE, LPTSTR, DWORD );
//VDMDBG Function Pointers
INT ( WINAPI *lpfVDMEnumTaskWOWEx) (DWORD, TASKENUMPROCEX, LPARAM);
//Retrieve the OS version
osver.dwOSVersionInfoSize = sizeof(osver);
if(!GetVersionEx(&osver)) return FALSE;
//if Windows NT 4.0
if(osver.dwPlatformId == VER_PLATFORM_WIN32_NT && osver.dwMajorVersion == 4)
{
__try {
//Get the procedure address explicitly.
//We do this so that we don't have to worry about modules
//failing to load under OSes other than Windows NT 4.0
//because references to PSAPI.dll can't be resolved.
hInstLib = LoadLibraryA("PSAPI.DLL");
if(hInstLib == NULL)
__leave;
hInstLib2 = LoadLibrary("VDMDBG.DLL");
if(hInstLib2 == NULL)
__leave;
//Get procedure addresses.
lpfEnumProcesses = (BOOL (WINAPI *) (DWORD *, DWORD, DWORD*))
GetProcAddress(hInstLib, "EnumProcesses");
lpfEnumProcessModules = (BOOL (WINAPI *) (HANDLE, HMODULE *, DWORD, LPDWORD))
GetProcAddress(hInstLib, "EnumProcessModules");
lpfGetModuleBaseName = (DWORD (WINAPI *) (HANDLE, HMODULE, LPTSTR, DWORD))
GetProcAddress (hInstLib, "GetModuleBaseNameA");
lpfVDMEnumTaskWOWEx = (INT (WINAPI*) (DWORD, TASKENUMPROCEX, LPARAM))
GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
if(lpfEnumProcesses == NULL
|| lpfEnumProcessModules == NULL
|| lpfGetModuleBaseName == NULL
|| lpfVDMEnumTaskWOWEx == NULL)
__leave;
//
// Call the PSAPI function EnumProcesses to get all of the
// ProcIDs currently in the system.
// In the documentation, the third parameter of EnumProcesses
// is named cbNeeded, which implies that you can call
// the function once to find out how much space to
// allocate for the buffer and again to fill the buffer.
// This isn't true: the cbNeeded parameter returns the
// number of PIDs returned, so if your buffer size is
// zero cbNeeded returns zero.
//
// The "HeapAlloc" loop here ensures that we actually
// allocate a buffer large enough for all the PIDS in the system.
dwSize2 = 256 * sizeof(DWORD);
do {
if(lpdwPIDs){
HeapFree(GetProcessHeap(), 0, lpdwPIDs);
dwSize *= 2;
}
lpdwPIDs = (LPDWORD)HeapAlloc(GetProc essHeap(), 0, dwSize2);
if (lpdwPIDs == NULL)
__leave;
if(!lpfEnumProcesses(lpdwP IDs, dwSize2, &dwSize))
__leave;
}while (dwSize == dwSize2);
//How many ProcIds did we get?
dwSize /= sizeof(DWORD);
//Loop through each ProcID
for(dwIndex = 0; dwIndex < dwSize; dwIndex++)
{
szFileName[0] = 0;
// Open the process (if we can... security does not
// permit every process in the system to be opened).
hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, lpdwPIDs[dwIndex]);
if (hProcess != NULL) {
// Here we call EnumProcessModules to get only the
// first module in the process. This will be the
// EXE module for which we will retrieve the name.
if (lpfEnumProcessModules(hPr ocess, &hMod,
sizeof(hMod), &dwSize2)) {
// Get the module name
if (!lpfGetModuleBaseName(hPr ocess, hMod,
szFileName, sizeof(szFileName)))
szFileName[0] = 0;
}
CloseHandle(hProcess);
}
// Regardless of OpenProcess success or failure, we
// still call the enum func with the ProcID.
if (!lpProc(lpdwPIDs[dwIndex] , 0, szFileName, lParam))
break;
// Did we just bump into an NTVDM?
if (_stricmp(szFileName, "NTVDM.EXE") == 0) {
ProcessInfoEx proc;
// Fill in some info for the 16-bit enum proc.
proc.dwPID = lpdwPIDs[dwIndex];
proc.lpProc = lpProc;
proc.lParam = (DWORD) lParam;
proc.bEnd = FALSE;
// Enum the 16-bit stuff.
lpfVDMEnumTaskWOWEx(lpdwPI Ds[dwIndex ],
(TASKENUMPROCEX) Enum16, (LPARAM) &proc);
// Did our main enum func say quit?
if (proc.bEnd)
break;
process->push_back(proc);
}
}
} __finally {
if (hInstLib)
FreeLibrary(hInstLib);
if (hInstLib2)
FreeLibrary(hInstLib2);
if (lpdwPIDs)
HeapFree(GetProcessHeap(), 0, lpdwPIDs);
}
// If any OS other than Windows NT 4.0.
} else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
|| (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
&& osver.dwMajorVersion > 4)) {
__try {
hInstLib = LoadLibraryA("Kernel32.DLL ");
if (hInstLib == NULL)
__leave;
// If NT-based OS, load VDMDBG.DLL.
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
hInstLib2 = LoadLibraryA("VDMDBG.DLL") ;
if (hInstLib2 == NULL)
__leave;
}
// Get procedure addresses. We are linking to
// these functions explicitly, because a module using
// this code would fail to load under Windows NT,
// which does not have the Toolhelp32
// functions in KERNEL32.DLL.
lpfCreateToolhelp32Snapsho t =
(HANDLE (WINAPI *)(DWORD,DWORD))
GetProcAddress(hInstLib, "CreateToolhelp32Snapshot" );
lpfProcess32First =
(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32 ))
GetProcAddress(hInstLib, "Process32First");
lpfProcess32Next =
(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32 ))
GetProcAddress(hInstLib, "Process32Next");
if (lpfProcess32Next == NULL
|| lpfProcess32First == NULL
|| lpfCreateToolhelp32Snapsho t == NULL)
__leave;
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX,
LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
if (lpfVDMEnumTaskWOWEx == NULL)
__leave;
}
// Get a handle to a Toolhelp snapshot of all processes.
hSnapShot = lpfCreateToolhelp32Snapsho t(TH32CS_S NAPPROCESS , 0);
if (hSnapShot == INVALID_HANDLE_VALUE) {
FreeLibrary(hInstLib);
return FALSE;
}
// Get the first process' information.
procentry.dwSize = sizeof(PROCESSENTRY32);
bFlag = lpfProcess32First(hSnapSho t, &procentry);
// While there are processes, keep looping.
while (bFlag) {
ProcessInfoEx sProcess;
// Call the enum func with the filename and ProcID.
if (lpProc(procentry.th32Proc essID, 0,
procentry.szExeFile, reinterpret_cast<LPARAM>(& sProcess)) ) {
// Did we just bump into an NTVDM?
if (_stricmp(procentry.szExeF ile, "NTVDM.EXE") == 0) {
ProcessInfoEx sProcess;
// Fill in some info for the 16-bit enum proc.
sProcess.dwPID = procentry.th32ProcessID;
sProcess.lpProc = lpProc;
sProcess.lParam = (DWORD) lParam;
sProcess.bEnd = FALSE;
// Enum the 16-bit stuff.
lpfVDMEnumTaskWOWEx(procen try.th32Pr ocessID,
(TASKENUMPROCEX) Enum16, (LPARAM) &sProcess);
// Did our main enum func say quit?
if (sProcess.bEnd)
break;
process->push_back(sProces s);
}
procentry.dwSize = sizeof(PROCESSENTRY32);
bFlag = lpfProcess32Next(hSnapShot , &procentry);
process->push_back(sProces s);
} else
bFlag = FALSE;
}
} __finally {
if (hInstLib)
FreeLibrary(hInstLib);
if (hInstLib2)
FreeLibrary(hInstLib2);
}
} else
return FALSE;
// Free the library.
FreeLibrary(hInstLib);
return TRUE;
}
BOOL WINAPI Enum16(DWORD dwThreadId, WORD hMod16,
WORD hTask16,PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined)
{
BOOL bRet;
ProcessInfoEx *psInfo = (ProcessInfoEx *)lpUserDefined;
bRet = psInfo->lpProc(psInfo->dwP ID, hTask16, pszFileName,psInfo->lParam );
if (!bRet)
psInfo->bEnd = TRUE;
return !bRet;
}
BOOL CALLBACK ProcessEnumerator(DWORD dwPID, WORD wTask, LPCSTR szProcess, LPARAM lParam)
{
ProcessInfoEx &process = *(reinterpret_cast<Process InfoEx *>(lParam));
TCHAR userName[256]= {0};
TCHAR domainName[256]= {0};
DWORD userLen = sizeof(userName)/sizeof(us erName[0]) ;
DWORD domainLen = sizeof(domainName)/sizeof( domainName [0]);
if (wTask == 0){
if(GetCurrentUserAndDomain (userName, &userLen, domainName, &domainLen, dwPID))
{
HRESULT hr = StringCchCopy(process.User Name, sizeof(process.UserName), userName);
if (FAILED(hr))
{
return false;
}
hr = StringCchCopy(process.Doma in, domainLen, domainName);
if (FAILED(hr))
{
return false;
}
hr = StringCchCopy(process.Proc essName, sizeof(szProcess), szProcess);
if (FAILED(hr))
{
return false;
}
}
else
{
HRESULT hr = StringCchCopy(process.Proc essName,si zeof(proce ss.Process Name), szProcess);
if (FAILED(hr))
{
return false;
}
}
}
else { //if GetCurrentUserAndDomain == false
HRESULT hr = StringCchCopy(process.Proc essName, sizeof(szProcess), szProcess);
if (FAILED(hr))
{
return false;
}
//printf(" %5u %s\n", wTask, szProcess);}
}
return TRUE;
}
BOOL GetCurrentUserAndDomain(PT STR szUser, PDWORD pcchUser, PTSTR szDomain, PDWORD pcchDomain, DWORD dwPID)
{
BOOL fSuccess = FALSE;
HANDLE hToken = NULL;
HANDLE hProcess = NULL;
PTOKEN_USER ptiUser = NULL;
DWORD cbti = 0;
SID_NAME_USE snu;
__try {
// Get the process handle
hProcess = OpenProcess ( PROCESS_QUERY_INFORMATION, FALSE, dwPID);
if (!hProcess)
__leave;
if (!OpenProcessToken(hProces s, TOKEN_QUERY, &hToken))
__leave;
// Obtain the size of the user information in the token.
if (GetTokenInformation(hToke n, TokenUser, NULL, 0, &cbti)) {
// Call should have failed due to zero-length buffer.
__leave;
} else {
// Call should have failed due to zero-length buffer.
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
__leave;
}
// Allocate buffer for user information in the token.
ptiUser = (PTOKEN_USER) HeapAlloc(GetProcessHeap() , 0, cbti);
if (!ptiUser)
__leave;
// Retrieve the user information from the token.
if (!GetTokenInformation(hTok en, TokenUser, ptiUser, cbti, &cbti))
__leave;
// Retrieve user name and domain name based on user's SID.
if (!LookupAccountSid(NULL, ptiUser->User.Sid, szUser, pcchUser,
szDomain, pcchDomain, &snu))
__leave;
fSuccess = TRUE;
}
__finally {
// Free resources.
if (hToken)
CloseHandle(hToken);
if (ptiUser)
HeapFree(GetProcessHeap(), 0, ptiUser);
}
return fSuccess;
}
size_t ProcessInfo::ProcessCount( )
{
return processes.size();
}
ProcessInfoEx& ProcessInfo::Process( size_t index )
{
if( index < processes.size() )
{
return processes.at(index);
}
return processes.back();
}
All suggestions are welcome - please help!
TIA,
S/.
This method only displays one process name as follows:
[System]
What I want is to see all the processes displayed along with the user id (i.e., [System] Apache.exe and so on). I've run it through the debugger and tried stepping through the method, but to no avail - I can't figure out what could be causing the bug.
Here's my code:
==========================
//ProcessInfo.h
#pragma once
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <vdmdbg.h>
#include <ios>
#include <iostream>
#include <limits>
#include "Common.h"
#include "IAcquire.h"
#include <vector>
typedef BOOL (CALLBACK *PROCENUMPROC)(DWORD, WORD, LPSTR, LPARAM);
typedef struct {
DWORD dwPID;
PROCENUMPROC lpProc;
DWORD lParam;
BOOL bEnd;
TCHAR UserName[256];
TCHAR Domain[256];
TCHAR ProcessName[256];
} ProcessInfoEx;
class ProcessInfo : public IAcquire
{
public:
bool Acquire();
ProcessInfoEx &Process(size_t idx);
size_t ProcessInfo::ProcessCount(
typedef std::vector<ProcessInfoEx>
private:
Processes processes;
};
==========================
//ProcessInfo.cpp
#include "ProcessInfo.h"
BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam);
BOOL GetCurrentUserAndDomain(LP
BOOL WINAPI Enum16(DWORD dwThreadId, WORD HMod16, WORD hTask16, PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined);
BOOL CALLBACK ProcessEnumerator(DWORD dwPID, WORD wTask, LPCSTR szProcess, LPARAM lParam);
bool ProcessInfo::Acquire()
{
return EnumProcs((PROCENUMPROC)Pr
}
//
// The EnumProcs function takes a pointer to a callback function that
// will be called once per process with the process filename and
// the process id.
// lpProc - address of the callback routine
// lParam - a user-defined LPARAM value to be passed to the callback routine.
// Callback function definition:
// BOOL CALLBACK Proc ( DWORD dw, WORD w, LPCTSTR lpstr, LPARAM lParam);
BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam)
{
OSVERSIONINFO osver;
HINSTANCE hInstLib = NULL;
HINSTANCE hInstLib2 = NULL;
HANDLE hSnapShot = NULL;
LPDWORD lpdwPIDs = NULL;
PROCESSENTRY32 procentry;
BOOL bFlag;
DWORD dwSize;
DWORD dwSize2;
DWORD dwIndex;
HMODULE hMod;
HANDLE hProcess;
char szFileName[MAX_PATH];
// ProcessInfoEx sProcess;
//the container for processes
ProcessInfo::Processes *process = reinterpret_cast<ProcessIn
// ToolHelp Function pointers
HANDLE( WINAPI *lpfCreateToolhelp32Snapsh
BOOL ( WINAPI *lpfProcess32First )( HANDLE, LPPROCESSENTRY32 );
BOOL ( WINAPI *lpfProcess32Next ) ( HANDLE, LPPROCESSENTRY32 );
//PSAPI Function Pointers
BOOL ( WINAPI *lpfEnumProcesses ) (DWORD *, DWORD, DWORD * );
BOOL ( WINAPI *lpfEnumProcessModules ) (HANDLE, HMODULE *, DWORD, LPDWORD );
DWORD ( WINAPI *lpfGetModuleBaseName ) (HANDLE, HMODULE, LPTSTR, DWORD );
//VDMDBG Function Pointers
INT ( WINAPI *lpfVDMEnumTaskWOWEx) (DWORD, TASKENUMPROCEX, LPARAM);
//Retrieve the OS version
osver.dwOSVersionInfoSize = sizeof(osver);
if(!GetVersionEx(&osver)) return FALSE;
//if Windows NT 4.0
if(osver.dwPlatformId == VER_PLATFORM_WIN32_NT && osver.dwMajorVersion == 4)
{
__try {
//Get the procedure address explicitly.
//We do this so that we don't have to worry about modules
//failing to load under OSes other than Windows NT 4.0
//because references to PSAPI.dll can't be resolved.
hInstLib = LoadLibraryA("PSAPI.DLL");
if(hInstLib == NULL)
__leave;
hInstLib2 = LoadLibrary("VDMDBG.DLL");
if(hInstLib2 == NULL)
__leave;
//Get procedure addresses.
lpfEnumProcesses = (BOOL (WINAPI *) (DWORD *, DWORD, DWORD*))
GetProcAddress(hInstLib, "EnumProcesses");
lpfEnumProcessModules = (BOOL (WINAPI *) (HANDLE, HMODULE *, DWORD, LPDWORD))
GetProcAddress(hInstLib, "EnumProcessModules");
lpfGetModuleBaseName = (DWORD (WINAPI *) (HANDLE, HMODULE, LPTSTR, DWORD))
GetProcAddress (hInstLib, "GetModuleBaseNameA");
lpfVDMEnumTaskWOWEx = (INT (WINAPI*) (DWORD, TASKENUMPROCEX, LPARAM))
GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
if(lpfEnumProcesses == NULL
|| lpfEnumProcessModules == NULL
|| lpfGetModuleBaseName == NULL
|| lpfVDMEnumTaskWOWEx == NULL)
__leave;
//
// Call the PSAPI function EnumProcesses to get all of the
// ProcIDs currently in the system.
// In the documentation, the third parameter of EnumProcesses
// is named cbNeeded, which implies that you can call
// the function once to find out how much space to
// allocate for the buffer and again to fill the buffer.
// This isn't true: the cbNeeded parameter returns the
// number of PIDs returned, so if your buffer size is
// zero cbNeeded returns zero.
//
// The "HeapAlloc" loop here ensures that we actually
// allocate a buffer large enough for all the PIDS in the system.
dwSize2 = 256 * sizeof(DWORD);
do {
if(lpdwPIDs){
HeapFree(GetProcessHeap(),
dwSize *= 2;
}
lpdwPIDs = (LPDWORD)HeapAlloc(GetProc
if (lpdwPIDs == NULL)
__leave;
if(!lpfEnumProcesses(lpdwP
__leave;
}while (dwSize == dwSize2);
//How many ProcIds did we get?
dwSize /= sizeof(DWORD);
//Loop through each ProcID
for(dwIndex = 0; dwIndex < dwSize; dwIndex++)
{
szFileName[0] = 0;
// Open the process (if we can... security does not
// permit every process in the system to be opened).
hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, lpdwPIDs[dwIndex]);
if (hProcess != NULL) {
// Here we call EnumProcessModules to get only the
// first module in the process. This will be the
// EXE module for which we will retrieve the name.
if (lpfEnumProcessModules(hPr
sizeof(hMod), &dwSize2)) {
// Get the module name
if (!lpfGetModuleBaseName(hPr
szFileName, sizeof(szFileName)))
szFileName[0] = 0;
}
CloseHandle(hProcess);
}
// Regardless of OpenProcess success or failure, we
// still call the enum func with the ProcID.
if (!lpProc(lpdwPIDs[dwIndex]
break;
// Did we just bump into an NTVDM?
if (_stricmp(szFileName, "NTVDM.EXE") == 0) {
ProcessInfoEx proc;
// Fill in some info for the 16-bit enum proc.
proc.dwPID = lpdwPIDs[dwIndex];
proc.lpProc = lpProc;
proc.lParam = (DWORD) lParam;
proc.bEnd = FALSE;
// Enum the 16-bit stuff.
lpfVDMEnumTaskWOWEx(lpdwPI
(TASKENUMPROCEX) Enum16, (LPARAM) &proc);
// Did our main enum func say quit?
if (proc.bEnd)
break;
process->push_back(proc);
}
}
} __finally {
if (hInstLib)
FreeLibrary(hInstLib);
if (hInstLib2)
FreeLibrary(hInstLib2);
if (lpdwPIDs)
HeapFree(GetProcessHeap(),
}
// If any OS other than Windows NT 4.0.
} else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
|| (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
&& osver.dwMajorVersion > 4)) {
__try {
hInstLib = LoadLibraryA("Kernel32.DLL
if (hInstLib == NULL)
__leave;
// If NT-based OS, load VDMDBG.DLL.
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
hInstLib2 = LoadLibraryA("VDMDBG.DLL")
if (hInstLib2 == NULL)
__leave;
}
// Get procedure addresses. We are linking to
// these functions explicitly, because a module using
// this code would fail to load under Windows NT,
// which does not have the Toolhelp32
// functions in KERNEL32.DLL.
lpfCreateToolhelp32Snapsho
(HANDLE (WINAPI *)(DWORD,DWORD))
GetProcAddress(hInstLib, "CreateToolhelp32Snapshot"
lpfProcess32First =
(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32
GetProcAddress(hInstLib, "Process32First");
lpfProcess32Next =
(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32
GetProcAddress(hInstLib, "Process32Next");
if (lpfProcess32Next == NULL
|| lpfProcess32First == NULL
|| lpfCreateToolhelp32Snapsho
__leave;
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX,
LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
if (lpfVDMEnumTaskWOWEx == NULL)
__leave;
}
// Get a handle to a Toolhelp snapshot of all processes.
hSnapShot = lpfCreateToolhelp32Snapsho
if (hSnapShot == INVALID_HANDLE_VALUE) {
FreeLibrary(hInstLib);
return FALSE;
}
// Get the first process' information.
procentry.dwSize = sizeof(PROCESSENTRY32);
bFlag = lpfProcess32First(hSnapSho
// While there are processes, keep looping.
while (bFlag) {
ProcessInfoEx sProcess;
// Call the enum func with the filename and ProcID.
if (lpProc(procentry.th32Proc
procentry.szExeFile, reinterpret_cast<LPARAM>(&
// Did we just bump into an NTVDM?
if (_stricmp(procentry.szExeF
ProcessInfoEx sProcess;
// Fill in some info for the 16-bit enum proc.
sProcess.dwPID = procentry.th32ProcessID;
sProcess.lpProc = lpProc;
sProcess.lParam = (DWORD) lParam;
sProcess.bEnd = FALSE;
// Enum the 16-bit stuff.
lpfVDMEnumTaskWOWEx(procen
(TASKENUMPROCEX) Enum16, (LPARAM) &sProcess);
// Did our main enum func say quit?
if (sProcess.bEnd)
break;
process->push_back(sProces
}
procentry.dwSize = sizeof(PROCESSENTRY32);
bFlag = lpfProcess32Next(hSnapShot
process->push_back(sProces
} else
bFlag = FALSE;
}
} __finally {
if (hInstLib)
FreeLibrary(hInstLib);
if (hInstLib2)
FreeLibrary(hInstLib2);
}
} else
return FALSE;
// Free the library.
FreeLibrary(hInstLib);
return TRUE;
}
BOOL WINAPI Enum16(DWORD dwThreadId, WORD hMod16,
WORD hTask16,PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined)
{
BOOL bRet;
ProcessInfoEx *psInfo = (ProcessInfoEx *)lpUserDefined;
bRet = psInfo->lpProc(psInfo->dwP
if (!bRet)
psInfo->bEnd = TRUE;
return !bRet;
}
BOOL CALLBACK ProcessEnumerator(DWORD dwPID, WORD wTask, LPCSTR szProcess, LPARAM lParam)
{
ProcessInfoEx &process = *(reinterpret_cast<Process
TCHAR userName[256]= {0};
TCHAR domainName[256]= {0};
DWORD userLen = sizeof(userName)/sizeof(us
DWORD domainLen = sizeof(domainName)/sizeof(
if (wTask == 0){
if(GetCurrentUserAndDomain
{
HRESULT hr = StringCchCopy(process.User
if (FAILED(hr))
{
return false;
}
hr = StringCchCopy(process.Doma
if (FAILED(hr))
{
return false;
}
hr = StringCchCopy(process.Proc
if (FAILED(hr))
{
return false;
}
}
else
{
HRESULT hr = StringCchCopy(process.Proc
if (FAILED(hr))
{
return false;
}
}
}
else { //if GetCurrentUserAndDomain == false
HRESULT hr = StringCchCopy(process.Proc
if (FAILED(hr))
{
return false;
}
//printf(" %5u %s\n", wTask, szProcess);}
}
return TRUE;
}
BOOL GetCurrentUserAndDomain(PT
{
BOOL fSuccess = FALSE;
HANDLE hToken = NULL;
HANDLE hProcess = NULL;
PTOKEN_USER ptiUser = NULL;
DWORD cbti = 0;
SID_NAME_USE snu;
__try {
// Get the process handle
hProcess = OpenProcess ( PROCESS_QUERY_INFORMATION,
if (!hProcess)
__leave;
if (!OpenProcessToken(hProces
__leave;
// Obtain the size of the user information in the token.
if (GetTokenInformation(hToke
// Call should have failed due to zero-length buffer.
__leave;
} else {
// Call should have failed due to zero-length buffer.
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
__leave;
}
// Allocate buffer for user information in the token.
ptiUser = (PTOKEN_USER) HeapAlloc(GetProcessHeap()
if (!ptiUser)
__leave;
// Retrieve the user information from the token.
if (!GetTokenInformation(hTok
__leave;
// Retrieve user name and domain name based on user's SID.
if (!LookupAccountSid(NULL, ptiUser->User.Sid, szUser, pcchUser,
szDomain, pcchDomain, &snu))
__leave;
fSuccess = TRUE;
}
__finally {
// Free resources.
if (hToken)
CloseHandle(hToken);
if (ptiUser)
HeapFree(GetProcessHeap(),
}
return fSuccess;
}
size_t ProcessInfo::ProcessCount(
{
return processes.size();
}
ProcessInfoEx& ProcessInfo::Process( size_t index )
{
if( index < processes.size() )
{
return processes.at(index);
}
return processes.back();
}
All suggestions are welcome - please help!
TIA,
S/.
ASKER
Thanks jkr, but the braces match up (sorry about my misleading comment), so that doesn't seem to be causing the issue.
Here's my resulting XML output:
<Snapshot_of_Running_Proce sses>
<Process>
<Module>[System Process]</Module>
<User>¤Þ</User>
<Domain>Tß</Domain>
</Process>
<Process>
<Module>System</Module>
<User>¤Þ</User>
<Domain>Tß</Domain>
</Process>
</Snapshot_of_Running_Proc esses>
The thing is, I know this method should work because I built a separate solution just for the EnumProcs part (from my previous question that you had helped me with, remember?) that produces the output I want, but I think somehow in the GetCurrentUserAndDomain callback, it never goes past the first process - not sure why.
Comments?
Here's my resulting XML output:
<Snapshot_of_Running_Proce
<Process>
<Module>[System Process]</Module>
<User>¤Þ</User>
<Domain>Tß</Domain>
</Process>
<Process>
<Module>System</Module>
<User>¤Þ</User>
<Domain>Tß</Domain>
</Process>
</Snapshot_of_Running_Proc
The thing is, I know this method should work because I built a separate solution just for the EnumProcs part (from my previous question that you had helped me with, remember?) that produces the output I want, but I think somehow in the GetCurrentUserAndDomain callback, it never goes past the first process - not sure why.
Comments?
ASKER
Will no one help?
Patience, dude. ;-)
On which platform do you have this problem?
And it's OK that it displays only one line but how many processes do you have at earlier parts of the program? In other words: Have you tried using a debugger and checking the values agains the values you believe there should be? And it gets into a freeze after the first line or quits after the first process?
Btw, in the "lpfEnumProcesses" loop "dwSize2" is never increased so you'll never get out of the loop if you have more than 256 processes.
On which platform do you have this problem?
And it's OK that it displays only one line but how many processes do you have at earlier parts of the program? In other words: Have you tried using a debugger and checking the values agains the values you believe there should be? And it gets into a freeze after the first line or quits after the first process?
Btw, in the "lpfEnumProcesses" loop "dwSize2" is never increased so you'll never get out of the loop if you have more than 256 processes.
ASKER
hehe joghurt ;) point taken.
It's on XP.
>On which platform do you have this problem?
I have 47 processes displaying in my task manager.
>how many processes do you have at earlier parts of the program?
Yes, in the debugger, it displays the following:
[System Process]
System
NT Authority
crss.exe
NT Authority
After which it quits and displays the results.
>Have you tried using a debugger and checking the values agains the values you believe there should be? And it gets into a freeze after the first line or quits after the first process?
Hm, working on this, thanks.
>Btw, in the "lpfEnumProcesses" loop "dwSize2" is never increased so you'll never get out of the loop if you have more than >256 processes.
Thanks for your help,
S/.
It's on XP.
>On which platform do you have this problem?
I have 47 processes displaying in my task manager.
>how many processes do you have at earlier parts of the program?
Yes, in the debugger, it displays the following:
[System Process]
System
NT Authority
crss.exe
NT Authority
After which it quits and displays the results.
>Have you tried using a debugger and checking the values agains the values you believe there should be? And it gets into a freeze after the first line or quits after the first process?
Hm, working on this, thanks.
>Btw, in the "lpfEnumProcesses" loop "dwSize2" is never increased so you'll never get out of the loop if you have more than >256 processes.
Thanks for your help,
S/.
ASKER
oops, sorry about "top-posting"
Btw, unless you have Chinese (or so) user and domain names (that I don't believe), the values
<User>¤Þ</User>
<Domain>Tß</Domain>
seem a bit bogus. Such strings may also cause a crash after some loops.
What happens if you comment out the junk and print only the process IDs, then print the process names, too?
<User>¤Þ</User>
<Domain>Tß</Domain>
seem a bit bogus. Such strings may also cause a crash after some loops.
What happens if you comment out the junk and print only the process IDs, then print the process names, too?
ASKER
joghurt,
After commenting out the getCurrentUserAndDomain function, and simply printing out the process name, it displays all my running processes. (yay, thanks!)
But I'll need the UserName, because I have to separate out the processes by System or User as displayed in Task Manager.
Any advice?
After commenting out the getCurrentUserAndDomain function, and simply printing out the process name, it displays all my running processes. (yay, thanks!)
But I'll need the UserName, because I have to separate out the processes by System or User as displayed in Task Manager.
Any advice?
Your version of GetCurrentUserAndDomain seems to be a slight modifitcation of the original function.
What happens if you comment out parts of this function? I'd comment out LookupAccountSidA at the first try.
And would you put a MessageBox for all __leave statements to check where's the error? [Or use your debugger.]
Btw, another bug: In ProcessEnumerator you have two instances of
StringCchCopy(process.Proc essName, sizeof(szProcess), szProcess);
However, as the second parameter you should supply size of the destination (that is, size of process.ProcessName) instead. Furthermore, because szProcess is a pointer, sizeof(szProcess) is 4.
And the main bug:
The "processes" member is a std::vector. Now you take its address in ProcessInfo::Acquire and cast it to ProcessInfoEx* in ProcessEnumerator. This is a no-no. You must not use the address of a std::vector to manipulate its elements.
What happens if you comment out parts of this function? I'd comment out LookupAccountSidA at the first try.
And would you put a MessageBox for all __leave statements to check where's the error? [Or use your debugger.]
Btw, another bug: In ProcessEnumerator you have two instances of
StringCchCopy(process.Proc
However, as the second parameter you should supply size of the destination (that is, size of process.ProcessName) instead. Furthermore, because szProcess is a pointer, sizeof(szProcess) is 4.
And the main bug:
The "processes" member is a std::vector. Now you take its address in ProcessInfo::Acquire and cast it to ProcessInfoEx* in ProcessEnumerator. This is a no-no. You must not use the address of a std::vector to manipulate its elements.
ASKER
Hi joghurt,
I've fixed the bugs that you pointed out - thanks! However, that did not resolve the issue.
I've tried running it through a debugger, but I'm not getting any useful information. The message boxes that I added displayed the names as shown in the xml file and then the program continued execution.
Essentially, I've been agonizing over this issue ever since - will you please help?
Thanks,
S/.
I've fixed the bugs that you pointed out - thanks! However, that did not resolve the issue.
I've tried running it through a debugger, but I'm not getting any useful information. The message boxes that I added displayed the names as shown in the xml file and then the program continued execution.
Essentially, I've been agonizing over this issue ever since - will you please help?
Thanks,
S/.
Can you include the current sources?
ASKER
Hi joghurt,
Sure, here it is:
//ProcessInfo.cpp
#include "ProcessInfo.h"
//Function definitions
BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam);
BOOL GetCurrentUserAndDomain(LP TSTR szUser, PDWORD pcchUser, LPTSTR szDomain, PDWORD pcchDomain, DWORD dwPID);
BOOL WINAPI Enum16(DWORD dwThreadId, WORD HMod16, WORD hTask16, PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined);
BOOL CALLBACK ProcessEnumerator(DWORD dwPID, WORD wTask, LPCSTR szProcess, LPARAM lParam);
bool ProcessInfo::Acquire()
{
return EnumProcs((PROCENUMPROC)Pr ocessEnume rator, reinterpret_cast<LPARAM>(& processes) ) ? true : false;
}
//
// The EnumProcs function takes a pointer to a callback function that
// will be called once per process with the process filename and
// the process id.
// lpProc - address of the callback routine
// lParam - a user-defined LPARAM value to be passed to the callback routine.
// Callback function definition:
// BOOL CALLBACK Proc ( DWORD dw, WORD w, LPCTSTR lpstr, LPARAM lParam);
BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam)
{
OSVERSIONINFO osver;
HINSTANCE hInstLib = NULL;
HINSTANCE hInstLib2 = NULL;
HANDLE hSnapShot = NULL;
LPDWORD lpdwPIDs = NULL;
PROCESSENTRY32 procentry;
BOOL bFlag;
DWORD dwSize;
DWORD dwSize2;
DWORD dwIndex;
HMODULE hMod;
HANDLE hProcess;
char szFileName[MAX_PATH];
// ProcessInfoEx sProcess;
//the container for processes
ProcessInfo::Processes *process = reinterpret_cast<ProcessIn fo::Proces ses *>(lParam);
// ToolHelp Function pointers
HANDLE( WINAPI *lpfCreateToolhelp32Snapsh ot ) (DWORD, DWORD);
BOOL ( WINAPI *lpfProcess32First )( HANDLE, LPPROCESSENTRY32 );
BOOL ( WINAPI *lpfProcess32Next ) ( HANDLE, LPPROCESSENTRY32 );
//PSAPI Function Pointers
BOOL ( WINAPI *lpfEnumProcesses ) (DWORD *, DWORD, DWORD * );
BOOL ( WINAPI *lpfEnumProcessModules ) (HANDLE, HMODULE *, DWORD, LPDWORD );
DWORD ( WINAPI *lpfGetModuleBaseName ) (HANDLE, HMODULE, LPTSTR, DWORD );
//VDMDBG Function Pointers
INT ( WINAPI *lpfVDMEnumTaskWOWEx) (DWORD, TASKENUMPROCEX, LPARAM);
//Retrieve the OS version
osver.dwOSVersionInfoSize = sizeof(osver);
if(!GetVersionEx(&osver)) return FALSE;
//if Windows NT 4.0
if(osver.dwPlatformId == VER_PLATFORM_WIN32_NT && osver.dwMajorVersion == 4)
{
__try {
//Get the procedure address explicitly.
//We do this so that we don't have to worry about modules
//failing to load under OSes other than Windows NT 4.0
//because references to PSAPI.dll can't be resolved.
hInstLib = LoadLibraryA("PSAPI.DLL");
if(hInstLib == NULL)
__leave;
hInstLib2 = LoadLibrary("VDMDBG.DLL");
if(hInstLib2 == NULL)
__leave;
//Get procedure addresses.
lpfEnumProcesses = (BOOL (WINAPI *) (DWORD *, DWORD, DWORD*))
GetProcAddress(hInstLib, "EnumProcesses");
lpfEnumProcessModules = (BOOL (WINAPI *) (HANDLE, HMODULE *, DWORD, LPDWORD))
GetProcAddress(hInstLib, "EnumProcessModules");
lpfGetModuleBaseName = (DWORD (WINAPI *) (HANDLE, HMODULE, LPTSTR, DWORD))
GetProcAddress (hInstLib, "GetModuleBaseNameA");
lpfVDMEnumTaskWOWEx = (INT (WINAPI*) (DWORD, TASKENUMPROCEX, LPARAM))
GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
if(lpfEnumProcesses == NULL
|| lpfEnumProcessModules == NULL
|| lpfGetModuleBaseName == NULL
|| lpfVDMEnumTaskWOWEx == NULL)
__leave;
//
// Call the PSAPI function EnumProcesses to get all of the
// ProcIDs currently in the system.
// In the documentation, the third parameter of EnumProcesses
// is named cbNeeded, which implies that you can call
// the function once to find out how much space to
// allocate for the buffer and again to fill the buffer.
// This isn't true: the cbNeeded parameter returns the
// number of PIDs returned, so if your buffer size is
// zero cbNeeded returns zero.
//
// The "HeapAlloc" loop here ensures that we actually
// allocate a buffer large enough for all the PIDS in the system.
dwSize2 = 256 * sizeof(DWORD);
do {
if(lpdwPIDs){
HeapFree(GetProcessHeap(), 0, lpdwPIDs);
dwSize *= 2;
}
lpdwPIDs = (LPDWORD)HeapAlloc(GetProc essHeap(), 0, dwSize2);
if (lpdwPIDs == NULL)
__leave;
if(!lpfEnumProcesses(lpdwP IDs, dwSize2, &dwSize))
__leave;
}while (dwSize == dwSize2);
//How many ProcIds did we get?
dwSize /= sizeof(DWORD);
//Loop through each ProcID
for(dwIndex = 0; dwIndex < dwSize; dwIndex++)
{
szFileName[0] = 0;
// Open the process (if we can... security does not
// permit every process in the system to be opened).
hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, lpdwPIDs[dwIndex]);
if (hProcess != NULL) {
// Here we call EnumProcessModules to get only the
// first module in the process. This will be the
// EXE module for which we will retrieve the name.
if (lpfEnumProcessModules(hPr ocess, &hMod,
sizeof(hMod), &dwSize2)) {
// Get the module name
if (!lpfGetModuleBaseName(hPr ocess, hMod,
szFileName, sizeof(szFileName)))
szFileName[0] = 0;
}
CloseHandle(hProcess);
}
// Regardless of OpenProcess success or failure, we
// still call the enum func with the ProcID.
if (!lpProc(lpdwPIDs[dwIndex] , 0, szFileName, lParam))
break;
// Did we just bump into an NTVDM?
if (_stricmp(szFileName, "NTVDM.EXE") == 0) {
ProcessInfoEx proc;
// Fill in some info for the 16-bit enum proc.
proc.dwPID = lpdwPIDs[dwIndex];
proc.lpProc = lpProc;
proc.lParam = (DWORD) lParam;
proc.bEnd = FALSE;
// Enum the 16-bit stuff.
lpfVDMEnumTaskWOWEx(lpdwPI Ds[dwIndex ],
(TASKENUMPROCEX) Enum16, (LPARAM) &proc);
// Did our main enum func say quit?
if (proc.bEnd)
break;
process->push_back(proc);
}
}
} __finally {
if (hInstLib)
FreeLibrary(hInstLib);
if (hInstLib2)
FreeLibrary(hInstLib2);
if (lpdwPIDs)
HeapFree(GetProcessHeap(), 0, lpdwPIDs);
}
// If any OS other than Windows NT 4.0.
} else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
|| (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
&& osver.dwMajorVersion > 4)) {
__try {
hInstLib = LoadLibraryA("Kernel32.DLL ");
if (hInstLib == NULL)
__leave;
// If NT-based OS, load VDMDBG.DLL.
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
hInstLib2 = LoadLibraryA("VDMDBG.DLL") ;
if (hInstLib2 == NULL)
__leave;
}
// Get procedure addresses. We are linking to
// these functions explicitly, because a module using
// this code would fail to load under Windows NT,
// which does not have the Toolhelp32
// functions in KERNEL32.DLL.
lpfCreateToolhelp32Snapsho t =
(HANDLE (WINAPI *)(DWORD,DWORD))
GetProcAddress(hInstLib, "CreateToolhelp32Snapshot" );
lpfProcess32First =
(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32 ))
GetProcAddress(hInstLib, "Process32First");
lpfProcess32Next =
(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32 ))
GetProcAddress(hInstLib, "Process32Next");
if (lpfProcess32Next == NULL
|| lpfProcess32First == NULL
|| lpfCreateToolhelp32Snapsho t == NULL)
__leave;
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX,
LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
if (lpfVDMEnumTaskWOWEx == NULL)
__leave;
}
// Get a handle to a Toolhelp snapshot of all processes.
hSnapShot = lpfCreateToolhelp32Snapsho t(TH32CS_S NAPPROCESS , 0);
if (hSnapShot == INVALID_HANDLE_VALUE) {
FreeLibrary(hInstLib);
return FALSE;
}
// Get the first process' information.
procentry.dwSize = sizeof(PROCESSENTRY32);
bFlag = lpfProcess32First(hSnapSho t, &procentry);
// While there are processes, keep looping.
while (bFlag) {
ProcessInfoEx sProcess;
// Call the enum func with the filename and ProcID.
if (lpProc(procentry.th32Proc essID, 0,
procentry.szExeFile, reinterpret_cast<LPARAM>(& sProcess)) ) {
// Did we just bump into an NTVDM?
if (_stricmp(procentry.szExeF ile, "NTVDM.EXE") == 0) {
ProcessInfoEx sProcess;
// Fill in some info for the 16-bit enum proc.
sProcess.dwPID = procentry.th32ProcessID;
sProcess.lpProc = lpProc;
sProcess.lParam = (DWORD) lParam;
sProcess.bEnd = FALSE;
// Enum the 16-bit stuff.
lpfVDMEnumTaskWOWEx(procen try.th32Pr ocessID,
(TASKENUMPROCEX) Enum16, (LPARAM) &sProcess);
// Did our main enum func say quit?
if (sProcess.bEnd)
break;
process->push_back(sProces s);
}
procentry.dwSize = sizeof(PROCESSENTRY32);
bFlag = lpfProcess32Next(hSnapShot , &procentry);
process->push_back(sProces s);
} else
bFlag = FALSE;
}
} __finally {
if (hInstLib)
FreeLibrary(hInstLib);
if (hInstLib2)
FreeLibrary(hInstLib2);
}
} else
return FALSE;
// Free the library.
FreeLibrary(hInstLib);
return TRUE;
}
BOOL WINAPI Enum16(DWORD dwThreadId, WORD hMod16,
WORD hTask16,PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined)
{
BOOL bRet;
ProcessInfoEx *psInfo = (ProcessInfoEx *)lpUserDefined;
bRet = psInfo->lpProc(psInfo->dwP ID, hTask16, pszFileName,psInfo->lParam );
if (!bRet)
psInfo->bEnd = TRUE;
return !bRet;
}
BOOL CALLBACK ProcessEnumerator(DWORD dwPID, WORD wTask, LPCSTR szProcess, LPARAM lParam)
{
ProcessInfoEx &process = *(reinterpret_cast<Process InfoEx *>(lParam));
TCHAR userName[1024]= {0};
TCHAR domainName[1024]= {0};
DWORD userLen = sizeof(userName)/sizeof(us erName[0]) ;
DWORD domainLen = sizeof(domainName)/sizeof( domainName [0]);
if (wTask == 0)
{
//if(GetCurrentUserAndDoma in(userNam e, &userLen, domainName, &domainLen, dwPID))
//{
// HRESULT hr = StringCchCopy(process.User Name, sizeof(process.UserName), userName);
// if (FAILED(hr))
// {
// MessageBox("Copy of User Name failed", 0, 0);
//
// return false;
// }
// hr = StringCchCopy(process.Doma in, domainLen, domainName);
// if (FAILED(hr))
// {
// return false;
// }
// hr = StringCchCopy(process.Proc essName, sizeof(process.ProcessName ), szProcess);
// if (FAILED(hr))
// {
// return false;
// }
// //processContainer.push_ba ck(procInf o);
//}
//else
//{
HRESULT hr = StringCchCopy(process.Proc essName,si zeof(proce ss.Process Name), szProcess);
if (FAILED(hr))
{
return false;
}
//processContainer.push_ba ck(procInf o);
//}
}
else { //if wtask == false
HRESULT hr = StringCchCopy(process.Proc essName, sizeof(process.ProcessName ), szProcess);
if (FAILED(hr))
{
return false;
}
//processContainer.push_ba ck(procInf o);
//printf(" %5u %s\n", wTask, szProcess);}
}
return TRUE;
}
BOOL GetCurrentUserAndDomain(PT STR szUser, PDWORD pcchUser, PTSTR szDomain, PDWORD pcchDomain, DWORD dwPID)
{
BOOL fSuccess = FALSE;
HANDLE hToken = NULL;
HANDLE hProcess = NULL;
PTOKEN_USER ptiUser = NULL;
DWORD cbti = 0;
SID_NAME_USE snu;
__try {
// Get the process handle
hProcess = OpenProcess ( PROCESS_QUERY_INFORMATION, FALSE, dwPID);
if (!hProcess)
__leave;
if (!OpenProcessToken(hProces s, TOKEN_QUERY, &hToken))
__leave;
// Obtain the size of the user information in the token.
if (GetTokenInformation(hToke n, TokenUser, NULL, 0, &cbti)) {
// Call should have failed due to zero-length buffer.
__leave;
} else {
// Call should have failed due to zero-length buffer.
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
__leave;
}
// Allocate buffer for user information in the token.
ptiUser = (PTOKEN_USER) HeapAlloc(GetProcessHeap() , 0, cbti);
if (!ptiUser)
__leave;
// Retrieve the user information from the token.
if (!GetTokenInformation(hTok en, TokenUser, ptiUser, cbti, &cbti))
__leave;
// Retrieve user name and domain name based on user's SID.
if (!LookupAccountSid(NULL, ptiUser->User.Sid, szUser, pcchUser,
szDomain, pcchDomain, &snu))
__leave;
fSuccess = TRUE;
}
__finally {
// Free resources.
if (hToken)
CloseHandle(hToken);
if (ptiUser)
HeapFree(GetProcessHeap(), 0, ptiUser);
}
return fSuccess;
}
size_t ProcessInfo::ProcessCount( )
{
return processes.size();
}
ProcessInfoEx& ProcessInfo::Process( size_t index )
{
if( index < processes.size() )
{
return processes.at(index);
}
return processes.back();
}
TIA,
S/.
Sure, here it is:
//ProcessInfo.cpp
#include "ProcessInfo.h"
//Function definitions
BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam);
BOOL GetCurrentUserAndDomain(LP
BOOL WINAPI Enum16(DWORD dwThreadId, WORD HMod16, WORD hTask16, PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined);
BOOL CALLBACK ProcessEnumerator(DWORD dwPID, WORD wTask, LPCSTR szProcess, LPARAM lParam);
bool ProcessInfo::Acquire()
{
return EnumProcs((PROCENUMPROC)Pr
}
//
// The EnumProcs function takes a pointer to a callback function that
// will be called once per process with the process filename and
// the process id.
// lpProc - address of the callback routine
// lParam - a user-defined LPARAM value to be passed to the callback routine.
// Callback function definition:
// BOOL CALLBACK Proc ( DWORD dw, WORD w, LPCTSTR lpstr, LPARAM lParam);
BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam)
{
OSVERSIONINFO osver;
HINSTANCE hInstLib = NULL;
HINSTANCE hInstLib2 = NULL;
HANDLE hSnapShot = NULL;
LPDWORD lpdwPIDs = NULL;
PROCESSENTRY32 procentry;
BOOL bFlag;
DWORD dwSize;
DWORD dwSize2;
DWORD dwIndex;
HMODULE hMod;
HANDLE hProcess;
char szFileName[MAX_PATH];
// ProcessInfoEx sProcess;
//the container for processes
ProcessInfo::Processes *process = reinterpret_cast<ProcessIn
// ToolHelp Function pointers
HANDLE( WINAPI *lpfCreateToolhelp32Snapsh
BOOL ( WINAPI *lpfProcess32First )( HANDLE, LPPROCESSENTRY32 );
BOOL ( WINAPI *lpfProcess32Next ) ( HANDLE, LPPROCESSENTRY32 );
//PSAPI Function Pointers
BOOL ( WINAPI *lpfEnumProcesses ) (DWORD *, DWORD, DWORD * );
BOOL ( WINAPI *lpfEnumProcessModules ) (HANDLE, HMODULE *, DWORD, LPDWORD );
DWORD ( WINAPI *lpfGetModuleBaseName ) (HANDLE, HMODULE, LPTSTR, DWORD );
//VDMDBG Function Pointers
INT ( WINAPI *lpfVDMEnumTaskWOWEx) (DWORD, TASKENUMPROCEX, LPARAM);
//Retrieve the OS version
osver.dwOSVersionInfoSize = sizeof(osver);
if(!GetVersionEx(&osver)) return FALSE;
//if Windows NT 4.0
if(osver.dwPlatformId == VER_PLATFORM_WIN32_NT && osver.dwMajorVersion == 4)
{
__try {
//Get the procedure address explicitly.
//We do this so that we don't have to worry about modules
//failing to load under OSes other than Windows NT 4.0
//because references to PSAPI.dll can't be resolved.
hInstLib = LoadLibraryA("PSAPI.DLL");
if(hInstLib == NULL)
__leave;
hInstLib2 = LoadLibrary("VDMDBG.DLL");
if(hInstLib2 == NULL)
__leave;
//Get procedure addresses.
lpfEnumProcesses = (BOOL (WINAPI *) (DWORD *, DWORD, DWORD*))
GetProcAddress(hInstLib, "EnumProcesses");
lpfEnumProcessModules = (BOOL (WINAPI *) (HANDLE, HMODULE *, DWORD, LPDWORD))
GetProcAddress(hInstLib, "EnumProcessModules");
lpfGetModuleBaseName = (DWORD (WINAPI *) (HANDLE, HMODULE, LPTSTR, DWORD))
GetProcAddress (hInstLib, "GetModuleBaseNameA");
lpfVDMEnumTaskWOWEx = (INT (WINAPI*) (DWORD, TASKENUMPROCEX, LPARAM))
GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
if(lpfEnumProcesses == NULL
|| lpfEnumProcessModules == NULL
|| lpfGetModuleBaseName == NULL
|| lpfVDMEnumTaskWOWEx == NULL)
__leave;
//
// Call the PSAPI function EnumProcesses to get all of the
// ProcIDs currently in the system.
// In the documentation, the third parameter of EnumProcesses
// is named cbNeeded, which implies that you can call
// the function once to find out how much space to
// allocate for the buffer and again to fill the buffer.
// This isn't true: the cbNeeded parameter returns the
// number of PIDs returned, so if your buffer size is
// zero cbNeeded returns zero.
//
// The "HeapAlloc" loop here ensures that we actually
// allocate a buffer large enough for all the PIDS in the system.
dwSize2 = 256 * sizeof(DWORD);
do {
if(lpdwPIDs){
HeapFree(GetProcessHeap(),
dwSize *= 2;
}
lpdwPIDs = (LPDWORD)HeapAlloc(GetProc
if (lpdwPIDs == NULL)
__leave;
if(!lpfEnumProcesses(lpdwP
__leave;
}while (dwSize == dwSize2);
//How many ProcIds did we get?
dwSize /= sizeof(DWORD);
//Loop through each ProcID
for(dwIndex = 0; dwIndex < dwSize; dwIndex++)
{
szFileName[0] = 0;
// Open the process (if we can... security does not
// permit every process in the system to be opened).
hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, lpdwPIDs[dwIndex]);
if (hProcess != NULL) {
// Here we call EnumProcessModules to get only the
// first module in the process. This will be the
// EXE module for which we will retrieve the name.
if (lpfEnumProcessModules(hPr
sizeof(hMod), &dwSize2)) {
// Get the module name
if (!lpfGetModuleBaseName(hPr
szFileName, sizeof(szFileName)))
szFileName[0] = 0;
}
CloseHandle(hProcess);
}
// Regardless of OpenProcess success or failure, we
// still call the enum func with the ProcID.
if (!lpProc(lpdwPIDs[dwIndex]
break;
// Did we just bump into an NTVDM?
if (_stricmp(szFileName, "NTVDM.EXE") == 0) {
ProcessInfoEx proc;
// Fill in some info for the 16-bit enum proc.
proc.dwPID = lpdwPIDs[dwIndex];
proc.lpProc = lpProc;
proc.lParam = (DWORD) lParam;
proc.bEnd = FALSE;
// Enum the 16-bit stuff.
lpfVDMEnumTaskWOWEx(lpdwPI
(TASKENUMPROCEX) Enum16, (LPARAM) &proc);
// Did our main enum func say quit?
if (proc.bEnd)
break;
process->push_back(proc);
}
}
} __finally {
if (hInstLib)
FreeLibrary(hInstLib);
if (hInstLib2)
FreeLibrary(hInstLib2);
if (lpdwPIDs)
HeapFree(GetProcessHeap(),
}
// If any OS other than Windows NT 4.0.
} else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
|| (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
&& osver.dwMajorVersion > 4)) {
__try {
hInstLib = LoadLibraryA("Kernel32.DLL
if (hInstLib == NULL)
__leave;
// If NT-based OS, load VDMDBG.DLL.
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
hInstLib2 = LoadLibraryA("VDMDBG.DLL")
if (hInstLib2 == NULL)
__leave;
}
// Get procedure addresses. We are linking to
// these functions explicitly, because a module using
// this code would fail to load under Windows NT,
// which does not have the Toolhelp32
// functions in KERNEL32.DLL.
lpfCreateToolhelp32Snapsho
(HANDLE (WINAPI *)(DWORD,DWORD))
GetProcAddress(hInstLib, "CreateToolhelp32Snapshot"
lpfProcess32First =
(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32
GetProcAddress(hInstLib, "Process32First");
lpfProcess32Next =
(BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32
GetProcAddress(hInstLib, "Process32Next");
if (lpfProcess32Next == NULL
|| lpfProcess32First == NULL
|| lpfCreateToolhelp32Snapsho
__leave;
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX,
LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
if (lpfVDMEnumTaskWOWEx == NULL)
__leave;
}
// Get a handle to a Toolhelp snapshot of all processes.
hSnapShot = lpfCreateToolhelp32Snapsho
if (hSnapShot == INVALID_HANDLE_VALUE) {
FreeLibrary(hInstLib);
return FALSE;
}
// Get the first process' information.
procentry.dwSize = sizeof(PROCESSENTRY32);
bFlag = lpfProcess32First(hSnapSho
// While there are processes, keep looping.
while (bFlag) {
ProcessInfoEx sProcess;
// Call the enum func with the filename and ProcID.
if (lpProc(procentry.th32Proc
procentry.szExeFile, reinterpret_cast<LPARAM>(&
// Did we just bump into an NTVDM?
if (_stricmp(procentry.szExeF
ProcessInfoEx sProcess;
// Fill in some info for the 16-bit enum proc.
sProcess.dwPID = procentry.th32ProcessID;
sProcess.lpProc = lpProc;
sProcess.lParam = (DWORD) lParam;
sProcess.bEnd = FALSE;
// Enum the 16-bit stuff.
lpfVDMEnumTaskWOWEx(procen
(TASKENUMPROCEX) Enum16, (LPARAM) &sProcess);
// Did our main enum func say quit?
if (sProcess.bEnd)
break;
process->push_back(sProces
}
procentry.dwSize = sizeof(PROCESSENTRY32);
bFlag = lpfProcess32Next(hSnapShot
process->push_back(sProces
} else
bFlag = FALSE;
}
} __finally {
if (hInstLib)
FreeLibrary(hInstLib);
if (hInstLib2)
FreeLibrary(hInstLib2);
}
} else
return FALSE;
// Free the library.
FreeLibrary(hInstLib);
return TRUE;
}
BOOL WINAPI Enum16(DWORD dwThreadId, WORD hMod16,
WORD hTask16,PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined)
{
BOOL bRet;
ProcessInfoEx *psInfo = (ProcessInfoEx *)lpUserDefined;
bRet = psInfo->lpProc(psInfo->dwP
if (!bRet)
psInfo->bEnd = TRUE;
return !bRet;
}
BOOL CALLBACK ProcessEnumerator(DWORD dwPID, WORD wTask, LPCSTR szProcess, LPARAM lParam)
{
ProcessInfoEx &process = *(reinterpret_cast<Process
TCHAR userName[1024]= {0};
TCHAR domainName[1024]= {0};
DWORD userLen = sizeof(userName)/sizeof(us
DWORD domainLen = sizeof(domainName)/sizeof(
if (wTask == 0)
{
//if(GetCurrentUserAndDoma
//{
// HRESULT hr = StringCchCopy(process.User
// if (FAILED(hr))
// {
// MessageBox("Copy of User Name failed", 0, 0);
//
// return false;
// }
// hr = StringCchCopy(process.Doma
// if (FAILED(hr))
// {
// return false;
// }
// hr = StringCchCopy(process.Proc
// if (FAILED(hr))
// {
// return false;
// }
// //processContainer.push_ba
//}
//else
//{
HRESULT hr = StringCchCopy(process.Proc
if (FAILED(hr))
{
return false;
}
//processContainer.push_ba
//}
}
else { //if wtask == false
HRESULT hr = StringCchCopy(process.Proc
if (FAILED(hr))
{
return false;
}
//processContainer.push_ba
//printf(" %5u %s\n", wTask, szProcess);}
}
return TRUE;
}
BOOL GetCurrentUserAndDomain(PT
{
BOOL fSuccess = FALSE;
HANDLE hToken = NULL;
HANDLE hProcess = NULL;
PTOKEN_USER ptiUser = NULL;
DWORD cbti = 0;
SID_NAME_USE snu;
__try {
// Get the process handle
hProcess = OpenProcess ( PROCESS_QUERY_INFORMATION,
if (!hProcess)
__leave;
if (!OpenProcessToken(hProces
__leave;
// Obtain the size of the user information in the token.
if (GetTokenInformation(hToke
// Call should have failed due to zero-length buffer.
__leave;
} else {
// Call should have failed due to zero-length buffer.
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
__leave;
}
// Allocate buffer for user information in the token.
ptiUser = (PTOKEN_USER) HeapAlloc(GetProcessHeap()
if (!ptiUser)
__leave;
// Retrieve the user information from the token.
if (!GetTokenInformation(hTok
__leave;
// Retrieve user name and domain name based on user's SID.
if (!LookupAccountSid(NULL, ptiUser->User.Sid, szUser, pcchUser,
szDomain, pcchDomain, &snu))
__leave;
fSuccess = TRUE;
}
__finally {
// Free resources.
if (hToken)
CloseHandle(hToken);
if (ptiUser)
HeapFree(GetProcessHeap(),
}
return fSuccess;
}
size_t ProcessInfo::ProcessCount(
{
return processes.size();
}
ProcessInfoEx& ProcessInfo::Process( size_t index )
{
if( index < processes.size() )
{
return processes.at(index);
}
return processes.back();
}
TIA,
S/.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
OMG, joghurt - that worked! Thank you!!
=o)
=o)
Oh, just a last comment: If ProcessEnumerator fails, you shouldn't abort the enumeration; you should only skip that one process.
ASKER
joghurt - what do you mean?
learning,
S/.
learning,
S/.
If you return FALSE in ProcessEnumerator, the enumeration is aborted. So if there's some error (you don't have necessary privileges for a given process, etc.), you should only skip only that one process [to be more precise, only that one given member of the structure], and you shouldn't ever return FALSE. Or only if push_back fails and you're sure the next call will fail, too.
ASKER
Joghurt,
Thanks for your feedback - so, in other words, instead of doing this:
HRESULT hr = StringCchCopy(process.User Name, sizeof(process.UserName), userName);
if (FAILED(hr))
{
return false;
}
I should do this, instead:
if (FAILED(hr))
{
break;
}
Let me know.
Thanks,
S/.
Thanks for your feedback - so, in other words, instead of doing this:
HRESULT hr = StringCchCopy(process.User
if (FAILED(hr))
{
return false;
}
I should do this, instead:
if (FAILED(hr))
{
break;
}
Let me know.
Thanks,
S/.
Because there is no "for" or "switch" statement nearby, "break" won't compile. ;-)
BOOL CALLBACK ProcessEnumerator(DWORD dwPID, WORD wTask, LPCSTR szProcess, LPARAM lParam)
{
ProcessInfoEx &process = *(reinterpret_cast<Process InfoEx *>(lParam));
TCHAR userName[1024]= {0};
TCHAR domainName[1024]= {0};
DWORD userLen = sizeof(userName)/sizeof(us erName[0]) ;
DWORD domainLen = sizeof(domainName)/sizeof( domainName [0]);
bool ok = true;
process.UserName[0] = _T('\0');
process.Domain[0] = _T('\0');
process.ProcessName[0] = _T('\0');
if (wTask == 0)
{
if(GetCurrentUserAndDomain (userName, &userLen, domainName, &domainLen, dwPID)) {
HRESULT hr = StringCchCopy(process.User Name, sizeof(process.UserName), userName);
if (FAILED(hr))
ok = false;
hr = StringCchCopy(process.Doma in, domainLen, domainName);
if (FAILED(hr))
ok = false;
hr = StringCchCopy(process.Proc essName, sizeof(process.ProcessName ), szProcess);
if (FAILED(hr))
ok = false;
}
else
{
HRESULT hr = StringCchCopy(process.Proc essName,si zeof(proce ss.Process Name), szProcess);
if (FAILED(hr))
ok = false;
}
}
else { //if wtask == false
HRESULT hr = StringCchCopy(process.Proc essName, sizeof(process.ProcessName ), szProcess);
if (FAILED(hr))
ok = false;
}
// It's up to you whether you want to list processes with incomplete process information.
// If you need them, just remove the "if" line.
if (ok)
processContainer.push_back (process);
return TRUE;
}
BOOL CALLBACK ProcessEnumerator(DWORD dwPID, WORD wTask, LPCSTR szProcess, LPARAM lParam)
{
ProcessInfoEx &process = *(reinterpret_cast<Process
TCHAR userName[1024]= {0};
TCHAR domainName[1024]= {0};
DWORD userLen = sizeof(userName)/sizeof(us
DWORD domainLen = sizeof(domainName)/sizeof(
bool ok = true;
process.UserName[0] = _T('\0');
process.Domain[0] = _T('\0');
process.ProcessName[0] = _T('\0');
if (wTask == 0)
{
if(GetCurrentUserAndDomain
HRESULT hr = StringCchCopy(process.User
if (FAILED(hr))
ok = false;
hr = StringCchCopy(process.Doma
if (FAILED(hr))
ok = false;
hr = StringCchCopy(process.Proc
if (FAILED(hr))
ok = false;
}
else
{
HRESULT hr = StringCchCopy(process.Proc
if (FAILED(hr))
ok = false;
}
}
else { //if wtask == false
HRESULT hr = StringCchCopy(process.Proc
if (FAILED(hr))
ok = false;
}
// It's up to you whether you want to list processes with incomplete process information.
// If you need them, just remove the "if" line.
if (ok)
processContainer.push_back
return TRUE;
}
ASKER
Awesome, joghurt - thanks very much for your help!
=)
=)
if (wTask == 0){
if(GetCurrentUserAndDomain
{
HRESULT hr = StringCchCopy(process.User
if (FAILED(hr))
{
return false;
}
hr = StringCchCopy(process.Doma
if (FAILED(hr))
{
return false;
}
hr = StringCchCopy(process.Proc
if (FAILED(hr))
{
return false;
}
}
else
{
HRESULT hr = StringCchCopy(process.Proc
if (FAILED(hr))
{
return false;
}
}
}
else { //if GetCurrentUserAndDomain == false <-------- belongs to 'if (wTask == 0)'