You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
699 lines
24 KiB
699 lines
24 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sysinfo.cpp
|
|
|
|
Abstract:
|
|
|
|
This module implements CSystemInfo, the class that returns various
|
|
system information
|
|
|
|
Author:
|
|
|
|
William Hsieh (williamh) created
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
|
|
#include "devmgr.h"
|
|
#include "sysinfo.h"
|
|
|
|
// disk drive root template name. Used to retreive the disk's media
|
|
// information or geometry
|
|
const TCHAR* const DRIVE_ROOT = TEXT("\\\\.\\?:");
|
|
const int DRIVE_LETTER_IN_DRIVE_ROOT = 4;
|
|
|
|
// disk drive root directory template name. Used to retreive the disk's
|
|
// total and free space
|
|
const TCHAR* const DRIVE_ROOT_DIR = TEXT("?:\\");
|
|
const int DRIVE_LETTER_IN_DRIVE_ROOT_DIR = 0;
|
|
|
|
//
|
|
// Registry various subkey and value names used to retreive
|
|
// system information
|
|
//
|
|
const TCHAR* const REG_PATH_HARDWARE_SYSTEM = TEXT("HARDWARE\\DESCRIPTION\\System");
|
|
const TCHAR* const REG_VALUE_SYSTEMBIOSDATE = TEXT("SystemBiosDate");
|
|
const TCHAR* const REG_VALUE_SYSTEMBIOSVERSION = TEXT("SystemBiosVersion");
|
|
const TCHAR* const REG_VALUE_MACHINETYPE = TEXT("Identifier");
|
|
|
|
const TCHAR* const REG_PATH_WINDOWS_NT = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
|
|
const TCHAR* const REG_VALUE_REGISTERED_OWNER = TEXT("RegisteredOwner");
|
|
const TCHAR* const REG_VALUE_REGISTERED_ORGANIZATION = TEXT("RegisteredOrganization");
|
|
const TCHAR* const REG_VALUE_CURRENTBUILDNUMBER = TEXT("CurrentBuildNumber");
|
|
const TCHAR* const REG_VALUE_CURRENTVERSION = TEXT("CurrentVersion");
|
|
const TCHAR* const REG_VALUE_CSDVERSION = TEXT("CSDVersion");
|
|
const TCHAR* const REG_PATH_CPU = TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor");
|
|
const TCHAR* const REG_VALUE_CPU_TYPE = TEXT("Identifier");
|
|
const TCHAR* const REG_VALUE_CPU_VENDOR = TEXT("VendorIdentifier");
|
|
|
|
CSystemInfo::CSystemInfo(
|
|
CMachine* pMachine
|
|
)
|
|
{
|
|
// assuming the machine is a local machine and initialize
|
|
// the registry root key as well.
|
|
m_hKeyMachine = HKEY_LOCAL_MACHINE;
|
|
|
|
if (pMachine) {
|
|
m_fLocalMachine = pMachine->IsLocal();
|
|
m_strComputerName += pMachine->GetMachineDisplayName();
|
|
} else {
|
|
TCHAR LocalName[MAX_PATH + 1];
|
|
DWORD dwSize = ARRAYLEN(LocalName);
|
|
|
|
if (!GetComputerName(LocalName, &dwSize)) {
|
|
|
|
LocalName[0] = _T('\0');
|
|
}
|
|
|
|
|
|
// local machine
|
|
m_fLocalMachine = TRUE;
|
|
m_strComputerName = LocalName;
|
|
}
|
|
|
|
if (!m_fLocalMachine) {
|
|
// The machine is not local, connect to the registry
|
|
String strFullComputerName;
|
|
|
|
strFullComputerName = (LPCTSTR)TEXT("\\\\");
|
|
strFullComputerName += m_strComputerName;
|
|
m_hKeyMachine = NULL;
|
|
RegConnectRegistry((LPCTSTR)strFullComputerName, HKEY_LOCAL_MACHINE, &m_hKeyMachine);
|
|
}
|
|
}
|
|
|
|
CSystemInfo::~CSystemInfo()
|
|
{
|
|
if (!m_fLocalMachine && NULL != m_hKeyMachine) {
|
|
RegCloseKey(m_hKeyMachine);
|
|
|
|
// disconnect the machine
|
|
WNetCancelConnection2(TEXT("\\server\\ipc$"), 0, TRUE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// This function gets the disk information about the given disk drive
|
|
// INPUT:
|
|
// Drive -- the drive number. 0 for A, 1 for B and etc.
|
|
// DiskInfo -- the DISK_INFO to be filled with the information about
|
|
// the drive. DiskInfo.cbSize must be initialized before
|
|
// the call.
|
|
// OUTPUT:
|
|
// TRUE -- if succeeded, DiskInfo is filled with information
|
|
// FALSE -- if the drive information can not be retreived.
|
|
// No appropriate error code is returned;
|
|
BOOL
|
|
CSystemInfo::GetDiskInfo(
|
|
int Drive,
|
|
DISK_INFO& DiskInfo
|
|
)
|
|
{
|
|
// diskinfo only valid on local computer
|
|
if (!m_fLocalMachine) {
|
|
return FALSE;
|
|
}
|
|
|
|
TCHAR DriveLetter;
|
|
TCHAR Root[MAX_PATH];
|
|
DriveLetter = (TCHAR)(_T('A') + Drive);
|
|
StringCchCopy(Root, ARRAYLEN(Root), DRIVE_ROOT_DIR);
|
|
Root[DRIVE_LETTER_IN_DRIVE_ROOT_DIR] = DriveLetter;
|
|
UINT DriveType;
|
|
DriveType = GetDriveType(Root);
|
|
|
|
//
|
|
// only valid for local drives
|
|
//
|
|
if (DRIVE_UNKNOWN == DriveType || DRIVE_REMOTE == DriveType ||
|
|
DRIVE_NO_ROOT_DIR == DriveType) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (DiskInfo.cbSize < sizeof(DISK_INFO)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// form the disk root name from template
|
|
//
|
|
StringCchCopy(Root, ARRAYLEN(Root), DRIVE_ROOT);
|
|
Root[DRIVE_LETTER_IN_DRIVE_ROOT] = DriveLetter;
|
|
HANDLE hDisk;
|
|
|
|
// FILE_READ_ATTRIBUTES is used here so that we will not get nasty
|
|
// error or prompt if the disk is a removable drive and there is no
|
|
// media available.
|
|
hDisk = CreateFile(Root,
|
|
FILE_READ_ATTRIBUTES | SYNCHRONIZE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL);
|
|
|
|
if (INVALID_HANDLE_VALUE != hDisk) {
|
|
// form the disk root directory name from template
|
|
StringCchCopy(Root, ARRAYLEN(Root), DRIVE_ROOT_DIR);
|
|
Root[DRIVE_LETTER_IN_DRIVE_ROOT_DIR] = DriveLetter;
|
|
BYTE Buffer[512];
|
|
DWORD BytesRequired = 0;
|
|
|
|
if (DeviceIoControl(hDisk, IOCTL_STORAGE_GET_MEDIA_TYPES_EX, NULL, 0,
|
|
Buffer, sizeof(Buffer), &BytesRequired, NULL)) {
|
|
GET_MEDIA_TYPES* pMediaList;
|
|
DEVICE_MEDIA_INFO* pMediaInfo;
|
|
pMediaList = (GET_MEDIA_TYPES*)Buffer;
|
|
pMediaInfo = pMediaList->MediaInfo;
|
|
DWORD MediaCount = pMediaList->MediaInfoCount;
|
|
ULARGE_INTEGER MaxSpace, NewSpace;
|
|
DEVICE_MEDIA_INFO* pMaxMediaInfo;
|
|
MaxSpace.QuadPart = 0;
|
|
pMaxMediaInfo = NULL;
|
|
|
|
for (DWORD i = 0; i < MediaCount; i++, pMediaInfo++) {
|
|
//
|
|
// find the mediainfo which has max space
|
|
// A disk drive may support multiple media types and the
|
|
// one with maximum capacity is what we want to report.
|
|
//
|
|
if (DRIVE_REMOVABLE == DriveType || DRIVE_CDROM == DriveType) {
|
|
NewSpace.QuadPart =
|
|
pMediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector *
|
|
pMediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack *
|
|
pMediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder *
|
|
pMediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart;
|
|
|
|
} else {
|
|
NewSpace.QuadPart =
|
|
pMediaInfo->DeviceSpecific.DiskInfo.BytesPerSector *
|
|
pMediaInfo->DeviceSpecific.DiskInfo.SectorsPerTrack *
|
|
pMediaInfo->DeviceSpecific.DiskInfo.TracksPerCylinder *
|
|
pMediaInfo->DeviceSpecific.DiskInfo.Cylinders.QuadPart;
|
|
}
|
|
|
|
if (NewSpace.QuadPart > MaxSpace.QuadPart) {
|
|
MaxSpace.QuadPart = NewSpace.QuadPart;
|
|
pMaxMediaInfo = pMediaInfo;
|
|
}
|
|
}
|
|
|
|
if (pMaxMediaInfo) {
|
|
//
|
|
// a valid media information is found, compose DISK_INFO
|
|
// from the media information
|
|
//
|
|
DiskInfo.DriveType = DriveType;
|
|
if (DRIVE_REMOVABLE == DriveType || DRIVE_CDROM == DriveType) {
|
|
DiskInfo.MediaType = pMaxMediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType;
|
|
DiskInfo.Cylinders = pMaxMediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders;
|
|
DiskInfo.Heads = pMaxMediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder;
|
|
DiskInfo.BytesPerSector = pMaxMediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector;
|
|
DiskInfo.SectorsPerTrack = pMaxMediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack;
|
|
|
|
//
|
|
// Do not call GetDiskFreeSpaceEx on removable disk
|
|
// or CD-ROM
|
|
//
|
|
DiskInfo.TotalSpace = MaxSpace;
|
|
DiskInfo.FreeSpace.QuadPart = (ULONGLONG)-1;
|
|
|
|
} else {
|
|
DiskInfo.MediaType = pMaxMediaInfo->DeviceSpecific.DiskInfo.MediaType;
|
|
DiskInfo.Cylinders = pMaxMediaInfo->DeviceSpecific.DiskInfo.Cylinders;
|
|
DiskInfo.Heads = pMaxMediaInfo->DeviceSpecific.DiskInfo.TracksPerCylinder;
|
|
DiskInfo.BytesPerSector = pMaxMediaInfo->DeviceSpecific.DiskInfo.BytesPerSector;
|
|
DiskInfo.SectorsPerTrack = pMaxMediaInfo->DeviceSpecific.DiskInfo.SectorsPerTrack;
|
|
StringCchCopy(Root, ARRAYLEN(Root), DRIVE_ROOT_DIR);
|
|
Root[DRIVE_LETTER_IN_DRIVE_ROOT_DIR] = DriveLetter;
|
|
ULARGE_INTEGER FreeSpaceForCaller;
|
|
|
|
if (!GetDiskFreeSpaceEx(Root, &FreeSpaceForCaller, &DiskInfo.TotalSpace, &DiskInfo.FreeSpace)) {
|
|
DiskInfo.TotalSpace = MaxSpace;
|
|
|
|
// unknown
|
|
DiskInfo.FreeSpace.QuadPart = (ULONGLONG)-1;
|
|
}
|
|
}
|
|
|
|
CloseHandle(hDisk);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// we wouldn't go here if the drive is not removable.
|
|
// Basically, this is for floppy drives only.
|
|
//
|
|
if (DRIVE_REMOVABLE == DriveType &&
|
|
DeviceIoControl(hDisk, IOCTL_DISK_GET_MEDIA_TYPES, NULL, 0,
|
|
Buffer, sizeof(Buffer), &BytesRequired, NULL)) {
|
|
int TotalMediaTypes = BytesRequired / sizeof(DISK_GEOMETRY);
|
|
DISK_GEOMETRY* pGeometry;
|
|
pGeometry = (DISK_GEOMETRY*)Buffer;
|
|
ULARGE_INTEGER MaxSpace;
|
|
ULARGE_INTEGER NewSpace;
|
|
MaxSpace.QuadPart = 0;
|
|
DISK_GEOMETRY* pMaxGeometry = NULL;
|
|
|
|
for (int i = 0; i < TotalMediaTypes; i++, pGeometry++) {
|
|
//
|
|
// find the geometry with maximum capacity
|
|
//
|
|
NewSpace.QuadPart = pGeometry->BytesPerSector *
|
|
pGeometry->SectorsPerTrack *
|
|
pGeometry->TracksPerCylinder *
|
|
pGeometry->Cylinders.QuadPart;
|
|
|
|
if (NewSpace.QuadPart > MaxSpace.QuadPart) {
|
|
pMaxGeometry = pGeometry;
|
|
MaxSpace = NewSpace;
|
|
}
|
|
}
|
|
|
|
if (pMaxGeometry) {
|
|
DiskInfo.DriveType = DriveType;
|
|
DiskInfo.MediaType = (STORAGE_MEDIA_TYPE)pMaxGeometry->MediaType;
|
|
DiskInfo.Cylinders = pMaxGeometry->Cylinders;
|
|
DiskInfo.Heads = pMaxGeometry->TracksPerCylinder;
|
|
DiskInfo.BytesPerSector = pMaxGeometry->BytesPerSector;
|
|
DiskInfo.SectorsPerTrack = pMaxGeometry->SectorsPerTrack;
|
|
DiskInfo.TotalSpace = MaxSpace;
|
|
DiskInfo.FreeSpace.QuadPart = (ULONGLONG)-1;
|
|
CloseHandle(hDisk);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
CloseHandle(hDisk);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// This functions retreive the Window version information in text string
|
|
// INPUT:
|
|
// Buffer -- buffer to receive the text string
|
|
// BufferSize -- buffer size in char(in bytes on ANSI version)
|
|
// OUTPUT:
|
|
// The size of the text string, not including the terminated NULL char
|
|
// If the returned value is 0, GetLastError will returns the error code.
|
|
// If the returned value is larger than BufferSize, Buffer is too small
|
|
//
|
|
DWORD
|
|
CSystemInfo::WindowsVersion(
|
|
TCHAR* Buffer,
|
|
DWORD BufferSize
|
|
)
|
|
{
|
|
if (!Buffer && BufferSize) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
String strFinalText;
|
|
TCHAR Temp[LINE_LEN];
|
|
|
|
strFinalText.Empty();
|
|
|
|
strFinalText.LoadString(g_hInstance, IDS_WINDOWS_NT);
|
|
|
|
CSafeRegistry regWindowsNT;
|
|
if (regWindowsNT.Open(m_hKeyMachine, REG_PATH_WINDOWS_NT, KEY_READ)) {
|
|
DWORD Type, Size;
|
|
Size = sizeof(Temp);
|
|
|
|
if (regWindowsNT.GetValue(REG_VALUE_CURRENTVERSION, &Type,
|
|
(PBYTE)Temp, &Size)) {
|
|
strFinalText += (LPCTSTR)Temp;
|
|
}
|
|
|
|
Size = sizeof(Temp);
|
|
|
|
if (regWindowsNT.GetValue(REG_VALUE_CSDVERSION, &Type,
|
|
(PBYTE)Temp, &Size) && Size) {
|
|
strFinalText += (LPCTSTR)TEXT(" ");
|
|
strFinalText += (LPCTSTR)Temp;
|
|
}
|
|
|
|
Size = sizeof(Temp);
|
|
|
|
if (regWindowsNT.GetValue(REG_VALUE_CURRENTBUILDNUMBER, &Type,
|
|
(PBYTE)Temp, &Size) && Size) {
|
|
String strBuildFormat;
|
|
strBuildFormat.LoadString(g_hInstance, IDS_BUILD_NUMBER);
|
|
|
|
String strBuild;
|
|
strBuild.Format((LPCTSTR)strBuildFormat, Temp);
|
|
|
|
strFinalText += strBuild;
|
|
}
|
|
}
|
|
|
|
if (BufferSize > (DWORD)strFinalText.GetLength()) {
|
|
StringCchCopy(Buffer, BufferSize, (LPCTSTR)strFinalText);
|
|
SetLastError(ERROR_SUCCESS);
|
|
}
|
|
|
|
else {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
return strFinalText.GetLength();
|
|
}
|
|
|
|
//
|
|
// This functions retreive a REG_SZ from the registry
|
|
// INPUT:
|
|
// SubkeyName -- registry subkey name.
|
|
// ValueName -- registry value name;
|
|
// Buffer -- buffer to receive the string
|
|
// BufferSize -- buffer size in char(in bytes on ANSI version)
|
|
// hKeyAncestory -- the key under which Subkeyname should be opened.
|
|
//
|
|
// OUTPUT:
|
|
// The size of the text string, not including the terminated NULL char
|
|
// If the returned value is 0, GetLastError will returns the error code.
|
|
// If the returned value is larger than BufferSize, Buffer is too small
|
|
//
|
|
DWORD
|
|
CSystemInfo::InfoFromRegistry(
|
|
LPCTSTR SubkeyName,
|
|
LPCTSTR ValueName,
|
|
TCHAR* Buffer,
|
|
DWORD BufferSize,
|
|
HKEY hKeyAncestor
|
|
)
|
|
{
|
|
// validate parameters
|
|
if (!SubkeyName || !ValueName || _T('\0') == *SubkeyName ||
|
|
_T('\0') == *SubkeyName || (!Buffer && BufferSize)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if (!hKeyAncestor) {
|
|
hKeyAncestor = m_hKeyMachine;
|
|
}
|
|
|
|
CSafeRegistry regSubkey;
|
|
|
|
if (regSubkey.Open(hKeyAncestor, SubkeyName, KEY_READ)) {
|
|
TCHAR Temp[MAX_PATH];
|
|
DWORD Type;
|
|
DWORD Size;
|
|
Size = sizeof(Temp);
|
|
|
|
if (regSubkey.GetValue(ValueName, &Type, (PBYTE)Temp, &Size) && Size) {
|
|
Size /= sizeof(TCHAR);
|
|
|
|
if (BufferSize > Size) {
|
|
StringCchCopy(Buffer, BufferSize, Temp);
|
|
}
|
|
|
|
return Size;
|
|
}
|
|
}
|
|
|
|
SetLastError(ERROR_SUCCESS);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// This functions retreive the system BIOS date information in text string
|
|
// INPUT:
|
|
// Buffer -- buffer to receive the text string
|
|
// BufferSize -- buffer size in char(in bytes on ANSI version)
|
|
// OUTPUT:
|
|
// The size of the text string, not including the terminated NULL char
|
|
// If the returned value is 0, GetLastError will returns the error code.
|
|
// If the returned value is larger than BufferSize, Buffer is too small
|
|
//
|
|
DWORD
|
|
CSystemInfo::SystemBiosDate(
|
|
TCHAR* Buffer,
|
|
DWORD BufferSize
|
|
)
|
|
{
|
|
return InfoFromRegistry(REG_PATH_HARDWARE_SYSTEM,
|
|
REG_VALUE_SYSTEMBIOSDATE,
|
|
Buffer, BufferSize);
|
|
}
|
|
|
|
|
|
//
|
|
// This functions retreive the system BIOS version information in text string
|
|
// INPUT:
|
|
// Buffer -- buffer to receive the text string
|
|
// BufferSize -- buffer size in char(in bytes on ANSI version)
|
|
// OUTPUT:
|
|
// The size of the text string, not including the terminated NULL char
|
|
// If the returned value is 0, GetLastError will returns the error code.
|
|
// If the returned value is larger than BufferSize, Buffer is too small
|
|
//
|
|
DWORD
|
|
CSystemInfo::SystemBiosVersion(
|
|
TCHAR* Buffer,
|
|
DWORD BufferSize
|
|
)
|
|
{
|
|
return InfoFromRegistry(REG_PATH_HARDWARE_SYSTEM,
|
|
REG_VALUE_SYSTEMBIOSVERSION,
|
|
Buffer, BufferSize);
|
|
|
|
}
|
|
|
|
//
|
|
// This functions retreive the machine type in text string
|
|
// INPUT:
|
|
// Buffer -- buffer to receive the text string
|
|
// BufferSize -- buffer size in char(in bytes on ANSI version)
|
|
// OUTPUT:
|
|
// The size of the text string, not including the terminated NULL char
|
|
// If the returned value is 0, GetLastError will returns the error code.
|
|
// If the returned value is larger than BufferSize, Buffer is too small
|
|
//
|
|
DWORD
|
|
CSystemInfo::MachineType(
|
|
TCHAR* Buffer,
|
|
DWORD BufferSize
|
|
)
|
|
{
|
|
return InfoFromRegistry(REG_PATH_HARDWARE_SYSTEM,
|
|
REG_VALUE_MACHINETYPE,
|
|
Buffer, BufferSize);
|
|
}
|
|
|
|
//
|
|
// This functions retreive the registered owner name
|
|
// INPUT:
|
|
// Buffer -- buffer to receive the text string
|
|
// BufferSize -- buffer size in char(in bytes on ANSI version)
|
|
// OUTPUT:
|
|
// The size of the text string, not including the terminated NULL char
|
|
// If the returned value is 0, GetLastError will returns the error code.
|
|
// If the returned value is larger than BufferSize, Buffer is too small
|
|
//
|
|
DWORD
|
|
CSystemInfo::RegisteredOwner(
|
|
TCHAR* Buffer,
|
|
DWORD BufferSize
|
|
)
|
|
{
|
|
return InfoFromRegistry(REG_PATH_WINDOWS_NT,
|
|
REG_VALUE_REGISTERED_OWNER,
|
|
Buffer,
|
|
BufferSize
|
|
);
|
|
}
|
|
|
|
//
|
|
// This functions retreive the registered organization name
|
|
// INPUT:
|
|
// Buffer -- buffer to receive the text string
|
|
// BufferSize -- buffer size in char(in bytes on ANSI version)
|
|
// OUTPUT:
|
|
// The size of the text string, not including the terminated NULL char
|
|
// If the returned value is 0, GetLastError will returns the error code.
|
|
// If the returned value is larger than BufferSize, Buffer is too small
|
|
//
|
|
DWORD
|
|
CSystemInfo::RegisteredOrganization(
|
|
TCHAR* Buffer,
|
|
DWORD BufferSize
|
|
)
|
|
{
|
|
return InfoFromRegistry(REG_PATH_WINDOWS_NT,
|
|
REG_VALUE_REGISTERED_ORGANIZATION,
|
|
Buffer,
|
|
BufferSize
|
|
);
|
|
}
|
|
|
|
// This function resturns the number of processors on the computer
|
|
// INPUT:
|
|
// NONE
|
|
// OUTPUT:
|
|
// Number of processor.
|
|
//
|
|
DWORD
|
|
CSystemInfo::NumberOfProcessors()
|
|
{
|
|
CSafeRegistry regCPU;
|
|
DWORD CPUs = 0;
|
|
|
|
if (regCPU.Open(m_hKeyMachine, REG_PATH_CPU, KEY_READ)) {
|
|
TCHAR SubkeyName[MAX_PATH + 1];
|
|
DWORD SubkeySize = ARRAYLEN(SubkeyName);
|
|
|
|
while (regCPU.EnumerateSubkey(CPUs, SubkeyName, &SubkeySize)) {
|
|
SubkeySize = ARRAYLEN(SubkeyName);
|
|
CPUs++;
|
|
}
|
|
}
|
|
|
|
return CPUs;
|
|
}
|
|
|
|
// This function returns the processor vendor in text string
|
|
// INPUT:
|
|
// Buffer -- buffer to receive the string
|
|
// BufferSize -- size of the buffer in char(bytes in ANSI)
|
|
// OUTPUT:
|
|
// The size of the text string, not including the terminated NULL char
|
|
// If the returned value is 0, GetLastError will returns the error code.
|
|
// If the returned value is larger than BufferSize, Buffer is too small
|
|
//
|
|
// The system assumes that all processor in the machine must
|
|
// have the same type, therefore, this function does not take
|
|
// processor number as a parameter.
|
|
DWORD
|
|
CSystemInfo::ProcessorVendor(
|
|
TCHAR* Buffer,
|
|
DWORD BufferSize
|
|
)
|
|
{
|
|
return ProcessorInfo(REG_VALUE_CPU_VENDOR, Buffer, BufferSize);
|
|
}
|
|
|
|
// This function returns the processor type in text string
|
|
// INPUT:
|
|
// Buffer -- buffer to receive the string
|
|
// BufferSize -- size of the buffer in char(bytes in ANSI)
|
|
// OUTPUT:
|
|
// The size of the text string, not including the terminated NULL char
|
|
// If the returned value is 0, GetLastError will returns the error code.
|
|
// If the returned value is larger than BufferSize, Buffer is too small
|
|
//
|
|
// The system assumes that all processor in the machine must
|
|
// have the same type, therefore, this function does not take
|
|
// processor number as a parameter.
|
|
DWORD
|
|
CSystemInfo::ProcessorType(
|
|
TCHAR* Buffer,
|
|
DWORD BufferSize
|
|
)
|
|
{
|
|
return ProcessorInfo(REG_VALUE_CPU_TYPE, Buffer, BufferSize);
|
|
}
|
|
|
|
DWORD
|
|
CSystemInfo::ProcessorInfo(
|
|
LPCTSTR ValueName,
|
|
TCHAR* Buffer,
|
|
DWORD BufferSize
|
|
)
|
|
{
|
|
if (!ValueName || (!Buffer && BufferSize)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
CSafeRegistry regCPU;
|
|
DWORD CPUIndex = 0;
|
|
TCHAR CPUInfo[MAX_PATH];
|
|
DWORD CPUInfoSize = 0;
|
|
DWORD Type;
|
|
|
|
if (regCPU.Open(m_hKeyMachine, REG_PATH_CPU, KEY_READ)) {
|
|
TCHAR CPUKey[MAX_PATH + 1];
|
|
DWORD Size;
|
|
Size = ARRAYLEN(CPUKey);
|
|
|
|
// loop through all cpus until we find something interesting
|
|
while (CPUInfoSize <= sizeof(TCHAR) &&
|
|
regCPU.EnumerateSubkey(CPUIndex, CPUKey, &Size)) {
|
|
CSafeRegistry regTheCPU;
|
|
|
|
if (regTheCPU.Open(regCPU, CPUKey, KEY_READ)) {
|
|
CPUInfoSize = sizeof(CPUInfo);
|
|
regTheCPU.GetValue(ValueName, &Type, (PBYTE)CPUInfo, &CPUInfoSize);
|
|
}
|
|
|
|
CPUIndex++;
|
|
}
|
|
|
|
// CPUInfoSize != 0 means we find something
|
|
if (CPUInfoSize > sizeof(TCHAR)) {
|
|
CPUInfoSize = CPUInfoSize / sizeof(TCHAR) - 1;
|
|
if (BufferSize > CPUInfoSize) {
|
|
StringCchCopy(Buffer, BufferSize, CPUInfo);
|
|
}
|
|
|
|
return CPUInfoSize;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// This function returns the total physical memeory in KB
|
|
// INPUT:
|
|
// NONE
|
|
// OUTPUT:
|
|
// Total Memory in KB
|
|
//
|
|
void
|
|
CSystemInfo::TotalPhysicalMemory(
|
|
ULARGE_INTEGER& Size
|
|
)
|
|
{
|
|
if (m_fLocalMachine) {
|
|
SYSTEM_BASIC_INFORMATION SysBasicInfo;
|
|
NTSTATUS Status;
|
|
Status = NtQuerySystemInformation(SystemBasicInformation,
|
|
(PVOID)&SysBasicInfo,
|
|
sizeof(SysBasicInfo),
|
|
NULL);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Size.QuadPart = Int32x32To64(SysBasicInfo.PageSize,
|
|
SysBasicInfo.NumberOfPhysicalPages
|
|
);
|
|
}
|
|
|
|
else {
|
|
MEMORYSTATUS MemoryStatus;
|
|
GlobalMemoryStatus(&MemoryStatus);
|
|
Size.LowPart = (ULONG)MemoryStatus.dwTotalPhys;
|
|
Size.HighPart = 0;
|
|
}
|
|
}
|
|
|
|
else {
|
|
Size.QuadPart = 0;
|
|
SetLastError(ERROR_SUCCESS);
|
|
}
|
|
}
|