| OLD | NEW |
| (Empty) |
| 1 // Copyright 2004-2009 Google Inc. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 // ======================================================================== | |
| 15 | |
| 16 #include "omaha/base/system_info.h" | |
| 17 #include "base/basictypes.h" | |
| 18 #include "omaha/base/debug.h" | |
| 19 #include "omaha/base/logging.h" | |
| 20 #include "omaha/base/process.h" | |
| 21 #include "omaha/base/string.h" | |
| 22 | |
| 23 namespace omaha { | |
| 24 | |
| 25 bool SystemInfo::OSWinXPSP2OrLater() { | |
| 26 OSVersionType os_type(OS_WINDOWS_UNKNOWN); | |
| 27 DWORD sp(0); | |
| 28 | |
| 29 HRESULT hr = CategorizeOS(&os_type, &sp); | |
| 30 if (FAILED(hr)) { | |
| 31 ASSERT(false, (_T("[CategorizeOS failed][0x%x]"), hr)); | |
| 32 return false; | |
| 33 } | |
| 34 | |
| 35 return ((os_type == SystemInfo::OS_WINDOWS_XP && sp >= 2) || | |
| 36 os_type > SystemInfo::OS_WINDOWS_XP); | |
| 37 } | |
| 38 | |
| 39 bool SystemInfo::IsRunningOnW2K() { | |
| 40 OSVERSIONINFO os_info = {0}; | |
| 41 os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); | |
| 42 | |
| 43 if (!::GetVersionEx(&os_info)) { | |
| 44 ASSERT(false, (_T("GetVersionEx"))); | |
| 45 return false; | |
| 46 } | |
| 47 | |
| 48 return os_info.dwMajorVersion == 5 && os_info.dwMinorVersion == 0; | |
| 49 } | |
| 50 | |
| 51 bool SystemInfo::IsRunningOnXPOrLater() { | |
| 52 OSVersionType os_type(OS_WINDOWS_UNKNOWN); | |
| 53 | |
| 54 HRESULT hr = CategorizeOS(&os_type, NULL); | |
| 55 if (FAILED(hr)) { | |
| 56 ASSERT(false, (_T("[Failed to get os type][0x%x]"), hr)); | |
| 57 return false; | |
| 58 } | |
| 59 | |
| 60 return os_type >= SystemInfo::OS_WINDOWS_XP; | |
| 61 } | |
| 62 | |
| 63 bool SystemInfo::IsRunningOnXPSP1OrLater() { | |
| 64 OSVersionType os_type(OS_WINDOWS_UNKNOWN); | |
| 65 DWORD sp(0); | |
| 66 | |
| 67 HRESULT hr = CategorizeOS(&os_type, &sp); | |
| 68 if (FAILED(hr)) { | |
| 69 ASSERT(false, (_T("[Failed to get os type][0x%x]"), hr)); | |
| 70 return false; | |
| 71 } | |
| 72 | |
| 73 return ((os_type == SystemInfo::OS_WINDOWS_XP && sp >= 1) || | |
| 74 os_type > SystemInfo::OS_WINDOWS_XP); | |
| 75 } | |
| 76 | |
| 77 | |
| 78 bool SystemInfo::IsRunningOnVistaOrLater() { | |
| 79 OSVersionType os_type(OS_WINDOWS_UNKNOWN); | |
| 80 DWORD sp(0); | |
| 81 | |
| 82 HRESULT hr = CategorizeOS(&os_type, &sp); | |
| 83 if (FAILED(hr)) { | |
| 84 ASSERT(false, (_T("[Failed to get os type][0x%x]"), hr)); | |
| 85 return false; | |
| 86 } | |
| 87 | |
| 88 return (os_type >= OS_WINDOWS_VISTA); | |
| 89 } | |
| 90 | |
| 91 bool SystemInfo::IsRunningOnVistaRTM() { | |
| 92 OSVersionType os_type(OS_WINDOWS_UNKNOWN); | |
| 93 DWORD sp(0); | |
| 94 | |
| 95 HRESULT hr = CategorizeOS(&os_type, &sp); | |
| 96 if (FAILED(hr)) { | |
| 97 ASSERT(false, (_T("[Failed to get os type][0x%x]"), hr)); | |
| 98 return false; | |
| 99 } | |
| 100 | |
| 101 return (os_type == SystemInfo::OS_WINDOWS_VISTA && sp == 0); | |
| 102 } | |
| 103 | |
| 104 HRESULT SystemInfo::CategorizeOS(OSVersionType* os_ver, DWORD* sp) { | |
| 105 static OSVersionType os_ver_cached(OS_WINDOWS_UNKNOWN); | |
| 106 // Hopefully, Windows doesn't release a SP that's kuint32max. | |
| 107 static DWORD sp_cached(kuint32max); | |
| 108 | |
| 109 ASSERT(os_ver, (_T(""))); | |
| 110 | |
| 111 if (sp) { | |
| 112 *sp = 0; | |
| 113 } | |
| 114 | |
| 115 if (os_ver_cached == OS_WINDOWS_UNKNOWN || sp_cached == kuint32max) { | |
| 116 // Use GetVersionEx to get OS and Service Pack information. | |
| 117 OSVERSIONINFOEX osviex; | |
| 118 ::ZeroMemory(&osviex, sizeof(OSVERSIONINFOEX)); | |
| 119 osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); | |
| 120 BOOL r = ::GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&osviex)); | |
| 121 | |
| 122 // If ::GetVersionEx fails when given an OSVERSIONINFOEX then we're running | |
| 123 // on NT4.0SP5 or earlier. | |
| 124 if (!r) { | |
| 125 os_ver_cached = OS_WINDOWS_9X_OR_NT; | |
| 126 } else { | |
| 127 switch (osviex.dwPlatformId) { | |
| 128 case VER_PLATFORM_WIN32_NT: | |
| 129 // Windows 7 beta 1 reports the same major version as Vista does. | |
| 130 if (osviex.dwMajorVersion == 6 && osviex.dwMinorVersion == 1) { | |
| 131 os_ver_cached = OS_WINDOWS_7; | |
| 132 } else if (osviex.dwMajorVersion == 6 && osviex.dwMinorVersion == 0) { | |
| 133 os_ver_cached = OS_WINDOWS_VISTA; | |
| 134 } else if (osviex.dwMajorVersion == 5 && osviex.dwMinorVersion == 2) { | |
| 135 os_ver_cached = OS_WINDOWS_SERVER_2003; | |
| 136 } else if (osviex.dwMajorVersion == 5 && osviex.dwMinorVersion == 1) { | |
| 137 os_ver_cached = OS_WINDOWS_XP; | |
| 138 } else if (osviex.dwMajorVersion == 5 && osviex.dwMinorVersion == 0) { | |
| 139 os_ver_cached = OS_WINDOWS_2000; | |
| 140 } else if (osviex.dwMajorVersion <= 4) { | |
| 141 os_ver_cached = OS_WINDOWS_9X_OR_NT; | |
| 142 break; | |
| 143 } else { | |
| 144 os_ver_cached = OS_WINDOWS_UNKNOWN; | |
| 145 break; | |
| 146 } | |
| 147 sp_cached = osviex.wServicePackMajor; | |
| 148 break; | |
| 149 | |
| 150 case VER_PLATFORM_WIN32_WINDOWS: | |
| 151 case VER_PLATFORM_WIN32s: | |
| 152 default: | |
| 153 os_ver_cached = OS_WINDOWS_9X_OR_NT; | |
| 154 break; | |
| 155 } | |
| 156 } | |
| 157 | |
| 158 OPT_LOG(L1, (_T("[OS][version: %s][service pack: %d]"), | |
| 159 OSVersionTypeAsString(os_ver_cached), | |
| 160 sp_cached)); | |
| 161 } | |
| 162 | |
| 163 ASSERT1(os_ver_cached != OS_WINDOWS_UNKNOWN && sp_cached != kuint32max); | |
| 164 | |
| 165 *os_ver = os_ver_cached; | |
| 166 if (sp) { | |
| 167 *sp = sp_cached; | |
| 168 } | |
| 169 | |
| 170 return S_OK; | |
| 171 } | |
| 172 | |
| 173 const wchar_t* SystemInfo::OSVersionTypeAsString(OSVersionType t) { | |
| 174 switch (t) { | |
| 175 case OS_WINDOWS_9X_OR_NT: return _T("OS_WINDOWS_9X_OR_NT"); | |
| 176 case OS_WINDOWS_2000: return _T("OS_WINDOWS_2000"); | |
| 177 case OS_WINDOWS_XP: return _T("OS_WINDOWS_XP"); | |
| 178 case OS_WINDOWS_SERVER_2003: return _T("OS_WINDOWS_SERVER_2003"); | |
| 179 case OS_WINDOWS_UNKNOWN: return _T("OS_WINDOWS_UNKNOWN"); | |
| 180 case OS_WINDOWS_VISTA: return _T("OS_WINDOWS_VISTA"); | |
| 181 case OS_WINDOWS_7: return _T("OS_WINDOWS_7"); | |
| 182 default: return _T("<unknown>"); | |
| 183 } | |
| 184 } | |
| 185 | |
| 186 // The following code which names the operating system comes from MSDN article | |
| 187 // "Getting the System Version" | |
| 188 #define kNullChar (_T('\0')) | |
| 189 bool SystemInfo::GetSystemVersion(int* major_version, | |
| 190 int* minor_version, | |
| 191 int* service_pack_major, | |
| 192 int* service_pack_minor, | |
| 193 TCHAR* name_buf, | |
| 194 size_t name_buf_len) { | |
| 195 ASSERT1(major_version); | |
| 196 ASSERT1(minor_version); | |
| 197 ASSERT1(service_pack_major); | |
| 198 ASSERT1(service_pack_minor); | |
| 199 ASSERT1(name_buf); | |
| 200 ASSERT1(0 < name_buf_len); | |
| 201 | |
| 202 // Clear the name to start with. | |
| 203 name_buf[0] = kNullChar; | |
| 204 | |
| 205 DWORD buf_len = MAX_PATH; | |
| 206 TCHAR buffer[MAX_PATH]; | |
| 207 TCHAR format_buffer[64]; | |
| 208 | |
| 209 buffer[0] = kNullChar; | |
| 210 | |
| 211 OSVERSIONINFOEX osvi; | |
| 212 BOOL ver_info_exists; | |
| 213 | |
| 214 // Try calling GetVersionEx using the OSVERSIONINFOEX structure. | |
| 215 // If that fails, try using the OSVERSIONINFO structure. | |
| 216 ::ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); | |
| 217 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); | |
| 218 | |
| 219 ver_info_exists = ::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&osvi)); | |
| 220 if (!ver_info_exists) { | |
| 221 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); | |
| 222 if (!::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&osvi))) { | |
| 223 return false; | |
| 224 } | |
| 225 } | |
| 226 | |
| 227 *major_version = osvi.dwMajorVersion; | |
| 228 *minor_version = osvi.dwMinorVersion; | |
| 229 *service_pack_major = osvi.wServicePackMajor; | |
| 230 *service_pack_minor = osvi.wServicePackMinor; | |
| 231 | |
| 232 switch (osvi.dwPlatformId) { | |
| 233 // Test for the Windows NT product family. | |
| 234 case VER_PLATFORM_WIN32_NT: | |
| 235 | |
| 236 // Test for the specific product family. | |
| 237 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) { | |
| 238 SafeStrCat(buffer, | |
| 239 _T("Microsoft Windows Server 2003 family, "), | |
| 240 buf_len); | |
| 241 } | |
| 242 | |
| 243 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { | |
| 244 SafeStrCat(buffer, _T("Microsoft Windows XP "), buf_len); | |
| 245 } | |
| 246 | |
| 247 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) { | |
| 248 SafeStrCat(buffer, _T("Microsoft Windows 2000 "), buf_len); | |
| 249 } | |
| 250 | |
| 251 if (osvi.dwMajorVersion <= 4) { | |
| 252 SafeStrCat(buffer, _T("Microsoft Windows NT "), buf_len); | |
| 253 } | |
| 254 | |
| 255 // Test for specific product on Windows NT 4.0 SP6 and later. | |
| 256 if (ver_info_exists) { | |
| 257 // Test for the workstation type. | |
| 258 if (osvi.wProductType == VER_NT_WORKSTATION) { | |
| 259 if (osvi.dwMajorVersion == 4) { | |
| 260 SafeStrCat(buffer, _T("Workstation 4.0 "), buf_len); | |
| 261 } else if (osvi.wSuiteMask & VER_SUITE_PERSONAL) { | |
| 262 SafeStrCat(buffer, _T("Home Edition "), buf_len); | |
| 263 } else { | |
| 264 SafeStrCat(buffer, _T("Professional "), buf_len); | |
| 265 } | |
| 266 } else if (osvi.wProductType == VER_NT_SERVER || | |
| 267 osvi.wProductType == VER_NT_DOMAIN_CONTROLLER) { | |
| 268 // server type. | |
| 269 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) { | |
| 270 if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { | |
| 271 SafeStrCat(buffer, _T("Datacenter Edition "), buf_len); | |
| 272 } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { | |
| 273 SafeStrCat(buffer, _T("Enterprise Edition "), buf_len); | |
| 274 } else if (osvi.wSuiteMask == VER_SUITE_BLADE) { | |
| 275 SafeStrCat(buffer, _T("Web Edition "), buf_len); | |
| 276 } else { | |
| 277 SafeStrCat(buffer, _T("Standard Edition "), buf_len); | |
| 278 } | |
| 279 } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) { | |
| 280 if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { | |
| 281 SafeStrCat(buffer, _T("Datacenter Server "), buf_len); | |
| 282 } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { | |
| 283 SafeStrCat(buffer, _T("Advanced Server "), buf_len); | |
| 284 } else { | |
| 285 SafeStrCat(buffer, _T("Server "), buf_len); | |
| 286 } | |
| 287 } else { | |
| 288 // Windows NT 4.0. | |
| 289 if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { | |
| 290 SafeStrCat(buffer, | |
| 291 _T("Server 4.0, Enterprise Edition "), | |
| 292 buf_len); | |
| 293 } else { | |
| 294 SafeStrCat(buffer, _T("Server 4.0 "), buf_len); | |
| 295 } | |
| 296 } | |
| 297 } | |
| 298 } else { | |
| 299 // Test for specific product on Windows NT 4.0 SP5 and earlier. | |
| 300 HKEY hKey; | |
| 301 TCHAR product_type[64] = {0}; | |
| 302 DWORD dwBufLen = arraysize(product_type); | |
| 303 LONG lRet; | |
| 304 | |
| 305 // TODO(omaha): should we use the RegKey API for consistency. | |
| 306 lRet = ::RegOpenKeyEx( | |
| 307 HKEY_LOCAL_MACHINE, | |
| 308 _T("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"), | |
| 309 0, | |
| 310 KEY_QUERY_VALUE, | |
| 311 &hKey); | |
| 312 if (lRet != ERROR_SUCCESS) { | |
| 313 return false; | |
| 314 } | |
| 315 | |
| 316 lRet = ::RegQueryValueEx(hKey, | |
| 317 _T("ProductType"), | |
| 318 NULL, | |
| 319 NULL, | |
| 320 reinterpret_cast<byte *>(product_type), | |
| 321 &dwBufLen); | |
| 322 if ((lRet != ERROR_SUCCESS) || (dwBufLen > arraysize(product_type))) { | |
| 323 return false; | |
| 324 } | |
| 325 | |
| 326 ::RegCloseKey(hKey); | |
| 327 | |
| 328 if (::lstrcmpi(_T("WINNT"), product_type) == 0) { | |
| 329 SafeStrCat(buffer, _T("Workstation "), buf_len); | |
| 330 } | |
| 331 if (::lstrcmpi(_T("LANMANNT"), product_type) == 0) { | |
| 332 SafeStrCat(buffer, _T("Server "), buf_len); | |
| 333 } | |
| 334 if (::lstrcmpi(_T("SERVERNT"), product_type) == 0) { | |
| 335 SafeStrCat(buffer, _T("Advanced Server "), buf_len); | |
| 336 } | |
| 337 | |
| 338 ::wsprintf(format_buffer, | |
| 339 _T("%d.%d "), | |
| 340 osvi.dwMajorVersion, | |
| 341 osvi.dwMinorVersion); | |
| 342 SafeStrCat(buffer, format_buffer, buf_len); | |
| 343 } | |
| 344 | |
| 345 // Display service pack (if any) and build number. | |
| 346 if (osvi.dwMajorVersion == 4 && | |
| 347 ::lstrcmpi(osvi.szCSDVersion, _T("Service Pack 6")) == 0) { | |
| 348 HKEY hKey; | |
| 349 LONG lRet; | |
| 350 | |
| 351 // Test for SP6 versus SP6a. | |
| 352 lRet = ::RegOpenKeyEx( | |
| 353 HKEY_LOCAL_MACHINE, | |
| 354 _T("SOFTWARE\\Microsoft\\Windows NT\\") | |
| 355 _T("CurrentVersion\\Hotfix\\Q246009"), | |
| 356 0, | |
| 357 KEY_QUERY_VALUE, | |
| 358 &hKey); | |
| 359 if (lRet == ERROR_SUCCESS) { | |
| 360 ::wsprintf(format_buffer, | |
| 361 _T("Service Pack 6a (Build %d)"), | |
| 362 osvi.dwBuildNumber & 0xFFFF); | |
| 363 SafeStrCat(buffer, format_buffer, buf_len); | |
| 364 } else { | |
| 365 // Windows NT 4.0 prior to SP6a. | |
| 366 ::wsprintf(format_buffer, _T("%s (Build %d)"), | |
| 367 osvi.szCSDVersion, | |
| 368 osvi.dwBuildNumber & 0xFFFF); | |
| 369 SafeStrCat(buffer, format_buffer, buf_len); | |
| 370 } | |
| 371 ::RegCloseKey(hKey); | |
| 372 } else { | |
| 373 // Windows NT 3.51 and earlier or Windows 2000 and later. | |
| 374 ::wsprintf(format_buffer, | |
| 375 _T("%s (Build %d)"), | |
| 376 osvi.szCSDVersion, | |
| 377 osvi.dwBuildNumber & 0xFFFF); | |
| 378 SafeStrCat(buffer, format_buffer, buf_len); | |
| 379 } | |
| 380 | |
| 381 break; | |
| 382 | |
| 383 // Test for the Windows 95 product family. | |
| 384 case VER_PLATFORM_WIN32_WINDOWS: | |
| 385 | |
| 386 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) { | |
| 387 SafeStrCat(buffer, _T("Microsoft Windows 95 "), buf_len); | |
| 388 if (osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B') { | |
| 389 SafeStrCat(buffer, _T("OSR2 "), buf_len); | |
| 390 } | |
| 391 } | |
| 392 | |
| 393 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) { | |
| 394 SafeStrCat(buffer, _T("Microsoft Windows 98 "), buf_len); | |
| 395 if (osvi.szCSDVersion[1] == 'A') { | |
| 396 SafeStrCat(buffer, _T("SE "), buf_len); | |
| 397 } | |
| 398 } | |
| 399 | |
| 400 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) { | |
| 401 SafeStrCat(buffer, | |
| 402 _T("Microsoft Windows Millennium Edition"), | |
| 403 buf_len); | |
| 404 } | |
| 405 break; | |
| 406 | |
| 407 case VER_PLATFORM_WIN32s: | |
| 408 | |
| 409 SafeStrCat(buffer, _T("Microsoft Win32s"), buf_len); | |
| 410 break; | |
| 411 | |
| 412 default: | |
| 413 SafeStrCat(buffer, _T("Unknown operating system"), buf_len); | |
| 414 break; | |
| 415 } | |
| 416 // SKIP_LOC_END | |
| 417 | |
| 418 // Remove trailing space, if any. | |
| 419 DWORD buffer_len = ::lstrlen(buffer); | |
| 420 if (buffer[buffer_len-1] == kNullChar) { | |
| 421 buffer[buffer_len-1] = kNullChar; | |
| 422 } | |
| 423 | |
| 424 // Copy to destination argument. | |
| 425 String_StrNCpy(name_buf, buffer, name_buf_len); | |
| 426 | |
| 427 return true; | |
| 428 } | |
| 429 | |
| 430 DWORD SystemInfo::GetProcessorArchitecture() { | |
| 431 static DWORD processor_architecture_cached(PROCESSOR_ARCHITECTURE_UNKNOWN); | |
| 432 | |
| 433 if (processor_architecture_cached == PROCESSOR_ARCHITECTURE_UNKNOWN) { | |
| 434 typedef void (WINAPI * GetSystemInfoFunc)(LPSYSTEM_INFO); | |
| 435 | |
| 436 HMODULE handle = ::GetModuleHandle(_T("kernel32")); | |
| 437 ASSERT1(handle); | |
| 438 GetSystemInfoFunc get_native_system_info = | |
| 439 reinterpret_cast<GetSystemInfoFunc>(::GetProcAddress( | |
| 440 handle, | |
| 441 "GetNativeSystemInfo")); | |
| 442 | |
| 443 if (get_native_system_info != NULL) { | |
| 444 SYSTEM_INFO sys_info = {0}; | |
| 445 | |
| 446 get_native_system_info(&sys_info); | |
| 447 | |
| 448 processor_architecture_cached = sys_info.wProcessorArchitecture; | |
| 449 } else { | |
| 450 // If we couldn't get the _native_ system info, then we must be on OS | |
| 451 // earlier than XP, so can't be 64-bit anyway. Assume Intel. | |
| 452 processor_architecture_cached = PROCESSOR_ARCHITECTURE_INTEL; | |
| 453 } | |
| 454 } | |
| 455 | |
| 456 return processor_architecture_cached; | |
| 457 } | |
| 458 | |
| 459 bool SystemInfo::Is64BitWindows() { | |
| 460 #if defined(_WIN64) | |
| 461 return true; | |
| 462 #else | |
| 463 return Process::IsWow64(::GetCurrentProcessId()); | |
| 464 #endif | |
| 465 } | |
| 466 | |
| 467 } // namespace omaha | |
| OLD | NEW |