Leaked source code of windows server 2003
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

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