text: #include <windows.h>
  #include <assert.h>
  #include <psapi.h>
  #include <stdio.h>
  #include <tchar.h>
  #include <time.h>
  #include <tlhelp32.h>
  #include "Shlwapi.h"
  
  #pragma comment(lib, "psapi.lib")
  #pragma comment(lib, "shlwapi.lib")
  
  int gQueryInterval = 5; // seconds
  time_t gDuration = 0;   // seconds
  LPTSTR gCommandLine;
  
  HRESULT ProcessArgs(int argc, TCHAR *argv[]);
  HRESULT PrintUsage();
  void UseImage(void (functionForQueryType(HANDLE)));
  void QueryContinuously(HANDLE hProcess);
  int EvalProcesses(HANDLE hProcess);
  time_t ElapsedTime(time_t startTime);
  
  int __cdecl _tmain (int argc, TCHAR *argv[])
  {
      HRESULT result = ProcessArgs(argc, argv);
      if (FAILED(result))
          return result;
  
      UseImage(QueryContinuously);
      return S_OK;
  }
  
  HRESULT ProcessArgs(int argc, TCHAR *argv[])
  {
      LPTSTR argument;
      for( int count = 1; count < argc; count++ ) {
          argument = argv[count] ;
          if (wcsstr(argument, _T("-h")) || wcsstr(argument, _T("--help")))
              return PrintUsage();
          else if (wcsstr(argument, _T("--exe"))) {
              gCommandLine = argv[++count];
          } else if (wcsstr(argument, _T("-i")) || 
              wcsstr(argument, _T("--interval"))) {
              gQueryInterval = _wtoi(argv[++count]);
              if (gQueryInterval < 1) {
                  printf("ERROR: invalid interval\n");
                  return E_INVALIDARG;
              }
          } else if (wcsstr(argument, _T("-d")) ||
              wcsstr(argument, _T("--duration"))) {
              gDuration = _wtoi(argv[++count]);
              if (gDuration < 1) {
                  printf("ERROR: invalid duration\n");
                  return E_INVALIDARG;
              }
          } else {
              _tprintf(_T("ERROR: unrecognized argument \"%s\"\n"), (LPCTSTR)argument);
              return PrintUsage();
          }
      }
      if (argc < 2 || !wcslen(gCommandLine) ) {
          printf("ERROR: executable path is required\n");
          return PrintUsage();
      }
      return S_OK;
  }
  
  HRESULT PrintUsage()
  {
      printf("record-memory-win --exe EXE_PATH\n");
      printf("    Launch an executable and print the memory usage (in Private Bytes)\n");
      printf("    of the process.\n\n");
      printf("Usage:\n");
      printf("-h [--help]         : Print usage\n");
      printf("--exe arg           : Launch specified image.  Required\n");
      printf("-i [--interval] arg : Print memory usage every arg seconds.  Default: 5 seconds\n");
      printf("-d [--duration] arg : Run for up to arg seconds.  Default: no limit\n\n");
      printf("Examples:\n");
      printf("    record-memory-win --exe \"C:\\Program Files\\Safari\\Safari.exe /newprocess\"\n");
      printf("    record-memory-win --exe \"Safari.exe /newprocess\" -i 10 -d 7200\n");
      printf("    NOTE: Close all other browser intances to ensure launching in a new process\n");
      printf("          Or, pass the /newprocess (or equivalent) argument to the browser\n");
      return E_FAIL;
  }
  
  unsigned int getMemoryInfo(DWORD processID)
  {
      unsigned int memInfo = 0;
      HANDLE hProcess;
      PROCESS_MEMORY_COUNTERS_EX pmc;
  
      hProcess = OpenProcess(  PROCESS_QUERY_INFORMATION |
                                      PROCESS_VM_READ,
                                      FALSE, processID );
      if (NULL == hProcess)
          return 0;
  
      if (GetProcessMemoryInfo( hProcess, (PPROCESS_MEMORY_COUNTERS)&pmc, sizeof(pmc))) {
          memInfo = (pmc.PrivateUsage);
      }
  
      CloseHandle( hProcess );
      return memInfo;
  }
  
  void printProcessInfo(DWORD processID)
  {
      TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
     
      // Get a handle to the process.
      HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
                                     PROCESS_VM_READ,
                                     FALSE, processID );
  
      // Get the process name.
      if (NULL != hProcess) {
          HMODULE hMod;       // An array that receives the list of module handles.
          DWORD cbNeeded;     //The number of bytes required to store all module handles in the Module array
  
          if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
              GetModuleBaseName(hProcess, hMod, szProcessName, 
                                 sizeof(szProcessName)/sizeof(TCHAR));
          }
      }
  
      // Print the process name and identifier of matching strings, ignoring case
      _tprintf(TEXT("%s  (PID: %u)\n"), szProcessName, processID);
      
      // Release the handle to the process.
      CloseHandle( hProcess );
  }
  
  int evalProcesses(HANDLE hProcess)
  {
      if (NULL == hProcess)
          return 0;
  
      unsigned int totalMemUsage = 0;
      DWORD processID = GetProcessId(hProcess);
    
      HANDLE hProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  
      PROCESSENTRY32 processEntry = { 0 };
      processEntry.dwSize = sizeof(PROCESSENTRY32);
  
      // Retrieves information about the first process encountered in a system snapshot
      if(Process32First(hProcessSnapshot, &processEntry)) {
          do {
              // if th32processID = processID, we are the parent process!  
              // if th32ParentProcessID = processID, we are a child process!
              if ((processEntry.th32ProcessID == processID) || (processEntry.th32ParentProcessID == processID)) {
                  unsigned int procMemUsage = 0;
                  // Record parent process memory
                  procMemUsage = getMemoryInfo(processEntry.th32ProcessID);
                  totalMemUsage += procMemUsage;
              }
            // Retrieves information about the next process recorded in a system snapshot.   
          } while(Process32Next(hProcessSnapshot, &processEntry));
      }
  
      CloseHandle(hProcessSnapshot);
      return totalMemUsage;
  }
  
  
  void UseImage(void (functionForQueryType(HANDLE)))
  {
      STARTUPINFO si = {0};
      si.cb = sizeof(STARTUPINFO);
      PROCESS_INFORMATION pi = {0};
  
      // Start the child process. 
      if(!CreateProcess( NULL,   // No module name (use command line)
          gCommandLine,        // Command line
          NULL,           // Process handle not inheritable
          NULL,           // Thread handle not inheritable
          FALSE,          // Set handle inheritance to FALSE
          0,              // No creation flags
          NULL,           // Use parent's environment block
          NULL,           // Use parent's starting directory 
          &si,            // Pointer to STARTUPINFO structure
          &pi ))          // Pointer to PROCESS_INFORMATION structure
          printf("CreateProcess failed (%d)\n", GetLastError());
      else {
          printf("Created process with id: %d\n", pi.dwProcessId);
          functionForQueryType(pi.hProcess);
          // Close process and thread handles. 
          CloseHandle( pi.hProcess );
          CloseHandle( pi.hThread );
      }
  }
  
  void QueryContinuously(HANDLE hProcess)
  {
      Sleep(2000); // give the process some time to launch
      bool pastDuration = false;
      time_t startTime = time(NULL);
      unsigned int memUsage = evalProcesses(hProcess);
      while(memUsage && !pastDuration) {
          printf( "%u\n", memUsage );
          Sleep(gQueryInterval*1000);
          memUsage = evalProcesses(hProcess);
          pastDuration = gDuration > 0 ? ElapsedTime(startTime) > gDuration : false;
      } 
  }
  
  // returns elapsed time in seconds
  time_t ElapsedTime(time_t startTime)
  {
      time_t currentTime = time(NULL);
      return currentTime - startTime;
  }
  