Source code of Windows XP (NT5)
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.

779 lines
26 KiB

  1. /*++
  2. Copyright (C) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. sysinfo.cpp
  5. Abstract:
  6. This module implements CSystemInfo, the class that returns various
  7. system information
  8. Author:
  9. William Hsieh (williamh) created
  10. Revision History:
  11. --*/
  12. #include "devmgr.h"
  13. #include "sysinfo.h"
  14. // disk drive root template name. Used to retreive the disk's media
  15. // information or geometry
  16. const TCHAR* const DRIVE_ROOT = TEXT("\\\\.\\?:");
  17. const int DRIVE_LETTER_IN_DRIVE_ROOT = 4;
  18. // disk drive root directory template name. Used to retreive the disk's
  19. // total and free space
  20. const TCHAR* const DRIVE_ROOT_DIR = TEXT("?:\\");
  21. const int DRIVE_LETTER_IN_DRIVE_ROOT_DIR = 0;
  22. //
  23. // Registry various subkey and value names used to retreive
  24. // system information
  25. //
  26. const TCHAR* const REG_PATH_HARDWARE_SYSTEM = TEXT("HARDWARE\\DESCRIPTION\\System");
  27. const TCHAR* const REG_VALUE_SYSTEMBIOSDATE = TEXT("SystemBiosDate");
  28. const TCHAR* const REG_VALUE_SYSTEMBIOSVERSION = TEXT("SystemBiosVersion");
  29. const TCHAR* const REG_VALUE_MACHINETYPE = TEXT("Identifier");
  30. const TCHAR* const REG_VALUE_PROCESSOR_SPEED = TEXT("~MHZ");
  31. const TCHAR* const REG_PATH_WINDOWS_NT = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
  32. const TCHAR* const REG_VALUE_REGISTERED_OWNER = TEXT("RegisteredOwner");
  33. const TCHAR* const REG_VALUE_REGISTERED_ORGANIZATION = TEXT("RegisteredOrganization");
  34. const TCHAR* const REG_VALUE_BUID_TYPE = TEXT("CurrentType");
  35. const TCHAR* const REG_VALUE_SYSTEMROOT = TEXT("SystemRoot");
  36. const TCHAR* const REG_VALUE_INSTALLDATE = TEXT("InstallDate");
  37. const TCHAR* const REG_VALUE_CURRENTBUILDNUMBER = TEXT("CurrentBuildNumber");
  38. const TCHAR* const REG_VALUE_CURRENTVERSION = TEXT("CurrentVersion");
  39. const TCHAR* const REG_VALUE_CSDVERSION = TEXT("CSDVersion");
  40. const TCHAR* const REG_PATH_CPU = TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor");
  41. const TCHAR* const REG_VALUE_CPU_TYPE = TEXT("Identifier");
  42. const TCHAR* const REG_VALUE_CPU_SPEED = TEXT("~MHz");
  43. const TCHAR* const REG_VALUE_CPU_VENDOR = TEXT("VendorIdentifier");
  44. CSystemInfo::CSystemInfo(
  45. CMachine* pMachine
  46. )
  47. {
  48. // assuming the machine is a local machine and initialize
  49. // the registry root key as well.
  50. m_hKeyMachine = HKEY_LOCAL_MACHINE;
  51. if (pMachine) {
  52. m_fLocalMachine = pMachine->IsLocal();
  53. m_strComputerName += pMachine->GetMachineDisplayName();
  54. } else {
  55. TCHAR LocalName[MAX_PATH + 1];
  56. DWORD dwSize = sizeof(LocalName) / sizeof(TCHAR);
  57. if (!GetComputerName(LocalName, &dwSize)) {
  58. LocalName[0] = _T('\0');
  59. }
  60. // local machine
  61. m_fLocalMachine = TRUE;
  62. m_strComputerName = LocalName;
  63. }
  64. if (!m_fLocalMachine) {
  65. // The machine is not local, connect to the registry
  66. TCHAR ComputerName[MAX_PATH];
  67. // the api requires an LPTSTR instead of LPCTSTR!!!!
  68. lstrcpy(ComputerName, TEXT("\\\\"));
  69. lstrcat(ComputerName, (LPCTSTR)m_strComputerName);
  70. m_hKeyMachine = NULL;
  71. RegConnectRegistry(ComputerName, HKEY_LOCAL_MACHINE, &m_hKeyMachine);
  72. }
  73. }
  74. CSystemInfo::~CSystemInfo()
  75. {
  76. if (!m_fLocalMachine && NULL != m_hKeyMachine) {
  77. RegCloseKey(m_hKeyMachine);
  78. // disconnect the machine
  79. WNetCancelConnection2(TEXT("\\server\\ipc$"), 0, TRUE);
  80. }
  81. }
  82. //
  83. // This function gets the disk information about the given disk drive
  84. // INPUT:
  85. // Drive -- the drive number. 0 for A, 1 for B and etc.
  86. // DiskInfo -- the DISK_INFO to be filled with the information about
  87. // the drive. DiskInfo.cbSize must be initialized before
  88. // the call.
  89. // OUTPUT:
  90. // TRUE -- if succeeded, DiskInfo is filled with information
  91. // FALSE -- if the drive information can not be retreived.
  92. // No appropriate error code is returned;
  93. BOOL
  94. CSystemInfo::GetDiskInfo(
  95. int Drive,
  96. DISK_INFO& DiskInfo
  97. )
  98. {
  99. // diskinfo only valid on local computer
  100. if (!m_fLocalMachine) {
  101. return FALSE;
  102. }
  103. TCHAR DriveLetter;
  104. TCHAR Root[MAX_PATH];
  105. DriveLetter = _T('A') + Drive;
  106. lstrcpy(Root, DRIVE_ROOT_DIR);
  107. Root[DRIVE_LETTER_IN_DRIVE_ROOT_DIR] = DriveLetter;
  108. UINT DriveType;
  109. DriveType = GetDriveType(Root);
  110. //
  111. // only valid for local drives
  112. //
  113. if (DRIVE_UNKNOWN == DriveType || DRIVE_REMOTE == DriveType ||
  114. DRIVE_NO_ROOT_DIR == DriveType) {
  115. return FALSE;
  116. }
  117. if (DiskInfo.cbSize < sizeof(DISK_INFO)) {
  118. SetLastError(ERROR_INVALID_PARAMETER);
  119. return FALSE;
  120. }
  121. //
  122. // form the disk root name from template
  123. //
  124. lstrcpy(Root, DRIVE_ROOT);
  125. Root[DRIVE_LETTER_IN_DRIVE_ROOT] = DriveLetter;
  126. HANDLE hDisk;
  127. // FILE_READ_ATTRIBUTES is used here so that we will not get nasty
  128. // error or prompt if the disk is a removable drive and there is no
  129. // media available.
  130. hDisk = CreateFile(Root,
  131. FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  132. FILE_SHARE_READ | FILE_SHARE_WRITE,
  133. NULL,
  134. OPEN_EXISTING,
  135. 0,
  136. NULL);
  137. if (INVALID_HANDLE_VALUE != hDisk) {
  138. // form the disk root directory name from template
  139. lstrcpy(Root, DRIVE_ROOT_DIR);
  140. Root[DRIVE_LETTER_IN_DRIVE_ROOT_DIR] = DriveLetter;
  141. BYTE Buffer[512];
  142. DWORD BytesRequired = 0;
  143. if (DeviceIoControl(hDisk, IOCTL_STORAGE_GET_MEDIA_TYPES_EX, NULL, 0,
  144. Buffer, sizeof(Buffer), &BytesRequired, NULL)) {
  145. GET_MEDIA_TYPES* pMediaList;
  146. DEVICE_MEDIA_INFO* pMediaInfo;
  147. pMediaList = (GET_MEDIA_TYPES*)Buffer;
  148. pMediaInfo = pMediaList->MediaInfo;
  149. DWORD MediaCount = pMediaList->MediaInfoCount;
  150. ULARGE_INTEGER MaxSpace, NewSpace;
  151. DEVICE_MEDIA_INFO* pMaxMediaInfo;
  152. MaxSpace.QuadPart = 0;
  153. pMaxMediaInfo = NULL;
  154. for (DWORD i = 0; i < MediaCount; i++, pMediaInfo++) {
  155. //
  156. // find the mediainfo which has max space
  157. // A disk drive may support multiple media types and the
  158. // one with maximum capacity is what we want to report.
  159. //
  160. if (DRIVE_REMOVABLE == DriveType || DRIVE_CDROM == DriveType) {
  161. NewSpace.QuadPart =
  162. pMediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector *
  163. pMediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack *
  164. pMediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder *
  165. pMediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart;
  166. } else {
  167. NewSpace.QuadPart =
  168. pMediaInfo->DeviceSpecific.DiskInfo.BytesPerSector *
  169. pMediaInfo->DeviceSpecific.DiskInfo.SectorsPerTrack *
  170. pMediaInfo->DeviceSpecific.DiskInfo.TracksPerCylinder *
  171. pMediaInfo->DeviceSpecific.DiskInfo.Cylinders.QuadPart;
  172. }
  173. if (NewSpace.QuadPart > MaxSpace.QuadPart) {
  174. MaxSpace.QuadPart = NewSpace.QuadPart;
  175. pMaxMediaInfo = pMediaInfo;
  176. }
  177. }
  178. if (pMaxMediaInfo) {
  179. //
  180. // a valid media information is found, compose DISK_INFO
  181. // from the media information
  182. //
  183. DiskInfo.DriveType = DriveType;
  184. if (DRIVE_REMOVABLE == DriveType || DRIVE_CDROM == DriveType) {
  185. DiskInfo.MediaType = pMaxMediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType;
  186. DiskInfo.Cylinders = pMaxMediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders;
  187. DiskInfo.Heads = pMaxMediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder;
  188. DiskInfo.BytesPerSector = pMaxMediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector;
  189. DiskInfo.SectorsPerTrack = pMaxMediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack;
  190. //
  191. // Do not call GetDiskFreeSpaceEx on removable disk
  192. // or CD-ROM
  193. //
  194. DiskInfo.TotalSpace = MaxSpace;
  195. DiskInfo.FreeSpace.QuadPart = -1;
  196. } else {
  197. DiskInfo.MediaType = pMaxMediaInfo->DeviceSpecific.DiskInfo.MediaType;
  198. DiskInfo.Cylinders = pMaxMediaInfo->DeviceSpecific.DiskInfo.Cylinders;
  199. DiskInfo.Heads = pMaxMediaInfo->DeviceSpecific.DiskInfo.TracksPerCylinder;
  200. DiskInfo.BytesPerSector = pMaxMediaInfo->DeviceSpecific.DiskInfo.BytesPerSector;
  201. DiskInfo.SectorsPerTrack = pMaxMediaInfo->DeviceSpecific.DiskInfo.SectorsPerTrack;
  202. lstrcpy(Root, DRIVE_ROOT_DIR);
  203. Root[DRIVE_LETTER_IN_DRIVE_ROOT_DIR] = DriveLetter;
  204. ULARGE_INTEGER FreeSpaceForCaller;
  205. if (!GetDiskFreeSpaceEx(Root, &FreeSpaceForCaller, &DiskInfo.TotalSpace, &DiskInfo.FreeSpace)) {
  206. DiskInfo.TotalSpace = MaxSpace;
  207. // unknown
  208. DiskInfo.FreeSpace.QuadPart = -1;
  209. }
  210. }
  211. CloseHandle(hDisk);
  212. return TRUE;
  213. }
  214. }
  215. //
  216. // we wouldn't go here if the drive is not removable.
  217. // Basically, this is for floppy drives only.
  218. //
  219. if (DRIVE_REMOVABLE == DriveType &&
  220. DeviceIoControl(hDisk, IOCTL_DISK_GET_MEDIA_TYPES, NULL, 0,
  221. Buffer, sizeof(Buffer), &BytesRequired, NULL)) {
  222. int TotalMediaTypes = BytesRequired / sizeof(DISK_GEOMETRY);
  223. DISK_GEOMETRY* pGeometry;
  224. pGeometry = (DISK_GEOMETRY*)Buffer;
  225. ULARGE_INTEGER MaxSpace;
  226. ULARGE_INTEGER NewSpace;
  227. MaxSpace.QuadPart = 0;
  228. DISK_GEOMETRY* pMaxGeometry = NULL;
  229. for (int i = 0; i < TotalMediaTypes; i++, pGeometry++) {
  230. //
  231. // find the geometry with maximum capacity
  232. //
  233. NewSpace.QuadPart = pGeometry->BytesPerSector *
  234. pGeometry->SectorsPerTrack *
  235. pGeometry->TracksPerCylinder *
  236. pGeometry->Cylinders.QuadPart;
  237. if (NewSpace.QuadPart > MaxSpace.QuadPart) {
  238. pMaxGeometry = pGeometry;
  239. MaxSpace = NewSpace;
  240. }
  241. }
  242. if (pMaxGeometry) {
  243. DiskInfo.DriveType = DriveType;
  244. DiskInfo.MediaType = (STORAGE_MEDIA_TYPE)pMaxGeometry->MediaType;
  245. DiskInfo.Cylinders = pMaxGeometry->Cylinders;
  246. DiskInfo.Heads = pMaxGeometry->TracksPerCylinder;
  247. DiskInfo.BytesPerSector = pMaxGeometry->BytesPerSector;
  248. DiskInfo.SectorsPerTrack = pMaxGeometry->SectorsPerTrack;
  249. DiskInfo.TotalSpace = MaxSpace;
  250. DiskInfo.FreeSpace.QuadPart = -1;
  251. CloseHandle(hDisk);
  252. return TRUE;
  253. }
  254. }
  255. CloseHandle(hDisk);
  256. }
  257. return FALSE;
  258. }
  259. //
  260. // This functions retreive the Window version information in text string
  261. // INPUT:
  262. // Buffer -- buffer to receive the text string
  263. // BufferSize -- buffer size in char(in bytes on ANSI version)
  264. // OUTPUT:
  265. // The size of the text string, not including the terminated NULL char
  266. // If the returned value is 0, GetLastError will returns the error code.
  267. // If the returned value is larger than BufferSize, Buffer is too small
  268. //
  269. DWORD
  270. CSystemInfo::WindowsVersion(
  271. TCHAR* Buffer,
  272. DWORD BufferSize
  273. )
  274. {
  275. if (!Buffer && BufferSize) {
  276. SetLastError(ERROR_INVALID_PARAMETER);
  277. return 0;
  278. }
  279. TCHAR FinalText[1024];
  280. TCHAR Temp[LINE_LEN];
  281. TCHAR Build[128];
  282. FinalText[0] = TEXT('\0');
  283. LoadString(g_hInstance, IDS_WINDOWS_NT, FinalText, ARRAYLEN(FinalText));
  284. LoadString(g_hInstance, IDS_BUILD_NUMBER, Build, ARRAYLEN(Build));
  285. CSafeRegistry regWindowsNT;
  286. if (regWindowsNT.Open(m_hKeyMachine, REG_PATH_WINDOWS_NT, KEY_READ)) {
  287. DWORD Type, Size;
  288. Size = sizeof(Temp);
  289. if (regWindowsNT.GetValue(REG_VALUE_CURRENTVERSION, &Type,
  290. (PBYTE)Temp, &Size)) {
  291. lstrcat(FinalText, Temp);
  292. }
  293. Size = sizeof(Temp);
  294. if (regWindowsNT.GetValue(REG_VALUE_CSDVERSION, &Type,
  295. (PBYTE)Temp, &Size) && Size) {
  296. lstrcat(FinalText, TEXT(" "));
  297. lstrcat(FinalText, Temp);
  298. }
  299. Size = sizeof(Temp);
  300. if (regWindowsNT.GetValue(REG_VALUE_CURRENTBUILDNUMBER, &Type,
  301. (PBYTE)Temp, &Size) && Size) {
  302. DWORD FinalLen = lstrlen(FinalText);
  303. wsprintf(FinalText + FinalLen, Build, Temp);
  304. }
  305. }
  306. DWORD FinalLen = lstrlen(FinalText);
  307. if (BufferSize > FinalLen) {
  308. lstrcpyn(Buffer, FinalText, FinalLen + 1);
  309. SetLastError(ERROR_SUCCESS);
  310. }
  311. else {
  312. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  313. }
  314. return FinalLen;
  315. }
  316. //
  317. // This functions retreive a REG_SZ from the registry
  318. // INPUT:
  319. // SubkeyName -- registry subkey name.
  320. // ValueName -- registry value name;
  321. // Buffer -- buffer to receive the string
  322. // BufferSize -- buffer size in char(in bytes on ANSI version)
  323. // hKeyAncestory -- the key under which Subkeyname should be opened.
  324. //
  325. // OUTPUT:
  326. // The size of the text string, not including the terminated NULL char
  327. // If the returned value is 0, GetLastError will returns the error code.
  328. // If the returned value is larger than BufferSize, Buffer is too small
  329. //
  330. DWORD
  331. CSystemInfo::InfoFromRegistry(
  332. LPCTSTR SubkeyName,
  333. LPCTSTR ValueName,
  334. TCHAR* Buffer,
  335. DWORD BufferSize,
  336. HKEY hKeyAncestor
  337. )
  338. {
  339. // validate parameters
  340. if (!SubkeyName || !ValueName || _T('\0') == *SubkeyName ||
  341. _T('\0') == *SubkeyName || (!Buffer && BufferSize)) {
  342. SetLastError(ERROR_INVALID_PARAMETER);
  343. return 0;
  344. }
  345. if (!hKeyAncestor) {
  346. hKeyAncestor = m_hKeyMachine;
  347. }
  348. CSafeRegistry regSubkey;
  349. if (regSubkey.Open(hKeyAncestor, SubkeyName)) {
  350. TCHAR Temp[MAX_PATH];
  351. DWORD Type;
  352. DWORD Size;
  353. Size = sizeof(Temp);
  354. if (regSubkey.GetValue(ValueName, &Type, (PBYTE)Temp, &Size) && Size) {
  355. Size /= sizeof(TCHAR);
  356. if (BufferSize > Size) {
  357. lstrcpy(Buffer, Temp);
  358. }
  359. return Size;
  360. }
  361. }
  362. SetLastError(ERROR_SUCCESS);
  363. return 0;
  364. }
  365. //
  366. // This functions retreive the system BIOS date information in text string
  367. // INPUT:
  368. // Buffer -- buffer to receive the text string
  369. // BufferSize -- buffer size in char(in bytes on ANSI version)
  370. // OUTPUT:
  371. // The size of the text string, not including the terminated NULL char
  372. // If the returned value is 0, GetLastError will returns the error code.
  373. // If the returned value is larger than BufferSize, Buffer is too small
  374. //
  375. DWORD
  376. CSystemInfo::SystemBiosDate(
  377. TCHAR* Buffer,
  378. DWORD BufferSize
  379. )
  380. {
  381. return InfoFromRegistry(REG_PATH_HARDWARE_SYSTEM,
  382. REG_VALUE_SYSTEMBIOSDATE,
  383. Buffer, BufferSize);
  384. }
  385. //
  386. // This functions retreive the system BIOS version information in text string
  387. // INPUT:
  388. // Buffer -- buffer to receive the text string
  389. // BufferSize -- buffer size in char(in bytes on ANSI version)
  390. // OUTPUT:
  391. // The size of the text string, not including the terminated NULL char
  392. // If the returned value is 0, GetLastError will returns the error code.
  393. // If the returned value is larger than BufferSize, Buffer is too small
  394. //
  395. DWORD
  396. CSystemInfo::SystemBiosVersion(
  397. TCHAR* Buffer,
  398. DWORD BufferSize
  399. )
  400. {
  401. return InfoFromRegistry(REG_PATH_HARDWARE_SYSTEM,
  402. REG_VALUE_SYSTEMBIOSVERSION,
  403. Buffer, BufferSize);
  404. }
  405. //
  406. // This functions retreive the machine type in text string
  407. // INPUT:
  408. // Buffer -- buffer to receive the text string
  409. // BufferSize -- buffer size in char(in bytes on ANSI version)
  410. // OUTPUT:
  411. // The size of the text string, not including the terminated NULL char
  412. // If the returned value is 0, GetLastError will returns the error code.
  413. // If the returned value is larger than BufferSize, Buffer is too small
  414. //
  415. DWORD
  416. CSystemInfo::MachineType(
  417. TCHAR* Buffer,
  418. DWORD BufferSize
  419. )
  420. {
  421. return InfoFromRegistry(REG_PATH_HARDWARE_SYSTEM,
  422. REG_VALUE_MACHINETYPE,
  423. Buffer, BufferSize);
  424. }
  425. //
  426. // This functions retreive the registered owner name
  427. // INPUT:
  428. // Buffer -- buffer to receive the text string
  429. // BufferSize -- buffer size in char(in bytes on ANSI version)
  430. // OUTPUT:
  431. // The size of the text string, not including the terminated NULL char
  432. // If the returned value is 0, GetLastError will returns the error code.
  433. // If the returned value is larger than BufferSize, Buffer is too small
  434. //
  435. DWORD
  436. CSystemInfo::RegisteredOwner(
  437. TCHAR* Buffer,
  438. DWORD BufferSize
  439. )
  440. {
  441. return InfoFromRegistry(REG_PATH_WINDOWS_NT,
  442. REG_VALUE_REGISTERED_OWNER,
  443. Buffer,
  444. BufferSize
  445. );
  446. }
  447. //
  448. // This functions retreive the registered organization name
  449. // INPUT:
  450. // Buffer -- buffer to receive the text string
  451. // BufferSize -- buffer size in char(in bytes on ANSI version)
  452. // OUTPUT:
  453. // The size of the text string, not including the terminated NULL char
  454. // If the returned value is 0, GetLastError will returns the error code.
  455. // If the returned value is larger than BufferSize, Buffer is too small
  456. //
  457. DWORD
  458. CSystemInfo::RegisteredOrganization(
  459. TCHAR* Buffer,
  460. DWORD BufferSize
  461. )
  462. {
  463. return InfoFromRegistry(REG_PATH_WINDOWS_NT,
  464. REG_VALUE_REGISTERED_ORGANIZATION,
  465. Buffer,
  466. BufferSize
  467. );
  468. }
  469. // This function resturns the number of processors on the computer
  470. // INPUT:
  471. // NONE
  472. // OUTPUT:
  473. // Number of processor.
  474. //
  475. DWORD
  476. CSystemInfo::NumberOfProcessors()
  477. {
  478. CSafeRegistry regCPU;
  479. DWORD CPUs = 0;
  480. if (regCPU.Open(m_hKeyMachine, REG_PATH_CPU, KEY_READ)) {
  481. TCHAR SubkeyName[MAX_PATH + 1];
  482. DWORD SubkeySize = ARRAYLEN(SubkeyName);
  483. while (regCPU.EnumerateSubkey(CPUs, SubkeyName, &SubkeySize)) {
  484. SubkeySize = ARRAYLEN(SubkeyName);
  485. CPUs++;
  486. }
  487. }
  488. return CPUs;
  489. }
  490. // This function returns the processor vendor in text string
  491. // INPUT:
  492. // Buffer -- buffer to receive the string
  493. // BufferSize -- size of the buffer in char(bytes in ANSI)
  494. // OUTPUT:
  495. // The size of the text string, not including the terminated NULL char
  496. // If the returned value is 0, GetLastError will returns the error code.
  497. // If the returned value is larger than BufferSize, Buffer is too small
  498. //
  499. // The system assumes that all processor in the machine must
  500. // have the same type, therefore, this function does not take
  501. // processor number as a parameter.
  502. DWORD
  503. CSystemInfo::ProcessorVendor(
  504. TCHAR* Buffer,
  505. DWORD BufferSize
  506. )
  507. {
  508. return ProcessorInfo(REG_VALUE_CPU_VENDOR, Buffer, BufferSize);
  509. }
  510. // This function returns the processor type in text string
  511. // INPUT:
  512. // Buffer -- buffer to receive the string
  513. // BufferSize -- size of the buffer in char(bytes in ANSI)
  514. // OUTPUT:
  515. // The size of the text string, not including the terminated NULL char
  516. // If the returned value is 0, GetLastError will returns the error code.
  517. // If the returned value is larger than BufferSize, Buffer is too small
  518. //
  519. // The system assumes that all processor in the machine must
  520. // have the same type, therefore, this function does not take
  521. // processor number as a parameter.
  522. DWORD
  523. CSystemInfo::ProcessorType(
  524. TCHAR* Buffer,
  525. DWORD BufferSize
  526. )
  527. {
  528. return ProcessorInfo(REG_VALUE_CPU_TYPE, Buffer, BufferSize);
  529. }
  530. DWORD
  531. CSystemInfo::ProcessorInfo(
  532. LPCTSTR ValueName,
  533. TCHAR* Buffer,
  534. DWORD BufferSize
  535. )
  536. {
  537. if (!ValueName || (!Buffer && BufferSize)) {
  538. SetLastError(ERROR_INVALID_PARAMETER);
  539. return 0;
  540. }
  541. CSafeRegistry regCPU;
  542. DWORD CPUIndex = 0;
  543. TCHAR CPUInfo[MAX_PATH];
  544. DWORD CPUInfoSize = 0;
  545. DWORD Type;
  546. if (regCPU.Open(m_hKeyMachine, REG_PATH_CPU, KEY_READ)) {
  547. TCHAR CPUKey[MAX_PATH + 1];
  548. DWORD Size;
  549. Size = ARRAYLEN(CPUKey);
  550. // loop through all cpus until we find something interesting
  551. while (CPUInfoSize <= sizeof(TCHAR) &&
  552. regCPU.EnumerateSubkey(CPUIndex, CPUKey, &Size)) {
  553. CSafeRegistry regTheCPU;
  554. if (regTheCPU.Open(regCPU, CPUKey, KEY_READ)) {
  555. CPUInfoSize = sizeof(CPUInfo);
  556. regTheCPU.GetValue(ValueName, &Type, (PBYTE)CPUInfo, &CPUInfoSize);
  557. }
  558. CPUIndex++;
  559. }
  560. // CPUInfoSize != 0 means we find something
  561. if (CPUInfoSize > sizeof(TCHAR)) {
  562. CPUInfoSize = CPUInfoSize / sizeof(TCHAR) - 1;
  563. if (BufferSize > CPUInfoSize) {
  564. lstrcpyn(Buffer, CPUInfo, CPUInfoSize + 1);
  565. }
  566. return CPUInfoSize;
  567. }
  568. }
  569. return 0;
  570. }
  571. #if 0
  572. DWORD
  573. CSystemInfo::ProcessorType(
  574. TCHAR* Buffer,
  575. DWORD BufferSize
  576. )
  577. {
  578. SYSTEM_INFO SysInfo;
  579. GetSystemInfo(&SysInfo);
  580. TCHAR Format[MAX_PATH];
  581. TCHAR CPUType[MAX_PATH];
  582. TCHAR Revision[128];
  583. switch (SysInfo.wProcessorArchitecture) {
  584. case PROCESSOR_ARCHITECTURE_INTEL:
  585. // decode the processor level and revision
  586. if (3 == SysInfo.wProcessorLevel ||
  587. 4 == SysInfo.wProcessorLevel) {
  588. int StringId = (3 == SysInfo.wProcessorLevel) ?
  589. IDS_CPU_INTEL_386 : IDS_CPU_INTEL_486;
  590. LoadString(g_hInstance, StringId, CPUType, ARRAYLEN(CPUType));
  591. if (SysInfo.wProcessorRevision & 0xFF00 == 0xFF00) {
  592. LoadString(g_hInstance, IDS_CPU_REVISION_MODEL_STEPPING,
  593. Format, ARRAYLEN(Format));
  594. wsprintf(Revision, Format,
  595. ((SysInfo.wProcessorRevision & 0x00F0) > 4) - 10,
  596. SysInfo.wProcessorRevision & 0x000F);
  597. }
  598. else {
  599. LoadString(g_hInstance, IDS_CPU_REVISION_STEPPING,
  600. Format, ARRAYLEN(Format));
  601. wsprintf(Revision, Format,
  602. (SysInfo.wProcessorRevision >> 8) + _T('A'),
  603. SysInfo.wProcessorRevision & 0x00FF);
  604. }
  605. }
  606. else if (5 == SysInfo.wProcessorLevel) {
  607. LoadString(g_hInstance, IDS_CPU_INTEL_PENTIUM, CPUType, ARRAYLEN(CPUType));
  608. LoadString(g_hInstance, IDS_CPU_REVISION_MODEL_STEPPING,
  609. Format, ARRAYLEN(Format));
  610. wsprintf(Revision, Format, SysInfo.wProcessorRevision >> 8,
  611. SysInfo.wProcessorRevision & 0x00FF);
  612. }
  613. lstrcat(CPUType, Revision);
  614. break;
  615. case PROCESSOR_ARCHITECTURE_ALPHA:
  616. LoadString(g_hInstance, IDS_CPU_ALPHA, Format, ARRAYLEN(Format));
  617. wsprintf(CPUType, Format, SysInfo.wProcessorLevel);
  618. LoadString(g_hInstance, IDS_CPU_REVISION_ALPHA, Format,
  619. ARRAYLEN(Format));
  620. wsprintf(Revision, Format, (SysInfo.wProcessorRevision >> 8) + _T('A'),
  621. SysInfo.wProcessorRevision & 0x00FF);
  622. lstrcat(CPUType, Revision);
  623. default:
  624. CPUType[0] = _T('\0');
  625. }
  626. DWORD Size = lstrlen(CPUType);
  627. if (BufferSize > Size) {
  628. lstrcpy(Buffer, CPUType);
  629. }
  630. SetLastError(ERROR_SUCCESS);
  631. return Size;
  632. }
  633. #endif
  634. //
  635. // This function returns the total physical memeory in KB
  636. // INPUT:
  637. // NONE
  638. // OUTPUT:
  639. // Total Memory in KB
  640. //
  641. void
  642. CSystemInfo::TotalPhysicalMemory(
  643. ULARGE_INTEGER& Size
  644. )
  645. {
  646. if (m_fLocalMachine) {
  647. SYSTEM_BASIC_INFORMATION SysBasicInfo;
  648. NTSTATUS Status;
  649. Status = NtQuerySystemInformation(SystemBasicInformation,
  650. (PVOID)&SysBasicInfo,
  651. sizeof(SysBasicInfo),
  652. NULL);
  653. if (NT_SUCCESS(Status)) {
  654. Size.QuadPart = Int32x32To64(SysBasicInfo.PageSize,
  655. SysBasicInfo.NumberOfPhysicalPages
  656. );
  657. }
  658. else {
  659. MEMORYSTATUS MemoryStatus;
  660. GlobalMemoryStatus(&MemoryStatus);
  661. Size.LowPart = (ULONG)MemoryStatus.dwTotalPhys;
  662. Size.HighPart = 0;
  663. }
  664. }
  665. else {
  666. Size.QuadPart = 0;
  667. SetLastError(ERROR_SUCCESS);
  668. }
  669. }