780 lines
26 KiB
C++
780 lines
26 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (C) 1997-1999 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_VALUE_PROCESSOR_SPEED = TEXT("~MHZ");
|
||
|
|
||
|
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_BUID_TYPE = TEXT("CurrentType");
|
||
|
const TCHAR* const REG_VALUE_SYSTEMROOT = TEXT("SystemRoot");
|
||
|
const TCHAR* const REG_VALUE_INSTALLDATE = TEXT("InstallDate");
|
||
|
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_SPEED = TEXT("~MHz");
|
||
|
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 = sizeof(LocalName) / sizeof(TCHAR);
|
||
|
|
||
|
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
|
||
|
TCHAR ComputerName[MAX_PATH];
|
||
|
|
||
|
// the api requires an LPTSTR instead of LPCTSTR!!!!
|
||
|
lstrcpy(ComputerName, TEXT("\\\\"));
|
||
|
lstrcat(ComputerName, (LPCTSTR)m_strComputerName);
|
||
|
m_hKeyMachine = NULL;
|
||
|
RegConnectRegistry(ComputerName, 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 = _T('A') + Drive;
|
||
|
lstrcpy(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
|
||
|
//
|
||
|
lstrcpy(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
|
||
|
lstrcpy(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 = -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;
|
||
|
lstrcpy(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 = -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 = -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;
|
||
|
}
|
||
|
|
||
|
TCHAR FinalText[1024];
|
||
|
TCHAR Temp[LINE_LEN];
|
||
|
TCHAR Build[128];
|
||
|
|
||
|
FinalText[0] = TEXT('\0');
|
||
|
|
||
|
LoadString(g_hInstance, IDS_WINDOWS_NT, FinalText, ARRAYLEN(FinalText));
|
||
|
LoadString(g_hInstance, IDS_BUILD_NUMBER, Build, ARRAYLEN(Build));
|
||
|
|
||
|
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)) {
|
||
|
lstrcat(FinalText, Temp);
|
||
|
}
|
||
|
|
||
|
Size = sizeof(Temp);
|
||
|
|
||
|
if (regWindowsNT.GetValue(REG_VALUE_CSDVERSION, &Type,
|
||
|
(PBYTE)Temp, &Size) && Size) {
|
||
|
lstrcat(FinalText, TEXT(" "));
|
||
|
lstrcat(FinalText, Temp);
|
||
|
}
|
||
|
|
||
|
Size = sizeof(Temp);
|
||
|
|
||
|
if (regWindowsNT.GetValue(REG_VALUE_CURRENTBUILDNUMBER, &Type,
|
||
|
(PBYTE)Temp, &Size) && Size) {
|
||
|
DWORD FinalLen = lstrlen(FinalText);
|
||
|
wsprintf(FinalText + FinalLen, Build, Temp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DWORD FinalLen = lstrlen(FinalText);
|
||
|
|
||
|
if (BufferSize > FinalLen) {
|
||
|
lstrcpyn(Buffer, FinalText, FinalLen + 1);
|
||
|
SetLastError(ERROR_SUCCESS);
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||
|
}
|
||
|
|
||
|
return FinalLen;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// 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)) {
|
||
|
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) {
|
||
|
lstrcpy(Buffer, 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) {
|
||
|
lstrcpyn(Buffer, CPUInfo, CPUInfoSize + 1);
|
||
|
}
|
||
|
|
||
|
return CPUInfoSize;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
DWORD
|
||
|
CSystemInfo::ProcessorType(
|
||
|
TCHAR* Buffer,
|
||
|
DWORD BufferSize
|
||
|
)
|
||
|
{
|
||
|
SYSTEM_INFO SysInfo;
|
||
|
GetSystemInfo(&SysInfo);
|
||
|
TCHAR Format[MAX_PATH];
|
||
|
TCHAR CPUType[MAX_PATH];
|
||
|
TCHAR Revision[128];
|
||
|
|
||
|
switch (SysInfo.wProcessorArchitecture) {
|
||
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
||
|
// decode the processor level and revision
|
||
|
if (3 == SysInfo.wProcessorLevel ||
|
||
|
4 == SysInfo.wProcessorLevel) {
|
||
|
int StringId = (3 == SysInfo.wProcessorLevel) ?
|
||
|
IDS_CPU_INTEL_386 : IDS_CPU_INTEL_486;
|
||
|
LoadString(g_hInstance, StringId, CPUType, ARRAYLEN(CPUType));
|
||
|
|
||
|
if (SysInfo.wProcessorRevision & 0xFF00 == 0xFF00) {
|
||
|
LoadString(g_hInstance, IDS_CPU_REVISION_MODEL_STEPPING,
|
||
|
Format, ARRAYLEN(Format));
|
||
|
wsprintf(Revision, Format,
|
||
|
((SysInfo.wProcessorRevision & 0x00F0) > 4) - 10,
|
||
|
SysInfo.wProcessorRevision & 0x000F);
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
LoadString(g_hInstance, IDS_CPU_REVISION_STEPPING,
|
||
|
Format, ARRAYLEN(Format));
|
||
|
wsprintf(Revision, Format,
|
||
|
(SysInfo.wProcessorRevision >> 8) + _T('A'),
|
||
|
SysInfo.wProcessorRevision & 0x00FF);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else if (5 == SysInfo.wProcessorLevel) {
|
||
|
LoadString(g_hInstance, IDS_CPU_INTEL_PENTIUM, CPUType, ARRAYLEN(CPUType));
|
||
|
LoadString(g_hInstance, IDS_CPU_REVISION_MODEL_STEPPING,
|
||
|
Format, ARRAYLEN(Format));
|
||
|
wsprintf(Revision, Format, SysInfo.wProcessorRevision >> 8,
|
||
|
SysInfo.wProcessorRevision & 0x00FF);
|
||
|
}
|
||
|
|
||
|
lstrcat(CPUType, Revision);
|
||
|
break;
|
||
|
|
||
|
case PROCESSOR_ARCHITECTURE_ALPHA:
|
||
|
LoadString(g_hInstance, IDS_CPU_ALPHA, Format, ARRAYLEN(Format));
|
||
|
wsprintf(CPUType, Format, SysInfo.wProcessorLevel);
|
||
|
LoadString(g_hInstance, IDS_CPU_REVISION_ALPHA, Format,
|
||
|
ARRAYLEN(Format));
|
||
|
wsprintf(Revision, Format, (SysInfo.wProcessorRevision >> 8) + _T('A'),
|
||
|
SysInfo.wProcessorRevision & 0x00FF);
|
||
|
lstrcat(CPUType, Revision);
|
||
|
|
||
|
default:
|
||
|
CPUType[0] = _T('\0');
|
||
|
}
|
||
|
|
||
|
DWORD Size = lstrlen(CPUType);
|
||
|
|
||
|
if (BufferSize > Size) {
|
||
|
lstrcpy(Buffer, CPUType);
|
||
|
}
|
||
|
|
||
|
SetLastError(ERROR_SUCCESS);
|
||
|
return Size;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
//
|
||
|
// 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);
|
||
|
}
|
||
|
}
|