Größe des Speichers eines Prozesses rausfinden



  • Hallo allerseits, ich schmiede gerade an einem Programm, ähnlich dem Taskmanager bei Win2000/XP:

    Bis jetzt kann ich ProzessID, Name, Zeiten, ThreadCounter und Priorität eines jeden Prozesses auslesen. Ich möchte aber auch noch die CPU-Zeit in % und den verwendeten Speicher (so wie im Taskmanager) darstellen. Jetzt bin ich leider mit meinem Latein am Ende.

    Die Win32 Funktion "GetProcessWorkingSetSize()" hilft mir da auch nicht so richtig.

    Hier erstmal mein Quellcode soweit:

    #include <vcl.h>
    #pragma hdrstop
    
    #include "Unit1.h"
    #include <windows.h>
    #include <tlhelp32.h>
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    
    typedef BOOL (WINAPI *TH32_PROCESS)(HANDLE hSnapShot, LPPROCESSENTRY32 lppe);
    
    static TH32_PROCESS pProcess32First = NULL;
    static TH32_PROCESS pProcess32Next = NULL;
    
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      HANDLE hSnapShot;
      HANDLE hProcess;
      PROCESSENTRY32 ProcEntry = {0};
      TTreeNode *Node;
      TFileTime CreationTime;
      TFileTime ExitTime;
      TFileTime KernelTime;
      TFileTime UserTime;
      TDateTime dtTempTime;
      int iThreadCnt;
    
      AnsiString sPriority;
    
      HINSTANCE hDll = LoadLibrary("kernel32.dll");
    
      pProcess32First=(TH32_PROCESS)GetProcAddress(hDll,"Process32First");
      pProcess32Next=(TH32_PROCESS)GetProcAddress(hDll,"Process32Next");
    
      TreeView1->Items->BeginUpdate();
    
      try
      {
          TreeView1->Items->Clear();
          TreeView1->Items->Add(NULL, "Processes");
    
          hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    
          if ((hSnapShot == 0) || (hSnapShot == INVALID_HANDLE_VALUE)) ShowMessage("ERROR: CreateToolhelp32Snapshot");
          else
          {
              ProcEntry.dwSize = sizeof (PROCESSENTRY32);
    
              if (!(pProcess32First (hSnapShot, &ProcEntry))) ShowMessage("ERROR: Process32First");
              else
              {
                  do
    	      {
                    Node = TreeView1->Items->GetFirstNode();
                    Node = TreeView1->Items->AddChild(Node, "("+IntToStr(ProcEntry.th32ProcessID)+") "+ExtractFileName(ProcEntry.szExeFile));
    
                    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, false, ProcEntry.th32ProcessID);
    
                    if (hProcess != 0)
                    {
                        if (!GetProcessTimes(hProcess, &CreationTime, &ExitTime, &KernelTime, &UserTime)) ShowMessage("ERROR: GetProcessTimes (Node: "+Node->Text+")");
                        else
                        {
                            switch (GetPriorityClass(hProcess))
                            {
                                   case HIGH_PRIORITY_CLASS     : sPriority = "high"; break;
                                   case IDLE_PRIORITY_CLASS     : sPriority = "idle"; break;
                                   case NORMAL_PRIORITY_CLASS   : sPriority = "normal"; break;
                                   case REALTIME_PRIORITY_CLASS : sPriority = "realtime"; break;
                            }
    
                            FileTime2DateTime(&CreationTime, &dtTempTime);
                            TreeView1->Items->AddChild(Node, "CreationTime: "+dtTempTime.DateString()+" : "+dtTempTime.TimeString());
                            FileTime2DateTime(&ExitTime, &dtTempTime);
                            TreeView1->Items->AddChild(Node, "ExitTime: "+dtTempTime.DateString()+" : "+dtTempTime.TimeString());
                            FileTime2DateTime(&KernelTime, &dtTempTime);
                            TreeView1->Items->AddChild(Node, "KernelTime: "+dtTempTime.DateString()+" : "+dtTempTime.TimeString());
                            FileTime2DateTime(&UserTime, &dtTempTime);
                            TreeView1->Items->AddChild(Node, "UserTime: "+dtTempTime.DateString()+" : "+dtTempTime.TimeString());
                            iThreadCnt = ProcEntry.cntThreads;
                            TreeView1->Items->AddChild(Node, "Threads: "+IntToStr(iThreadCnt));
                            TreeView1->Items->AddChild(Node, "Priority: "+sPriority);
                        }
    
                        CloseHandle(hProcess);
                    }
                  }
                  while (pProcess32Next (hSnapShot, &ProcEntry));
    
                  CloseHandle(hSnapShot);
              }
          }
      }
      __finally
      {
               TreeView1->Items->EndUpdate();
               Node = TreeView1->Items->GetFirstNode();
               Node->Expand(true);
      }
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm1::FileTime2DateTime(LPFILETIME lpFileTime, TDateTime* DateTime)
    {
        //** DEC VAR
        SYSTEMTIME SystemTime;
        //** FileTime ==> SystemTime
        FileTimeToSystemTime(lpFileTime,&SystemTime);
        //** SystemTime ==> DateTime
        *DateTime = SystemTimeToDateTime(SystemTime);
    }
    

    Die einzelnen Prozesse werden in einem TreeView+Childs (Eigenschaften) hinterlegt.

    Kann mir jemand helfen?



  • Und ab nach WinAPI! 😉



  • Du könntest einen Timer anlegen und dann immer über die Zeitdifferenzen von GetSystemTimes und GetProcessTimes den Prozentualen Anteil berechnen 🙂



  • Erstmal ist die Frage, ob du für XP/NT oder für 9x schreiben willst. Wenn's für XP sein soll, dann kannst du GetProcessMemoryInfo() benutzen. Ich habe das mal mit meinem eigenen Prozess versucht und eine gute Annäherung an den im Taskmanager angezeigten Wert im WorkingSetSize-Member der PROCESS_MEMORY_COUNTERS-Struktur beobachtet. Es waren lediglich 24 KB Abweichung. Aber IMMER genau diese 24. Du kannst das evtl. auch mal versuchen. Vielleicht bekommst du ja auch immer diesen Wert als Differenz hin. Dann kannst du diesen ja bei deiner Anzeige draufaddieren. Falls du die PSAPI.h nicht hast, wird dir folgendes weiterhelfen:

    typedef size_t SIZE_T;
    
    typedef struct _PROCESS_MEMORY_COUNTERS
    {
       DWORD cb;
       DWORD PageFaultCount;
       SIZE_T PeakWorkingSetSize;
       SIZE_T WorkingSetSize;
       SIZE_T QuotaPeakPagedPoolUsage;
       SIZE_T QuotaPagedPoolUsage;
       SIZE_T QuotaPeakNonPagedPoolUsage;
       SIZE_T QuotaNonPagedPoolUsage;
       SIZE_T PagefileUsage;
       SIZE_T PeakPagefileUsage;
    } PROCESS_MEMORY_COUNTERS, *PPROCESS_MEMORY_COUNTERS;
    
    typedef BOOL (WINAPI *LPPMI) (HANDLE, PPROCESS_MEMORY_COUNTERS, DWORD);
    
    int GetMemoryStatus()
    {
       DWORD id;
       HANDLE hProcess;
       HINSTANCE hDll;
    
       PROCESS_MEMORY_COUNTERS pmc;
       pmc.cb = sizeof(PROCESS_MEMORY_COUNTERS);
    
       hDll = LoadLibrary( TEXT("PSAPI.DLL") );
       if(hDll)
       {
          LPPMI GetProcessMemoryInfo = (LPPMI)GetProcAddress(hDll, "GetProcessMemoryInfo");
          if(GetProcessMemoryInfo)
          {
             id = GetCurrentProcessId();
             hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);
             if(hProcess)
             {
                GetProcessMemoryInfo(hProcess, &pmc, pmc.cb);
                CloseHandle(hProcess);
             }
             else
                ShowMessage("NOPE: OpenProcess");
          }
          else
             ShowMessage("NOPE: GetProcAddress");
    
          FreeLibrary(hDll);
       }
       else
          ShowMessage("NOPE: LoadLibrary");
    
       return (int)pmc.WorkingSetSize;
    }
    

    Jetzt hast du deine Struktur gefüllt.



  • @WebFritzi:

    Ok. Ich brauche das Proggie für Win2000/XP. Ich habe mal Deinen Vorschlag mit eingearbeitet. Soweit funktioniert das jetzt alles. Danke nochmal!

    Ich habe jetzt mal in der MSDN nachgeschaut, das steht noch so einiges interessantes drin ... 😉

    #include <vcl.h>
    #pragma hdrstop
    
    #include "Unit1.h"
    #include <windows.h>
    #include <tlhelp32.h>
    #include <Psapi.h>
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TfrmMain *frmMain;
    
    typedef BOOL (WINAPI *TH32_PROCESS)(HANDLE hSnapShot, LPPROCESSENTRY32 lppe);
    typedef BOOL (WINAPI *LPPMI) (HANDLE, PPROCESS_MEMORY_COUNTERS, DWORD);
    static TH32_PROCESS pProcess32First = NULL;
    static TH32_PROCESS pProcess32Next = NULL;
    
    //---------------------------------------------------------------------------
    __fastcall TfrmMain::TfrmMain(TComponent* Owner) : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TfrmMain::btnStartClick(TObject *Sender)
    {
      HANDLE hSnapShot;
      HANDLE hProcess;
      PROCESSENTRY32 ProcEntry = {0};
      ProcEntry.dwSize = sizeof (PROCESSENTRY32);
      PROCESS_MEMORY_COUNTERS pmc;
      pmc.cb = sizeof(PROCESS_MEMORY_COUNTERS);
      LPPMI GetProcessMemoryInfo;
      MEMORYSTATUSEX statex;
      statex.dwLength = sizeof (statex);
    
      TTreeNode *Node;
      TFileTime CreationTime;
      TFileTime ExitTime;
      TFileTime KernelTime;
      TFileTime UserTime;
      TDateTime dtTempTime;
      AnsiString sPriority;
      int iThreadCnt;
    
      // System-DLLs für die benötigten Funktionen laden
      HINSTANCE hDll = LoadLibrary("kernel32.dll");
      HINSTANCE hPMDll = LoadLibrary("PSAPI.DLL");
    
      try
      {
         if (hDll && hPMDll)
         {
            // Adressen der benötigten DLL-Funktionen ermitteln
            pProcess32First = (TH32_PROCESS)GetProcAddress(hDll, "Process32First");
            pProcess32Next = (TH32_PROCESS)GetProcAddress(hDll, "Process32Next");
            GetProcessMemoryInfo = (LPPMI)GetProcAddress(hPMDll, "GetProcessMemoryInfo");
    
            if (pProcess32First && pProcess32Next && GetProcessMemoryInfo)
            {
               // Treeview mit Daten füllen
               TreeView1->Items->BeginUpdate();
    
               TreeView1->Items->Clear();
               TreeView1->Items->Add(NULL, "Processes");
    
               // Snapshot erstellen
               hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    
               if ((hSnapShot == 0) || (hSnapShot == INVALID_HANDLE_VALUE)) ShowMessage("ERROR: CreateToolhelp32Snapshot");
               else
               {
                   // 1. Prozess ermitteln
                   if (!(pProcess32First (hSnapShot, &ProcEntry))) ShowMessage("ERROR: Process32First");
                   else
                   {
                       // Prozessliste solange durchsuchen, bis der letzt erreicht ist
                       do
                       {
                         Node = TreeView1->Items->GetFirstNode();
                         Node = TreeView1->Items->AddChild(Node, "("+IntToStr(ProcEntry.th32ProcessID)+") "+ExtractFileName(ProcEntry.szExeFile));
    
                         // Handle auf den jeweiligen Prozess holen
                         hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, false, ProcEntry.th32ProcessID);
    
                         if (hProcess != 0)
                         {
                             // Prozess-Zeiten ermitteln
                             if (!GetProcessTimes(hProcess, &CreationTime, &ExitTime, &KernelTime, &UserTime)) ShowMessage("ERROR: GetProcessTimes (Node: "+Node->Text+")");
                             else
                             {
                                 // Prozess-Priority holen
                                 switch (GetPriorityClass(hProcess))
                                 {
                                        case HIGH_PRIORITY_CLASS     : sPriority = "high"; break;
                                        case IDLE_PRIORITY_CLASS     : sPriority = "idle"; break;
                                        case NORMAL_PRIORITY_CLASS   : sPriority = "normal"; break;
                                        case REALTIME_PRIORITY_CLASS : sPriority = "realtime"; break;
                                 }
    
                                 // Memoryinfo für Prozess holen
                                 GetProcessMemoryInfo(hProcess, &pmc, pmc.cb);
    
                                 // Filetime (64Bit) in TDateTime umrechnen
                                 FileTime2DateTime(&CreationTime, &dtTempTime);
                                 // Daten in den Tree eintragen
                                 TreeView1->Items->AddChild(Node, "CreationTime: "+dtTempTime.DateString()+" : "+dtTempTime.TimeString());
                                 FileTime2DateTime(&ExitTime, &dtTempTime);
                                 TreeView1->Items->AddChild(Node, "ExitTime: "+dtTempTime.DateString()+" : "+dtTempTime.TimeString());
                                 FileTime2DateTime(&KernelTime, &dtTempTime);
                                 TreeView1->Items->AddChild(Node, "KernelTime: "+dtTempTime.DateString()+" : "+dtTempTime.TimeString());
                                 FileTime2DateTime(&UserTime, &dtTempTime);
                                 TreeView1->Items->AddChild(Node, "UserTime: "+dtTempTime.DateString()+" : "+dtTempTime.TimeString());
                                 iThreadCnt = ProcEntry.cntThreads;
                                 TreeView1->Items->AddChild(Node, "Threads: "+IntToStr(iThreadCnt));
                                 TreeView1->Items->AddChild(Node, "Priority: "+sPriority);
                                 TreeView1->Items->AddChild(Node, "Memory: "+IntToStr((int)pmc.WorkingSetSize)+" bytes");
                             }
    
                             CloseHandle(hProcess);
                         }
                       }
                       while (pProcess32Next (hSnapShot, &ProcEntry));
    
                       // Zum Schluss noch den Speicherstatus holen und in das Memo einfügen
                       GlobalMemoryStatusEx(&statex);
    
                       Memo1->Clear();
                       Memo1->Lines->Add("Memusage: "+IntToStr(statex.dwMemoryLoad)+"%");
                       Memo1->Lines->Add("phys. Mem: "+IntToStr((__int64)statex.ullTotalPhys)+" bytes");
                       Memo1->Lines->Add("avail. Mem: "+IntToStr((__int64)statex.ullAvailPhys)+" bytes");
                       Memo1->Lines->Add("total Page Mem: "+IntToStr((__int64)statex.ullTotalPhys)+" bytes");
                       Memo1->Lines->Add("avail Page Mem: "+IntToStr((__int64)statex.ullAvailPageFile)+" bytes");
                       Memo1->Lines->Add("total virtual Mem: "+IntToStr((__int64)statex.ullTotalVirtual)+" bytes");
                       Memo1->Lines->Add("avail virtual Mem: "+IntToStr((__int64)statex.ullAvailVirtual)+" bytes");
                       Memo1->Lines->Add("avail extended virtual Mem: "+IntToStr((__int64)statex.ullAvailExtendedVirtual)+" bytes");
    
                       CloseHandle(hSnapShot);
                   }
               }
            }
         }
         else ShowMessage("ERROR: kernel32.dll or PSAPI.DLL not found.");
      }
      __finally
      {
               TreeView1->Items->EndUpdate();
    
               // DLLs entladen
               if (hDll) FreeLibrary (hDll);
               if (hPMDll) FreeLibrary (hPMDll);
      }
    }
    //---------------------------------------------------------------------------
    // Funktion zum umrechnen von FileTime (64Bit) in TDateTime
    void __fastcall TfrmMain::FileTime2DateTime(LPFILETIME lpFileTime, TDateTime* DateTime)
    {
        //** DEC VAR
        SYSTEMTIME SystemTime;
        //** FileTime ==> SystemTime
        FileTimeToSystemTime(lpFileTime,&SystemTime);
        //** SystemTime ==> DateTime
        *DateTime = SystemTimeToDateTime(SystemTime);
    }
    

Anmelden zum Antworten