/* * PROJECT: ReactOS SystemInfo Command * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Displays system information. * COPYRIGHT: Copyright 2007 Dmitry Chapyshev * Copyright 2011 Rafal Harabien * Copyright 2018 Stanislav Motylkov */ #include #include #include #include #include #include #include #include #include #include #include #include "resource.h" #define BUFFER_SIZE 1024 /* Load string from registry */ static UINT RegGetSZ(HKEY hKey, PCWSTR pSubKey, PCWSTR pValueName, PWSTR pBuf, DWORD cchBuf) { DWORD dwBytes = cchBuf * sizeof(WCHAR), dwType = 0; UINT cChars; /* If SubKey is specified open it */ if (pSubKey && RegOpenKeyExW(hKey, pSubKey, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) { ConPrintf(StdErr, L"Warning! Cannot open %s. Last error: %lu.\n", pSubKey, GetLastError()); return 0; } /* Query registry value and check its type */ if (RegQueryValueExW(hKey, pValueName, NULL, &dwType, (PBYTE)pBuf, &dwBytes) != ERROR_SUCCESS || (dwType != REG_SZ && dwType != REG_MULTI_SZ)) { ConPrintf(StdErr, L"Warning! Cannot query %s. Last error: %lu, type: %lu.\n", pValueName, GetLastError(), dwType); dwBytes = 0; } else if (dwBytes == 0) { wcscpy(pBuf, L"N/A"); dwBytes = sizeof(L"N/A")-sizeof(WCHAR); } /* Close key if we opened it */ if (pSubKey) RegCloseKey(hKey); cChars = dwBytes/sizeof(WCHAR); /* NULL-terminate string */ pBuf[min(cchBuf-1, cChars)] = L'\0'; /* Don't count NULL characters */ while (cChars && !pBuf[cChars-1]) --cChars; return cChars; } /* Load DWORD from registry */ static BOOL RegGetDWORD(HKEY hKey, PCWSTR pSubKey, PCWSTR pValueName, PDWORD pData) { DWORD dwBytes = sizeof(*pData), dwType; BOOL bRet = TRUE; /* If SubKey is specified open it */ if (pSubKey && RegOpenKeyExW(hKey, pSubKey, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) { ConPrintf(StdErr, L"Warning! Cannot open %s. Last error: %lu.\n", pSubKey, GetLastError()); return FALSE; } /* Query registry value and check its type */ if (RegQueryValueExW(hKey, pValueName, NULL, &dwType, (PBYTE)pData, &dwBytes) != ERROR_SUCCESS || dwType != REG_DWORD) { ConPrintf(StdErr, L"Warning! Cannot query %s. Last err: %lu, type: %lu\n", pValueName, GetLastError(), dwType); *pData = 0; bRet = FALSE; } /* Close key if we opened it */ if (pSubKey) RegCloseKey(hKey); return bRet; } /* Format bytes */ static VOID FormatBytes(PWSTR pBuf, UINT cBytes) { WCHAR szMB[32]; NUMBERFMTW fmt; UINT i; _itow(cBytes / (1024*1024), szMB, 10); fmt.NumDigits = 0; fmt.LeadingZero = 0; fmt.Grouping = 3; fmt.lpDecimalSep = L""; fmt.lpThousandSep = L" "; fmt.NegativeOrder = 0; i = GetNumberFormatW(LOCALE_SYSTEM_DEFAULT, 0, szMB, &fmt, pBuf, BUFFER_SIZE - 3); if (i) --i; /* don't count NULL character */ wcscpy(pBuf + i, L" MB"); } /* Format date and time */ static VOID FormatDateTime(time_t Time, PWSTR pBuf) { UINT i; SYSTEMTIME SysTime; const struct tm *pTm; pTm = localtime(&Time); SysTime.wYear = (WORD)(1900 + pTm->tm_year); SysTime.wMonth = (WORD)(1 + pTm->tm_mon); SysTime.wDayOfWeek = (WORD)pTm->tm_wday; SysTime.wDay = (WORD)pTm->tm_mday; SysTime.wHour = (WORD)pTm->tm_hour; SysTime.wMinute = (WORD)pTm->tm_min; SysTime.wSecond = (WORD)pTm->tm_sec; SysTime.wMilliseconds = 0; /* Copy date first */ i = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &SysTime, NULL, pBuf, BUFFER_SIZE - 2); if (i) --i; /* don't count NULL character */ /* Copy time now */ i += _swprintf(pBuf + i, L", "); GetTimeFormatW(LOCALE_SYSTEM_DEFAULT, 0, &SysTime, NULL, pBuf + i, BUFFER_SIZE - i); } ULONGLONG GetSecondsQPC(VOID) { LARGE_INTEGER Counter, Frequency; QueryPerformanceCounter(&Counter); QueryPerformanceFrequency(&Frequency); return Counter.QuadPart / Frequency.QuadPart; } ULONGLONG GetSeconds(VOID) { ULONGLONG (WINAPI *pGetTickCount64)(VOID); ULONGLONG Ticks64; HMODULE hModule = GetModuleHandleW(L"kernel32.dll"); pGetTickCount64 = (PVOID)GetProcAddress(hModule, "GetTickCount64"); if (pGetTickCount64) return pGetTickCount64() / 1000; hModule = LoadLibraryW(L"kernel32_vista.dll"); if (!hModule) return GetSecondsQPC(); pGetTickCount64 = (PVOID)GetProcAddress(hModule, "GetTickCount64"); if (pGetTickCount64) Ticks64 = pGetTickCount64() / 1000; else Ticks64 = GetSecondsQPC(); FreeLibrary(hModule); return Ticks64; } /* Show usage */ static VOID Usage(VOID) { ConResPrintf(StdOut, IDS_USAGE); } static VOID PrintRow(UINT nTitleID, BOOL bIndent, PCWSTR pFormat, ...) { va_list Args; UINT c; WCHAR Buf[BUFFER_SIZE]; if (nTitleID) { c = LoadStringW(NULL, nTitleID, Buf, _countof(Buf) - 2); if (!c) return; wcscpy(Buf + c, L": "); } else { Buf[0] = L'\0'; } if (!bIndent) ConPrintf(StdOut, L"%-32s", Buf); else if (Buf[0]) ConPrintf(StdOut, L"%38s%-16s", L"", Buf); else ConPrintf(StdOut, L"%38s", L""); va_start(Args, pFormat); ConPrintfV(StdOut, pFormat, Args); va_end(Args); ConPuts(StdOut, L"\n"); } /* Print all system information */ VOID AllSysInfo(VOID) { DWORD dwCharCount, dwTimestamp, dwResult; OSVERSIONINFOW VersionInfo; SYSTEM_INFO SysInfo; WCHAR Buf[BUFFER_SIZE], Tmp[BUFFER_SIZE], szSystemDir[MAX_PATH]; PCWSTR SysType; PWSTR pBuffer; NETSETUP_JOIN_STATUS NetJoinStatus; MEMORYSTATUS MemoryStatus; UINT cSeconds, i, j; TIME_ZONE_INFORMATION TimeZoneInfo; HKEY hKey; PIP_ADAPTER_ADDRESSES pAdapters; ULONG cbAdapters; PVOID SMBiosBuf; PCHAR DmiStrings[ID_STRINGS_MAX] = { 0 }; if (!GetSystemDirectoryW(szSystemDir, _countof(szSystemDir))) { ConPrintf(StdErr, L"Error! GetSystemDirectory failed.\n"); return; } GetSystemInfo(&SysInfo); /* Getting computer name */ dwCharCount = _countof(Buf); if (!GetComputerNameW(Buf, &dwCharCount)) ConPrintf(StdErr, L"Error! GetComputerName failed.\n"); else PrintRow(IDS_HOST_NAME, FALSE, L"%s", Buf); /* Open CurrentVersion key */ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) { ConPrintf(StdErr, L"Error! RegOpenKeyEx failed.\n"); return; } /* Getting OS Name */ RegGetSZ(hKey, NULL, L"ProductName", Buf, _countof(Buf)); PrintRow(IDS_OS_NAME, FALSE, L"%s", Buf); /* Getting OS Version */ ZeroMemory(&VersionInfo, sizeof(VersionInfo)); VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo); GetVersionExW(&VersionInfo); if (!LoadStringW(NULL, IDS_BUILD, Tmp, _countof(Tmp))) Tmp[0] = L'\0'; PrintRow(IDS_OS_VERSION, FALSE, L"%lu.%lu.%lu %s %s %lu", VersionInfo.dwMajorVersion, VersionInfo.dwMinorVersion, VersionInfo.dwBuildNumber, VersionInfo.szCSDVersion, Tmp, VersionInfo.dwBuildNumber); /* Getting OS Manufacturer */ /* Getting OS Configuration */ /* Getting OS Build Type */ RegGetSZ(hKey, NULL, L"CurrentType", Buf, _countof(Buf)); PrintRow(IDS_OS_BUILD_TYPE, FALSE, L"%s", Buf); /* Getting Registered Owner */ RegGetSZ(hKey, NULL, L"RegisteredOwner", Buf, _countof(Buf)); PrintRow(IDS_REG_OWNER, FALSE, L"%s", Buf); /* Getting Registered Organization */ RegGetSZ(hKey, NULL, L"RegisteredOrganization", Buf, _countof(Buf)); PrintRow(IDS_REG_ORG, FALSE, L"%s", Buf); /* Getting Product ID */ RegGetSZ(hKey, NULL, L"ProductId", Buf, _countof(Buf)); PrintRow(IDS_PRODUCT_ID, FALSE, L"%s", Buf); /* Getting Install Date */ RegGetDWORD(hKey, NULL, L"InstallDate", &dwTimestamp); FormatDateTime((time_t)dwTimestamp, Buf); PrintRow(IDS_INST_DATE, FALSE, L"%s", Buf); /* Close Current Version key now */ RegCloseKey(hKey); /* Getting System Up Time */ cSeconds = GetSeconds(); if (!LoadStringW(NULL, IDS_UP_TIME_FORMAT, Tmp, _countof(Tmp))) Tmp[0] = L'\0'; _swprintf(Buf, Tmp, cSeconds / (60*60*24), (cSeconds / (60*60)) % 24, (cSeconds / 60) % 60, cSeconds % 60); PrintRow(IDS_UP_TIME, FALSE, L"%s", Buf); /* Prepare SMBIOS data */ SMBiosBuf = LoadSMBiosData(DmiStrings); /* Getting System Manufacturer; * HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\OEMInformation\Manufacturer * for Win >= 6.0 */ _swprintf(Tmp, L"%s\\oeminfo.ini", szSystemDir); GetPrivateProfileStringW(L"General", L"Manufacturer", L"", Buf, _countof(Buf), Tmp); if (wcslen(Buf) == 0 && SMBiosBuf) { GetSMBiosStringW(DmiStrings[SYS_VENDOR], Buf, _countof(Buf), FALSE); } PrintRow(IDS_SYS_MANUFACTURER, FALSE, L"%s", Buf); /* Getting System Model; * HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\OEMInformation\Model * for Win >= 6.0 */ GetPrivateProfileStringW(L"General", L"Model", L"", Buf, _countof(Buf), Tmp); if (wcslen(Buf) == 0 && SMBiosBuf) { GetSMBiosStringW(DmiStrings[SYS_PRODUCT], Buf, _countof(Buf), FALSE); } PrintRow(IDS_SYS_MODEL, FALSE, L"%s", Buf); /* Getting System type */ switch (SysInfo.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL: SysType = L"X86-based PC"; break; case PROCESSOR_ARCHITECTURE_IA64: SysType = L"IA64-based PC"; break; case PROCESSOR_ARCHITECTURE_AMD64: SysType = L"AMD64-based PC"; break; default: SysType = L"Unknown"; break; } PrintRow(IDS_SYS_TYPE, FALSE, L"%s", SysType); /* Getting Processor(s) */ if (!LoadStringW(NULL, IDS_PROCESSORS_FORMAT, Tmp, _countof(Tmp))) Tmp[0] = L'\0'; _swprintf(Buf, Tmp, (UINT)SysInfo.dwNumberOfProcessors); PrintRow(IDS_PROCESSORS, FALSE, L"%s", Buf); for (i = 0; i < (UINT)SysInfo.dwNumberOfProcessors; i++) { _swprintf(Tmp, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%u", i); j = _swprintf(Buf, L"[%02u]: ", i + 1); j += RegGetSZ(HKEY_LOCAL_MACHINE, Tmp, L"Identifier", Buf + j, _countof(Buf) - j); if (j + 1 < _countof(Buf)) Buf[j++] = L' '; RegGetSZ(HKEY_LOCAL_MACHINE, Tmp, L"VendorIdentifier", Buf + j, _countof(Buf) - j); PrintRow(0, FALSE, L"%s", Buf); } /* Getting BIOS Version */ if (SMBiosBuf) { j = GetSMBiosStringW(DmiStrings[BIOS_VENDOR], Buf, _countof(Buf), TRUE); if (j + 1 < _countof(Buf)) { Buf[j++] = L' '; Buf[j] = L'\0'; } GetSMBiosStringW(DmiStrings[BIOS_VERSION], Buf + j, _countof(Buf) - j, TRUE); } else { RegGetSZ(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System", L"SystemBiosVersion", Buf, _countof(Buf)); } PrintRow(IDS_BIOS_VERSION, FALSE, L"%s", Buf); /* Getting BIOS date */ if (SMBiosBuf) { GetSMBiosStringW(DmiStrings[BIOS_DATE], Buf, _countof(Buf), TRUE); } else { RegGetSZ(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System", L"SystemBiosDate", Buf, _countof(Buf)); } PrintRow(IDS_BIOS_DATE, FALSE, L"%s", Buf); /* Clean SMBIOS data */ FreeSMBiosData(SMBiosBuf); /* Getting ReactOS Directory */ if (!GetWindowsDirectoryW(Buf, _countof(Buf))) ConPrintf(StdErr, L"Error! GetWindowsDirectory failed."); else PrintRow(IDS_ROS_DIR, FALSE, L"%s", Buf); /* Getting System Directory */ PrintRow(IDS_SYS_DIR, 0, L"%s", szSystemDir); /* Getting Boot Device */ RegGetSZ(HKEY_LOCAL_MACHINE, L"SYSTEM\\Setup", L"SystemPartition", Buf, _countof(Buf)); PrintRow(IDS_BOOT_DEV, FALSE, L"%s", Buf); /* Getting System Locale */ if (GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_ILANGUAGE, Tmp, _countof(Tmp))) { if (RegGetSZ(HKEY_CLASSES_ROOT, L"MIME\\Database\\Rfc1766", Tmp, Buf, _countof(Buf))) { /* Get rid of @filename,resource */ pBuffer = wcschr(Buf, L';'); if (pBuffer) SHLoadIndirectString(pBuffer+1, pBuffer+1, _countof(Buf) - (pBuffer-Buf) - 1, NULL); PrintRow(IDS_SYS_LOCALE, FALSE, L"%s", Buf); } } /* Getting Input Locale */ if (RegGetSZ(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", L"1", Tmp, _countof(Tmp)) && wcslen(Tmp) > 4) { if (RegGetSZ(HKEY_CLASSES_ROOT, L"MIME\\Database\\Rfc1766", Tmp + 4, Buf, _countof(Buf))) { /* Get rid of @filename,resource */ pBuffer = wcschr(Buf, L';'); if (pBuffer) SHLoadIndirectString(pBuffer+1, pBuffer+1, _countof(Buf) - (pBuffer-Buf) - 1, NULL); PrintRow(IDS_INPUT_LOCALE, FALSE, L"%s", Buf); } } /* Getting Time Zone */ GetTimeZoneInformation(&TimeZoneInfo); /* Open Time Zones key */ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0, KEY_ENUMERATE_SUB_KEYS|KEY_READ, &hKey) == ERROR_SUCCESS) { /* Find current timezone */ UINT i; dwCharCount = _countof(Tmp); for (i = 0; RegEnumKeyExW(hKey, i, Tmp, &dwCharCount, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; ++i, dwCharCount = 255) { RegGetSZ(hKey, Tmp, L"Std", Buf, _countof(Buf)); if (!wcscmp(Buf, TimeZoneInfo.StandardName)) { RegGetSZ(hKey, Tmp, L"Display", Buf, _countof(Buf)); PrintRow(IDS_TIME_ZONE, FALSE, L"%s", Buf); break; } } RegCloseKey(hKey); } /* Getting Total Physical Memory */ GlobalMemoryStatus(&MemoryStatus); FormatBytes(Buf, MemoryStatus.dwTotalPhys); PrintRow(IDS_TOTAL_PHYS_MEM, FALSE, L"%s", Buf); /* Getting Available Physical Memory */ FormatBytes(Buf, MemoryStatus.dwAvailPhys); PrintRow(IDS_AVAIL_PHISICAL_MEM, FALSE, L"%s", Buf); /* Getting Virtual Memory: Max Size */ FormatBytes(Buf, MemoryStatus.dwTotalVirtual); PrintRow(IDS_VIRT_MEM_MAX, FALSE, L"%s", Buf); /* Getting Virtual Memory: Available */ FormatBytes(Buf, MemoryStatus.dwAvailVirtual); PrintRow(IDS_VIRT_MEM_AVAIL, FALSE, L"%s", Buf); /* Getting Virtual Memory: In Use */ FormatBytes(Buf, MemoryStatus.dwTotalVirtual-MemoryStatus.dwAvailVirtual); PrintRow(IDS_VIRT_MEM_INUSE, FALSE, L"%s", Buf); /* Getting Page File Location(s) */ if (RegGetSZ(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management", L"PagingFiles", Buf, _countof(Buf))) { UINT i; for (i = 0; Buf[i]; i++) { if (Buf[i] == L' ') { Buf[i] = L'\0'; break; } } PrintRow(IDS_PAGEFILE_LOC, FALSE, L"%s", Buf); } /* Getting Domain */ if (NetGetJoinInformation(NULL, &pBuffer, &NetJoinStatus) == NERR_Success) { if (NetJoinStatus == NetSetupWorkgroupName || NetJoinStatus == NetSetupDomainName) PrintRow(IDS_DOMAIN, FALSE, L"%s", pBuffer); NetApiBufferFree(pBuffer); } /* Getting Logon Server */ /* Getting NetWork Card(s) */ cbAdapters = 4096; pAdapters = malloc(cbAdapters); while ((dwResult = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST, NULL, pAdapters, &cbAdapters)) == ERROR_BUFFER_OVERFLOW) { cbAdapters += 4096; pAdapters = (PIP_ADAPTER_ADDRESSES)realloc(pAdapters, cbAdapters); } if (dwResult == ERROR_SUCCESS) { PIP_ADAPTER_ADDRESSES pCurrentAdapter = pAdapters; UINT cAdapters = 0; /* Count adapters */ for (i = 0; pCurrentAdapter; ++i) { if (pCurrentAdapter->IfType != IF_TYPE_SOFTWARE_LOOPBACK && pCurrentAdapter->IfType != IF_TYPE_TUNNEL) ++cAdapters; pCurrentAdapter = pCurrentAdapter->Next; } /* Print adapters count */ if (!LoadStringW(NULL, IDS_NETWORK_CARDS_FORMAT, Tmp, _countof(Tmp))) Tmp[0] = L'\0'; _swprintf(Buf, Tmp, cAdapters); PrintRow(IDS_NETWORK_CARDS, FALSE, L"%s", Buf); /* Show information about each adapter */ pCurrentAdapter = pAdapters; for (i = 0; pCurrentAdapter; ++i) { if (pCurrentAdapter->IfType != IF_TYPE_SOFTWARE_LOOPBACK && pCurrentAdapter->IfType != IF_TYPE_TUNNEL) { PIP_ADAPTER_UNICAST_ADDRESS pAddress; PrintRow(0, FALSE, L"[%02u]: %s", i + 1, pCurrentAdapter->Description); PrintRow(IDS_CONNECTION_NAME, TRUE, L"%s", pCurrentAdapter->FriendlyName); if (!(pCurrentAdapter->Flags & IP_ADAPTER_DHCP_ENABLED)) { if (!LoadStringW(NULL, IDS_NO, Buf, _countof(Buf))) Buf[0] = L'\0'; PrintRow(IDS_DHCP_ENABLED, TRUE, Buf); } if (pCurrentAdapter->OperStatus == IfOperStatusDown) { if (!LoadStringW(NULL, IDS_MEDIA_DISCONNECTED, Buf, _countof(Buf))) Buf[0] = L'\0'; PrintRow(IDS_STATUS, TRUE, Buf); } else { if (!LoadStringW(NULL, IDS_IP_ADDRESSES, Buf, _countof(Buf))) Buf[0] = L'\0'; PrintRow(0, TRUE, Buf); pAddress = pCurrentAdapter->FirstUnicastAddress; for (j = 0; pAddress; ++j) { dwCharCount = _countof(Buf); WSAAddressToStringW(pAddress->Address.lpSockaddr, pAddress->Address.iSockaddrLength, NULL, Buf, &dwCharCount); PrintRow(0, TRUE, L"[%02u]: %s", j + 1, Buf); pAddress = pAddress->Next; } } } pCurrentAdapter = pCurrentAdapter->Next; } } free(pAdapters); } /* Main program */ int wmain(int argc, wchar_t *argv[]) { WSADATA WsaData; int i; /* Initialize the Console Standard Streams */ ConInitStdStreams(); WSAStartup(MAKEWORD(2, 2), &WsaData); for (i = 1; i < argc; ++i) { if (!wcscmp(argv[i], L"/?") || !wcscmp(argv[i], L"-?")) { Usage(); return 0; } else { ConPrintf(StdErr, L"Unsupported argument: %s\n", argv[i]); return -1; } } AllSysInfo(); return 0; }