Solved

Background processes enumeration displays only one process - help

Posted on 2004-04-29
20
540 Views
Last Modified: 2013-12-03
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(LPTSTR 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)ProcessEnumerator, 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<ProcessInfo::Processes *>(lParam);


      // ToolHelp Function pointers
      HANDLE( WINAPI *lpfCreateToolhelp32Snapshot ) (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(GetProcessHeap(), 0, dwSize2);
                        if (lpdwPIDs == NULL)
                              __leave;

                        if(!lpfEnumProcesses(lpdwPIDs, 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(hProcess, &hMod,
                                    sizeof(hMod), &dwSize2)) {

                                          // Get the module name
                                          if (!lpfGetModuleBaseName(hProcess, 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(lpdwPIDs[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.
                        lpfCreateToolhelp32Snapshot =
                              (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
                              || lpfCreateToolhelp32Snapshot == 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 = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
                        if (hSnapShot == INVALID_HANDLE_VALUE) {
                              FreeLibrary(hInstLib);
                              return FALSE;
                        }

                        // Get the first process' information.
                        procentry.dwSize = sizeof(PROCESSENTRY32);
                        bFlag = lpfProcess32First(hSnapShot, &procentry);

                        // While there are processes, keep looping.
                        while (bFlag) {
                              ProcessInfoEx sProcess;



                              // Call the enum func with the filename and ProcID.
                              if (lpProc(procentry.th32ProcessID, 0,
                                    procentry.szExeFile, reinterpret_cast<LPARAM>(&sProcess))) {

                                          // Did we just bump into an NTVDM?
                                          if (_stricmp(procentry.szExeFile, "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(procentry.th32ProcessID,
                                                      (TASKENUMPROCEX) Enum16, (LPARAM) &sProcess);

                                                // Did our main enum func say quit?
                                                if (sProcess.bEnd)
                                                      break;
                                                process->push_back(sProcess);
                                          }

                                          procentry.dwSize = sizeof(PROCESSENTRY32);
                                          bFlag = lpfProcess32Next(hSnapShot, &procentry);
                                          process->push_back(sProcess);


                                    } 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->dwPID, 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<ProcessInfoEx *>(lParam));

      TCHAR userName[256]= {0};
      TCHAR domainName[256]= {0};

      DWORD userLen = sizeof(userName)/sizeof(userName[0]);
      DWORD domainLen = sizeof(domainName)/sizeof(domainName[0]);

      if (wTask == 0){
            if(GetCurrentUserAndDomain(userName, &userLen, domainName, &domainLen, dwPID))
            {
                  HRESULT hr = StringCchCopy(process.UserName, sizeof(process.UserName), userName);

                  if (FAILED(hr))
                  {
                        return false;
                  }

                  hr = StringCchCopy(process.Domain, domainLen, domainName);
                  if (FAILED(hr))
                  {
                        return false;
                  }

                  hr = StringCchCopy(process.ProcessName, sizeof(szProcess), szProcess);
                  if (FAILED(hr))
                  {
                        return false;
                  }

            }
            else
            {
            HRESULT hr = StringCchCopy(process.ProcessName,sizeof(process.ProcessName), szProcess);
                  if (FAILED(hr))
                  {
                        return false;
                  }
            }

      }

      else { //if GetCurrentUserAndDomain == false

            HRESULT hr = StringCchCopy(process.ProcessName, sizeof(szProcess), szProcess);
            if (FAILED(hr))
            {
                  return false;
            }
            //printf("  %5u %s\n", wTask, szProcess);}
      }
      return TRUE;
}


BOOL GetCurrentUserAndDomain(PTSTR 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(hProcess, TOKEN_QUERY, &hToken))
                  __leave;


            // Obtain the size of the user information in the token.
            if (GetTokenInformation(hToken, 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(hToken, 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/.
0
Comment
Question by:stitch2802
  • 11
  • 8
20 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 10951959
You seem to have a mismatched if/else pair:

  if (wTask == 0){
         if(GetCurrentUserAndDomain(userName, &userLen, domainName, &domainLen, dwPID))
         {
              HRESULT hr = StringCchCopy(process.UserName, sizeof(process.UserName), userName);

              if (FAILED(hr))
              {
                   return false;
              }

              hr = StringCchCopy(process.Domain, domainLen, domainName);
              if (FAILED(hr))
              {
                   return false;
              }

              hr = StringCchCopy(process.ProcessName, sizeof(szProcess), szProcess);
              if (FAILED(hr))
              {
                   return false;
              }

         }
         else
         {
         HRESULT hr = StringCchCopy(process.ProcessName,sizeof(process.ProcessName), szProcess);
              if (FAILED(hr))
              {
                   return false;
              }
         }

    }

    else { //if GetCurrentUserAndDomain == false <-------- belongs to 'if (wTask == 0)'
0
 

Author Comment

by:stitch2802
ID: 10952179
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_Processes>
    <Process>
     <Module>[System Process]</Module>
     <User>¤Þ</User>
     <Domain>Tß</Domain>
    </Process>
    <Process>
     <Module>System</Module>
     <User>¤Þ</User>
     <Domain>Tß</Domain>
    </Process>
   </Snapshot_of_Running_Processes>

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?
 
0
 

Author Comment

by:stitch2802
ID: 10963641
Will no one help?
0
 
LVL 6

Expert Comment

by:joghurt
ID: 10980760
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.
0
 

Author Comment

by:stitch2802
ID: 10981746
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/.
0
 

Author Comment

by:stitch2802
ID: 10981957
oops, sorry about "top-posting"
0
 
LVL 6

Expert Comment

by:joghurt
ID: 10982151
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?
0
 

Author Comment

by:stitch2802
ID: 10982448
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?
0
 
LVL 6

Expert Comment

by:joghurt
ID: 10984270
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.ProcessName, 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.
0
 

Author Comment

by:stitch2802
ID: 11064439
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/.
0
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 
LVL 6

Expert Comment

by:joghurt
ID: 11065996
Can you include the current sources?
0
 

Author Comment

by:stitch2802
ID: 11069646
Hi joghurt,

Sure, here it is:

//ProcessInfo.cpp

#include "ProcessInfo.h"

//Function definitions
BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam);
BOOL GetCurrentUserAndDomain(LPTSTR 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)ProcessEnumerator, 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<ProcessInfo::Processes *>(lParam);


      // ToolHelp Function pointers
      HANDLE( WINAPI *lpfCreateToolhelp32Snapshot ) (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(GetProcessHeap(), 0, dwSize2);
                        if (lpdwPIDs == NULL)
                              __leave;

                        if(!lpfEnumProcesses(lpdwPIDs, 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(hProcess, &hMod,
                                    sizeof(hMod), &dwSize2)) {

                                          // Get the module name
                                          if (!lpfGetModuleBaseName(hProcess, 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(lpdwPIDs[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.
                        lpfCreateToolhelp32Snapshot =
                              (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
                              || lpfCreateToolhelp32Snapshot == 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 = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
                        if (hSnapShot == INVALID_HANDLE_VALUE) {
                              FreeLibrary(hInstLib);
                              return FALSE;
                        }

                        // Get the first process' information.
                        procentry.dwSize = sizeof(PROCESSENTRY32);
                        bFlag = lpfProcess32First(hSnapShot, &procentry);

                        // While there are processes, keep looping.
                        while (bFlag) {
                              ProcessInfoEx sProcess;



                              // Call the enum func with the filename and ProcID.
                              if (lpProc(procentry.th32ProcessID, 0,
                                    procentry.szExeFile, reinterpret_cast<LPARAM>(&sProcess))) {

                                          // Did we just bump into an NTVDM?
                                          if (_stricmp(procentry.szExeFile, "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(procentry.th32ProcessID,
                                                      (TASKENUMPROCEX) Enum16, (LPARAM) &sProcess);

                                                // Did our main enum func say quit?
                                                if (sProcess.bEnd)
                                                      break;
                                                process->push_back(sProcess);
                                          }

                                          procentry.dwSize = sizeof(PROCESSENTRY32);
                                          bFlag = lpfProcess32Next(hSnapShot, &procentry);
                                          process->push_back(sProcess);


                                    } 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->dwPID, 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<ProcessInfoEx *>(lParam));

      TCHAR userName[1024]= {0};
      TCHAR domainName[1024]= {0};

      DWORD userLen = sizeof(userName)/sizeof(userName[0]);
      DWORD domainLen = sizeof(domainName)/sizeof(domainName[0]);

      if (wTask == 0)
      {
            //if(GetCurrentUserAndDomain(userName, &userLen, domainName, &domainLen, dwPID))
            //{
            //      HRESULT hr = StringCchCopy(process.UserName, sizeof(process.UserName), userName);

            //      if (FAILED(hr))
            //      {
            //            MessageBox("Copy of User Name failed", 0, 0);
            //            
            //            return false;
            //      }

            //      hr = StringCchCopy(process.Domain, domainLen, domainName);
            //      if (FAILED(hr))
            //      {
            //            return false;
            //      }

            //      hr = StringCchCopy(process.ProcessName, sizeof(process.ProcessName), szProcess);
            //      if (FAILED(hr))
            //      {
            //            return false;
            //      }

            //      //processContainer.push_back(procInfo);

            //}
            //else
            //{
                  HRESULT hr = StringCchCopy(process.ProcessName,sizeof(process.ProcessName), szProcess);
                  if (FAILED(hr))
                  {
                        return false;
                  }
                  //processContainer.push_back(procInfo);
            //}


      }

      else { //if wtask == false

            HRESULT hr = StringCchCopy(process.ProcessName, sizeof(process.ProcessName), szProcess);
            if (FAILED(hr))
            {
                  return false;
            }
            //processContainer.push_back(procInfo);
            //printf("  %5u %s\n", wTask, szProcess);}
      }
      return TRUE;
}




BOOL GetCurrentUserAndDomain(PTSTR 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(hProcess, TOKEN_QUERY, &hToken))
               __leave;


          // Obtain the size of the user information in the token.
          if (GetTokenInformation(hToken, 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(hToken, 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/.
0
 
LVL 6

Accepted Solution

by:
joghurt earned 500 total points
ID: 11071133
Well, after getting your code to compile, it took only 5 minutes to find the errors using the debugger:

1. You should initialize UserName and Domain members of the structure because GetCurrentUserAndDomain may (and will) fail and you'll get junk.
2. [It was the real cause.] Change the second parameter here:
               hr = StringCchCopy(process.Domain, sizeof(process.Domain), domainName);
Because size of process.Domain was smaller (256) then domainLen (1024), StringCchCopy failed and you've returned.
3. NB, if you use BOOL (just as in ProcessEnumerator), you should return "FALSE" instead of "false", even if the values are the same.
0
 

Author Comment

by:stitch2802
ID: 11072066
OMG, joghurt - that worked! Thank you!!

=o)
0
 
LVL 6

Expert Comment

by:joghurt
ID: 11074216
Oh, just a last comment: If ProcessEnumerator fails, you shouldn't abort the enumeration; you should only skip that one process.
0
 

Author Comment

by:stitch2802
ID: 11083405
joghurt - what do you mean?

learning,
S/.
0
 
LVL 6

Expert Comment

by:joghurt
ID: 11083887
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.
0
 

Author Comment

by:stitch2802
ID: 11089932
Joghurt,

Thanks for your feedback - so, in other words, instead of doing this:

HRESULT hr = StringCchCopy(process.UserName, sizeof(process.UserName), userName);

if (FAILED(hr))
     {
         return false;
     }

I should do this, instead:
if (FAILED(hr))
     {
        break;
     }

Let me know.

Thanks,
S/.



0
 
LVL 6

Expert Comment

by:joghurt
ID: 11091844
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<ProcessInfoEx *>(lParam));

     TCHAR userName[1024]= {0};
     TCHAR domainName[1024]= {0};

     DWORD userLen = sizeof(userName)/sizeof(userName[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.UserName, sizeof(process.UserName), userName);
               if (FAILED(hr))
                    ok = false;

               hr = StringCchCopy(process.Domain, domainLen, domainName);
               if (FAILED(hr))
                    ok = false;

               hr = StringCchCopy(process.ProcessName, sizeof(process.ProcessName), szProcess);
               if (FAILED(hr))
                    ok = false;
          }
          else
          {
               HRESULT hr = StringCchCopy(process.ProcessName,sizeof(process.ProcessName), szProcess);
               if (FAILED(hr))
                    ok = false;
          }
     }
     else { //if wtask == false
          HRESULT hr = StringCchCopy(process.ProcessName, 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;
}
0
 

Author Comment

by:stitch2802
ID: 11092343
Awesome, joghurt - thanks very much for your help!

=)
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

If you have ever found yourself doing a repetitive action with the mouse and keyboard, and if you have even a little programming experience, there is a good chance that you can use a text editor to whip together a sort of macro to automate the proce…
This article describes a technique for converting RTF (Rich Text Format) data to HTML and provides C++ source that does it all in just a few lines of code. Although RTF is coming to be considered a "legacy" format, it is still in common use... po…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

759 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

24 Experts available now in Live!

Get 1:1 Help Now