|
|
/*++
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); } }
|