I tried using PdhAddEnglishCounter but with no luck to get an external (another process) cpu usage. I only managed to get current process and for only 1 instance if another runs i get exceptions so i guess i am doing something wrong. I don't want to enumerate the whole list of processes to get the ones i want just to get the process info by PID or handle or exe name.
Code: Select all
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "MainU.h"
#include "Psapi.h"
#include <memory>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TMain *Main;
std::auto_ptr<TStringList> Config(new TStringList);
std::auto_ptr<TStringList> Logger(new TStringList);
//---------------------------------------------------------------------------
__fastcall TMain::TMain(TComponent* Owner)
: TForm(Owner)
{
//Extract app file path
AppPath = ExtractFilePath(ParamStr(0));
ConfigFile = AppPath + "Config.txt";
//load config settings to screen
if (FileExists(ConfigFile))
{
Config->LoadFromFile(ConfigFile);
Server->Text = Config->Values["Server"];
Port->Text = Config->Values["Port"].ToIntDef(25);
Mail->Text = Config->Values["Mail"];
}
//init performance counters
InitCPU();
//form server URL for later use
PrepareURL();
}
//---------------------------------------------------------------------------
void TMain::PrepareURL()
{
URL = "http://" + Server->Text.Trim() + ":" + Port->Text.Trim() + "/updateclient";
}
//---------------------------------------------------------------------------
void TMain::InitCPU()
{
//Creates a new query that is used to manage the collection of performance data.
PdhOpenQuery(NULL, NULL, &cpuQuery);
//Adds the specified language-neutral counter to the query.
PdhAddEnglishCounter(cpuQuery, L"\\Process(MachineStatisticsClient)\\% Processor Time", NULL, &cpuTotal);
/*
Collects the current raw data value for all
counters in the specified query and updates the
status code of each counter.
*/
PdhCollectQueryData(cpuQuery);
}
//---------------------------------------------------------------------------
int TMain::GetMemory()
{
//Retrieves information about the system's current usage of both physical and virtual memory.
GlobalMemoryStatus(&MemoryStatus);
//calculate used memory in percentage
double mem = MemoryStatus.dwTotalPhys - MemoryStatus.dwAvailPhys;
return (mem / MemoryStatus.dwTotalPhys) * 100;
}
//---------------------------------------------------------------------------
double TMain::GetCpuUsage()
{
PDH_FMT_COUNTERVALUE counterVal;
/*
Collects the current raw data value for all
counters in the specified query and updates the
status code of each counter.
*/
PdhCollectQueryData(cpuQuery);
//gets computes a displayable value for the specified counter.
PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);
return counterVal.doubleValue / 100.0;
}
//---------------------------------------------------------------------------
void __fastcall TMain::TimerTimer(TObject *Sender)
{
//Collect system info memory, cpu, processes
Mem = GetMemory();
Cpu = GetCpuUsage();
Pro = ProcessesCount();
//diplay them in labels
Memory->Caption = Format("Memory: %f%%",ARRAYOFCONST((Mem)));
CPUUsage->Caption = Format("CPU: %f%%",ARRAYOFCONST((Cpu)));
Processes->Caption = Format("Processes: %f",ARRAYOFCONST((Pro)));
//Display info on progress bars
MemBar->Position = Mem;
CPUBar->Position = (int)Cpu;
}
//---------------------------------------------------------------------------
int TMain::ProcessesCount()
{
//Retrieves the process identifier for each process object in the system.
if (!EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
{
return 1;
}
// Calculate how many process identifiers were returned.
return cbNeeded / sizeof(DWORD);
}
//---------------------------------------------------------------------------
void __fastcall TMain::StartStopClick(TObject *Sender)
{
//starts or stops the timers
Timer->Enabled = StartStop->Checked;
UpdateTimer->Enabled = StartStop->Checked;
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormDestroy(TObject *Sender)
{
Config->Values["Server"] = Server->Text;
Config->Values["Port"] = Port->Text;
Config->Values["Mail"] = Mail->Text;
Config->SaveToFile(ConfigFile);
}
//---------------------------------------------------------------------------
UnicodeString TMain::SendSysInfo(TStrings *ClientData)
{
std::auto_ptr<TMemoryStream> BodyStr(new TMemoryStream);
//sets mail, date, time in client data
ClientData->Values["Mail"] = Mail->Text.Trim();
ClientData->Values["Date"] = DateToStr(Date());
ClientData->Values["Time"] = TimeToStr(Time());
//save client data to memory stream & reset position
ClientData->SaveToStream(BodyStr.get());
BodyStr->Position = 0;
//Execute http POST request to server with ClientData as the request body
return HTTPClient->Post(URL,BodyStr.get())->ContentAsString();
}
//---------------------------------------------------------------------------
void __fastcall TMain::UpdateTimerTimer(TObject *Sender)
{
std::auto_ptr<TStringList> ClientData(new TStringList);
//Collect ClientData
ClientData->Values["ClientKey"] = THashBobJenkins::GetHashString(Mail->Text.Trim());
ClientData->Values["memory"] = Mem;
ClientData->Values["cpu"] = Cpu;
ClientData->Values["processes"] = Pro;
//Execute request and use ClientData to store response. Lazy hah
PrepareURL();
ClientData->Text = SendSysInfo(ClientData.get());
//Make response data to be in one line not 4 as sent by server, then logs the line
ClientData->LineBreak = ",";
LogEntry(ClientData->Text);
}
//---------------------------------------------------------------------------
void __fastcall TMain::HTTPClientRequestCompleted(TObject * const Sender, IHTTPResponse * const AResponse)
{
//on request error adds error message to log
if (AResponse->StatusCode != 200)
LogEntry(AResponse->ContentAsString());
}
//---------------------------------------------------------------------------
void __fastcall TMain::HTTPClientRequestError(TObject * const Sender, const UnicodeString AError)
{
//on request error adds error message to log
LogEntry(AError);
}
//---------------------------------------------------------------------------
void TMain::LogEntry(UnicodeString Text)
{
//Log Text and adding timestamp to the log entry
Logger->Add("[" + DateTimeToStr(Now()) +"] - " + Text);
Logger->SaveToFile(AppPath + "ClientLog.txt");
}
//---------------------------------------------------------------------------
Code: Select all
void InitProcessCPUUsage(HANDLE aProcess,
ULARGE_INTEGER &lastCPU,
ULARGE_INTEGER &lastSysCPU,
ULARGE_INTEGER &lastUserCPU)
{
SYSTEM_INFO sysInfo;
FILETIME ftime, fsys, fuser;
GetSystemInfo(&sysInfo);
CurNumProcessors = sysInfo.dwNumberOfProcessors;
GetSystemTimeAsFileTime(&ftime);
memcpy(&lastCPU, &ftime, sizeof(FILETIME));
GetProcessTimes(aProcess, &ftime, &ftime, &fsys, &fuser);
memcpy(&lastSysCPU, &fsys, sizeof(FILETIME));
memcpy(&lastUserCPU, &fuser, sizeof(FILETIME));
}
//---------------------------------------------------------------------------
double GetProcessCPUUsage(HANDLE aProcess,
ULARGE_INTEGER lastCPU,
ULARGE_INTEGER lastSysCPU,
ULARGE_INTEGER lastUserCPU)
{
FILETIME ftime, fsys, fuser;
ULARGE_INTEGER now, sys, user;
double percent;
GetSystemTimeAsFileTime(&ftime);
memcpy(&now, &ftime, sizeof(FILETIME));
GetProcessTimes(aProcess, &ftime, &ftime, &fsys, &fuser);
memcpy(&sys, &fsys, sizeof(FILETIME));
memcpy(&user, &fuser, sizeof(FILETIME));
percent = (sys.QuadPart - lastSysCPU.QuadPart) +
(user.QuadPart - lastUserCPU.QuadPart);
percent /= (now.QuadPart - lastCPU.QuadPart);
percent /= CurNumProcessors;
lastCPU = now;
lastUserCPU = user;
lastSysCPU = sys;
return percent * 100.0;
}
//---------------------------------------------------------------------------
Any help will be appreciated