취미 기록용 블로그

CPU, RAM, 네트워크, 하드디스크, 배터리 사용량 정보 구하는 코드

예전에 뭐땜시인지는 기억나지 않는데 CPU에 얼마나 여유가 있는지 확인하는 코드가 필요한적이 있었다.

그때 그 이유로 인터넷에서 여기저기 뒤쳐서 찾아놓은 샘플예제가 있었는데 지금 살펴보니 딱히 보기 좋은 상태가 아니라서(주석도 없고) 그냥 버리기엔 아깝고 해서 코드를 내 취향에 맞게 여기 정리해둠.

#include "SystemStatus.h"
#include <string>
#include <tchar.h>
 
CSystemStatus::CSystemStatus(void)
:m_hQuery(NULL),m_hCounterCPUTotal(NULL), m_CPUCoreCount(0), m_phCounterCPUCore(nullptr),m_NetAdaptorCount(0)
{
	
}

CSystemStatus::~CSystemStatus(void)
{
}

void
CSystemStatus::Init()
{
	PdhOpenQuery(NULL, 0, &m_hQuery);

	//CPU Total
	PdhAddCounter( m_hQuery, TEXT("\Processor(_Total)\% Processor Time"), 1, &m_hCounterCPUTotal );

	// CPU core 정보
	SYSTEM_INFO SystemInfo = { 0 };
	GetSystemInfo(&SystemInfo);
	if (SystemInfo.dwNumberOfProcessors > 0){
		m_CPUCoreCount = SystemInfo.dwNumberOfProcessors;
		m_phCounterCPUCore = new HCOUNTER[m_CPUCoreCount];
		for (int cnt = 0; cnt < m_CPUCoreCount; cnt++){
			TCHAR szFullCounterPath[1024] = { 0 };
			wsprintf(szFullCounterPath, TEXT("\Processor(%d)\%% Processor Time"), cnt);
			PdhAddCounter(m_hQuery, szFullCounterPath, 1, &m_phCounterCPUCore[cnt]);
		}
	}
	
	// 네트워크 카드
	DWORD pcchCounterListLength = 0, pcchInstanceListLength = 0 ;
	PdhEnumObjectItems( NULL, NULL, TEXT("Network Interface"), NULL, &pcchCounterListLength, NULL, &pcchInstanceListLength, PERF_DETAIL_WIZARD, 0 );	

	LPTSTR lpCounterList = new TCHAR[pcchCounterListLength];
	m_lpNetAdaptorList = new TCHAR[pcchInstanceListLength];
	if ( lpCounterList && m_lpNetAdaptorList ){
		/*HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionPerfliblangid */
		/*
		Bytes Total/sec
		Packets/sec
		Packets Received/sec
		Packets Sent/sec
		Current Bandwidth
		Bytes Received/sec
		Packets Received Unicast/sec
		Packets Received Non-Unicast/sec
		Packets Received Discarded
		Packets Received Errors
		Packets Received Unknown
		Bytes Sent/sec
		Packets Sent Unicast/sec
		Packets Sent Non-Unicast/sec
		Packets Outbound Discarded
		Packets Outbound Errors
		Output Queue Length
		Offloaded Connections
		TCP Active RSC Connections
		TCP RSC Coalesced Packets/sec
		TCP RSC Exceptions/sec
		TCP RSC Average Packet Size	*/
		
		PdhEnumObjectItems( NULL, NULL, TEXT("Network Interface"), lpCounterList, &pcchCounterListLength, m_lpNetAdaptorList, &pcchInstanceListLength, PERF_DETAIL_WIZARD, 0 );		

		TCHAR* pList = m_lpNetAdaptorList;
		m_NetAdaptorCount = 0;	//어댑터 갯수
		while (*pList) {
			m_NetAdaptorCount++;
			pList += (1 + _tcslen(pList));
		}

		m_phCounterNetAdaptor = new HCOUNTER[m_NetAdaptorCount];
		memset(m_phCounterNetAdaptor, 0, sizeof(HCOUNTER)*m_NetAdaptorCount);
		
		TCHAR* szInstanceName = m_lpNetAdaptorList;
		for (size_t cnt = 0; cnt < m_NetAdaptorCount; cnt++) {
			TCHAR szFullCounterPath[1024] = { 0 };
			DWORD dwFullPathSize = 1024;

			PDH_COUNTER_PATH_ELEMENTS pcpe = { 0 };
			pcpe.szObjectName = TEXT("Network Interface");
			pcpe.szInstanceName = szInstanceName;
			pcpe.dwInstanceIndex = -1;
			pcpe.szCounterName = TEXT("Bytes Total/sec");
			PdhMakeCounterPath(&pcpe, szFullCounterPath, &dwFullPathSize, 0);
			PdhAddCounter(m_hQuery, szFullCounterPath, 1, &m_phCounterNetAdaptor[cnt]);

			szInstanceName += (1 + _tcslen(szInstanceName));
		}
		delete lpCounterList;
	} 
}

void
CSystemStatus::getCPUStatus(LONG &total, LONG* arrCore, size_t arrCoreSize) {
	PDH_FMT_COUNTERVALUE PFC_Value = { 0 };
	PdhGetFormattedCounterValue(m_hCounterCPUTotal, PDH_FMT_LONG, NULL, &PFC_Value);
	total = PFC_Value.longValue;

	if (arrCore != nullptr && arrCoreSize > 0) {
		for (size_t c1 = 0; c1 < arrCoreSize; c1++){
			PDH_FMT_COUNTERVALUE PFC_Value = { 0 };
			PdhGetFormattedCounterValue(m_phCounterCPUCore[c1], PDH_FMT_LONG, NULL, &PFC_Value);
			arrCore[c1] = PFC_Value.longValue;
		}
	}
}

void
CSystemStatus::getRAMStatus(int &availableMem, int &physicalMem) {
	//메모리값
	MEMORYSTATUSEX MemoryStatus = {0};
	MemoryStatus.dwLength = sizeof (MemoryStatus);
	::GlobalMemoryStatusEx(&MemoryStatus);
	
	availableMem = (int)((MemoryStatus.ullTotalPhys - MemoryStatus.ullAvailPhys)/(1024*1024));
	physicalMem =  (int)((MemoryStatus.ullTotalPhys)/(1024*1024));
}

void
CSystemStatus::getNETStatus(LONG *adapTotalByte, size_t adaptorCount) {
	////네트워크
	PDH_FMT_COUNTERVALUE PFC_Value = { 0 };

	for (int cnt = 0; cnt < adaptorCount; cnt++) {
		PdhGetFormattedCounterValue(m_phCounterNetAdaptor[cnt], PDH_FMT_LONG, NULL, &PFC_Value);
		adapTotalByte[cnt] = PFC_Value.longValue;
	}
}

void
CSystemStatus::Update(){
	// 카운트 갱신
	PdhCollectQueryData( m_hQuery );
}

void
CSystemStatus::Terminate(){

	PdhRemoveCounter(m_hCounterCPUTotal);
	
	for (int cnt = 0; cnt < m_CPUCoreCount; cnt++)
		PdhRemoveCounter(m_phCounterCPUCore[cnt]);
	delete(m_phCounterCPUCore);

	for (int cnt = 0; cnt < m_NetAdaptorCount; cnt++)
		PdhRemoveCounter(m_phCounterNetAdaptor[cnt]);
	delete[] m_phCounterNetAdaptor;

	delete[] m_lpNetAdaptorList;
}

SystemStatus.cpp

#include <pdh.h>
#include <pdhmsg.h>
#include <Iphlpapi.h>
#pragma comment(lib, "pdh.lib")
#pragma comment(lib, "Iphlpapi.lib")

class CSystemStatus{
private:
		HQUERY					m_hQuery;

		size_t					m_CPUCoreCount;
		HCOUNTER				m_hCounterCPUTotal;	
		HCOUNTER*				m_phCounterCPUCore;		

		size_t					m_NetAdaptorCount;		//어댑터 갯수
		LPTSTR					m_lpNetAdaptorList;		//어댑터 이름 리스트
		HCOUNTER*				m_phCounterNetAdaptor;
		
public:
	CSystemStatus();
	~CSystemStatus(void);

	void	Init();
	void	Update();
	void	Terminate();
	
	size_t	getCPUCount() {	return m_CPUCoreCount;}
	void	getCPUStatus(LONG &total, LONG* arrCore, size_t arrCoreSize );
	void	getRAMStatus(int &availableMem, int &physicalMem); //단위:MB

	size_t			getNetAdaptorCount() { return m_NetAdaptorCount; }
	const LPTSTR	getNetAdatorList() { return m_lpNetAdaptorList;}
	void			getNETStatus(LONG *adapTotalByte, size_t adaptorCount);  

 };

SystemStatus.h

간단하게 설명하면 프로그램 실행시 Init(); 한번 실행해주고 프로그램 종료시에 Terminate(); 실행해주면 된다. 그리고 값 가져오기 전에 Update(); 한번 실행해주고 필요한 값 가져오면 됨.

다른것들에 대한걸 가져오고 싶으면 저 PdhAddCounter() 함수에 대해 여기저기 검색해보면 나옴.


//배터리 관련 정보
//https://msdn.microsoft.com/en-us/library/windows/desktop/aa373232(v=vs.85).aspx
SYSTEM_POWER_STATUS power_status = { 0 };
if (GetSystemPowerStatus(&power_status)) {

	if (power_status.BatteryFlag != 128) { //128 == No system battery
		if (power_status.ACLineStatus == 1)
			tmpLog.Format(TEXT("전원 연결중rn"));
		else
			tmpLog.Format(TEXT("배터리 사용중rn"));
		m_strEditOutput += tmpLog;

		tmpLog.Format(TEXT("배터리 충전률: %d%%rn"), power_status.BatteryLifePercent);
		m_strEditOutput += tmpLog;

		if (power_status.BatteryLifeTime != -1){
			int min = power_status.BatteryLifeTime / 60;
			if (min > 60)
				tmpLog.Format(TEXT("남은시간: %d시간 %d분rn"), min / 60, min % 60);
			else
				tmpLog.Format(TEXT("남은시간: %d분rn"), min);
		}
		else
			tmpLog.Format(TEXT("남은시간 계산중...rn"));
		m_strEditOutput += tmpLog;
	}
	else {
		tmpLog.Format(TEXT("No Batteryrn"));
		m_strEditOutput += tmpLog;
	}
}

배터리 관련 정보 구하는 코드


//하드디스크 
DWORD dwDrive = GetLogicalDrives();
DWORD dwDriveCh = 0x0001;
TCHAR DriveText[3] = { 0 };

for (TCHAR Drive = 'A'; Drive <= 'Z'; Drive++){
	wsprintf(DriveText, TEXT("%C:"), Drive);
	UINT type = GetDriveType(DriveText);
	if ((dwDrive & dwDriveCh) && (type == DRIVE_REMOVABLE || type == DRIVE_FIXED || type == DRIVE_RAMDISK)){
		// 하드용량			
		ULARGE_INTEGER i64FreeBytesToCaller = { 0 }, i64TotalBytes = { 0 }, i64FreeBytes = { 0 };
		BOOL bRsult = GetDiskFreeSpaceEx(DriveText, (PULARGE_INTEGER)&i64FreeBytesToCaller, (PULARGE_INTEGER)&i64TotalBytes, (PULARGE_INTEGER)&i64FreeBytes);
		if (bRsult){
			float ra = 1.0f - (float)(int)(i64FreeBytes.QuadPart >> 20) / (float)(int)(i64TotalBytes.QuadPart >> 20);
			tmpLog.Format(TEXT("%c: %I64d MB / %I64d MB(%d%%)rn"), Drive, i64FreeBytes.QuadPart >> 20, i64TotalBytes.QuadPart >> 20, (int)(ra * 100));
			m_strEditOutput += tmpLog;
		}
	}
	dwDriveCh <<= 1;
}

하드디스크 정보 구하는 코드


Comments

4의 “CPU, RAM, 네트워크, 하드디스크, 배터리 사용량 정보 구하는 코드”에 대한 답변

  1.  아바타
    익명

    좋네여

    1. Linsoo 아바타

      감사합니다.

  2. 수구리 아바타

    혹시 프로젝트는 mfc 프로젝트로 생성하고 edit Control하나를 만들어주고 변수 이름을 m_strEditOutput로 설정하신게 맞나욤?

    1. Linsoo 아바타

      네 맞습니다 맨위에 스샷에 결과 나오는 에디트박스가 m_strEditOutput랑 연결되어있습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. (이름과 이메일은 안써도 됩니다)

이 사이트는 Akismet을 사용하여 스팸을 줄입니다. 댓글 데이터가 어떻게 처리되는지 알아보세요.