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 |