Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(213)

Side by Side Diff: base/win/windows_version.cc

Issue 3823002: Move windows version-related stuff out of base/win_util and into base/win/win... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/win_util.h" 5 #include "base/win/windows_version.h"
6 6
7 #include <aclapi.h> 7 #include <windows.h>
8 #include <propvarutil.h>
9 #include <sddl.h>
10 #include <shlobj.h>
11 8
12 #include "base/logging.h" 9 #include "base/logging.h"
13 #include "base/registry.h"
14 #include "base/scoped_handle.h"
15 #include "base/scoped_ptr.h"
16 #include "base/string_util.h"
17 #include "base/stringprintf.h"
18 10
19 namespace win_util { 11 namespace base {
12 namespace win {
20 13
21 #define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(struct_name, member) \ 14 Version GetWinVersion() {
22 offsetof(struct_name, member) + \
23 (sizeof static_cast<struct_name*>(NULL)->member)
24 #define NONCLIENTMETRICS_SIZE_PRE_VISTA \
25 SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont)
26
27 const PROPERTYKEY kPKEYAppUserModelID =
28 { { 0x9F4C2855, 0x9F79, 0x4B39,
29 { 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, } }, 5 };
30
31 void GetNonClientMetrics(NONCLIENTMETRICS* metrics) {
32 DCHECK(metrics);
33
34 static const UINT SIZEOF_NONCLIENTMETRICS =
35 (GetWinVersion() >= WINVERSION_VISTA) ?
36 sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA;
37 metrics->cbSize = SIZEOF_NONCLIENTMETRICS;
38 const bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
39 SIZEOF_NONCLIENTMETRICS, metrics,
40 0);
41 DCHECK(success);
42 }
43
44 WinVersion GetWinVersion() {
45 static bool checked_version = false; 15 static bool checked_version = false;
46 static WinVersion win_version = WINVERSION_PRE_2000; 16 static Version win_version = VERSION_PRE_2000;
47 if (!checked_version) { 17 if (!checked_version) {
48 OSVERSIONINFOEX version_info; 18 OSVERSIONINFOEX version_info;
49 version_info.dwOSVersionInfoSize = sizeof version_info; 19 version_info.dwOSVersionInfoSize = sizeof version_info;
50 GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info)); 20 GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info));
51 if (version_info.dwMajorVersion == 5) { 21 if (version_info.dwMajorVersion == 5) {
52 switch (version_info.dwMinorVersion) { 22 switch (version_info.dwMinorVersion) {
53 case 0: 23 case 0:
54 win_version = WINVERSION_2000; 24 win_version = VERSION_2000;
55 break; 25 break;
56 case 1: 26 case 1:
57 win_version = WINVERSION_XP; 27 win_version = VERSION_XP;
58 break; 28 break;
59 case 2: 29 case 2:
60 default: 30 default:
61 win_version = WINVERSION_SERVER_2003; 31 win_version = VERSION_SERVER_2003;
62 break; 32 break;
63 } 33 }
64 } else if (version_info.dwMajorVersion == 6) { 34 } else if (version_info.dwMajorVersion == 6) {
65 if (version_info.wProductType != VER_NT_WORKSTATION) { 35 if (version_info.wProductType != VER_NT_WORKSTATION) {
66 // 2008 is 6.0, and 2008 R2 is 6.1. 36 // 2008 is 6.0, and 2008 R2 is 6.1.
67 win_version = WINVERSION_2008; 37 win_version = VERSION_2008;
68 } else { 38 } else {
69 if (version_info.dwMinorVersion == 0) { 39 if (version_info.dwMinorVersion == 0) {
70 win_version = WINVERSION_VISTA; 40 win_version = VERSION_VISTA;
71 } else { 41 } else {
72 win_version = WINVERSION_WIN7; 42 win_version = VERSION_WIN7;
73 } 43 }
74 } 44 }
75 } else if (version_info.dwMajorVersion > 6) { 45 } else if (version_info.dwMajorVersion > 6) {
76 win_version = WINVERSION_WIN7; 46 win_version = VERSION_WIN7;
77 } 47 }
78 checked_version = true; 48 checked_version = true;
79 } 49 }
80 return win_version; 50 return win_version;
81 } 51 }
82 52
83 void GetServicePackLevel(int* major, int* minor) { 53 void GetServicePackLevel(int* major, int* minor) {
84 DCHECK(major && minor); 54 DCHECK(major && minor);
85 static bool checked_version = false; 55 static bool checked_version = false;
86 static int service_pack_major = -1; 56 static int service_pack_major = -1;
87 static int service_pack_minor = -1; 57 static int service_pack_minor = -1;
88 if (!checked_version) { 58 if (!checked_version) {
89 OSVERSIONINFOEX version_info = {0}; 59 OSVERSIONINFOEX version_info = {0};
90 version_info.dwOSVersionInfoSize = sizeof(version_info); 60 version_info.dwOSVersionInfoSize = sizeof(version_info);
91 GetVersionEx(reinterpret_cast<OSVERSIONINFOW*>(&version_info)); 61 GetVersionEx(reinterpret_cast<OSVERSIONINFOW*>(&version_info));
92 service_pack_major = version_info.wServicePackMajor; 62 service_pack_major = version_info.wServicePackMajor;
93 service_pack_minor = version_info.wServicePackMinor; 63 service_pack_minor = version_info.wServicePackMinor;
94 checked_version = true; 64 checked_version = true;
95 } 65 }
96 66
97 *major = service_pack_major; 67 *major = service_pack_major;
98 *minor = service_pack_minor; 68 *minor = service_pack_minor;
99 } 69 }
100 70
101 bool AddAccessToKernelObject(HANDLE handle, WELL_KNOWN_SID_TYPE known_sid, 71 } // namespace win
102 ACCESS_MASK access) { 72 } // namespace base
103 PSECURITY_DESCRIPTOR descriptor = NULL;
104 PACL old_dacl = NULL;
105 PACL new_dacl = NULL;
106
107 if (ERROR_SUCCESS != GetSecurityInfo(handle, SE_KERNEL_OBJECT,
108 DACL_SECURITY_INFORMATION, NULL, NULL, &old_dacl, NULL,
109 &descriptor))
110 return false;
111
112 BYTE sid[SECURITY_MAX_SID_SIZE] = {0};
113 DWORD size_sid = SECURITY_MAX_SID_SIZE;
114
115 if (known_sid == WinSelfSid) {
116 // We hijack WinSelfSid when we want to add the current user instead of
117 // a known sid.
118 HANDLE token = NULL;
119 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) {
120 LocalFree(descriptor);
121 return false;
122 }
123
124 DWORD size = sizeof(TOKEN_USER) + size_sid;
125 scoped_array<BYTE> token_user_bytes(new BYTE[size]);
126 TOKEN_USER* token_user =
127 reinterpret_cast<TOKEN_USER*>(token_user_bytes.get());
128 BOOL ret = GetTokenInformation(token, TokenUser, token_user, size, &size);
129
130 CloseHandle(token);
131
132 if (!ret) {
133 LocalFree(descriptor);
134 return false;
135 }
136 memcpy(sid, token_user->User.Sid, size_sid);
137 } else {
138 if (!CreateWellKnownSid(known_sid , NULL, sid, &size_sid)) {
139 LocalFree(descriptor);
140 return false;
141 }
142 }
143
144 EXPLICIT_ACCESS new_access = {0};
145 new_access.grfAccessMode = GRANT_ACCESS;
146 new_access.grfAccessPermissions = access;
147 new_access.grfInheritance = NO_INHERITANCE;
148
149 new_access.Trustee.pMultipleTrustee = NULL;
150 new_access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
151 new_access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
152 new_access.Trustee.ptstrName = reinterpret_cast<LPWSTR>(&sid);
153
154 if (ERROR_SUCCESS != SetEntriesInAcl(1, &new_access, old_dacl, &new_dacl)) {
155 LocalFree(descriptor);
156 return false;
157 }
158
159 DWORD result = SetSecurityInfo(handle, SE_KERNEL_OBJECT,
160 DACL_SECURITY_INFORMATION, NULL, NULL,
161 new_dacl, NULL);
162
163 LocalFree(new_dacl);
164 LocalFree(descriptor);
165
166 if (ERROR_SUCCESS != result)
167 return false;
168
169 return true;
170 }
171
172 bool GetUserSidString(std::wstring* user_sid) {
173 // Get the current token.
174 HANDLE token = NULL;
175 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token))
176 return false;
177 ScopedHandle token_scoped(token);
178
179 DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
180 scoped_array<BYTE> user_bytes(new BYTE[size]);
181 TOKEN_USER* user = reinterpret_cast<TOKEN_USER*>(user_bytes.get());
182
183 if (!::GetTokenInformation(token, TokenUser, user, size, &size))
184 return false;
185
186 if (!user->User.Sid)
187 return false;
188
189 // Convert the data to a string.
190 wchar_t* sid_string;
191 if (!::ConvertSidToStringSid(user->User.Sid, &sid_string))
192 return false;
193
194 *user_sid = sid_string;
195
196 ::LocalFree(sid_string);
197
198 return true;
199 }
200
201 bool GetLogonSessionOnlyDACL(SECURITY_DESCRIPTOR** security_descriptor) {
202 // Get the current token.
203 HANDLE token = NULL;
204 if (!OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token))
205 return false;
206 ScopedHandle token_scoped(token);
207
208 // Get the size of the TokenGroups structure.
209 DWORD size = 0;
210 BOOL result = GetTokenInformation(token, TokenGroups, NULL, 0, &size);
211 if (result != FALSE && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
212 return false;
213
214 // Get the data.
215 scoped_array<char> token_groups_chars(new char[size]);
216 TOKEN_GROUPS* token_groups =
217 reinterpret_cast<TOKEN_GROUPS*>(token_groups_chars.get());
218
219 if (!GetTokenInformation(token, TokenGroups, token_groups, size, &size))
220 return false;
221
222 // Look for the logon sid.
223 SID* logon_sid = NULL;
224 for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
225 if ((token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) != 0) {
226 logon_sid = static_cast<SID*>(token_groups->Groups[i].Sid);
227 break;
228 }
229 }
230
231 if (!logon_sid)
232 return false;
233
234 // Convert the data to a string.
235 wchar_t* sid_string;
236 if (!ConvertSidToStringSid(logon_sid, &sid_string))
237 return false;
238
239 static const wchar_t dacl_format[] = L"D:(A;OICI;GA;;;%ls)";
240 wchar_t dacl[SECURITY_MAX_SID_SIZE + arraysize(dacl_format) + 1] = {0};
241 wsprintf(dacl, dacl_format, sid_string);
242
243 LocalFree(sid_string);
244
245 // Convert the string to a security descriptor
246 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
247 dacl,
248 SDDL_REVISION_1,
249 reinterpret_cast<PSECURITY_DESCRIPTOR*>(security_descriptor),
250 NULL)) {
251 return false;
252 }
253
254 return true;
255 }
256
257 #pragma warning(push)
258 #pragma warning(disable:4312 4244)
259 WNDPROC SetWindowProc(HWND hwnd, WNDPROC proc) {
260 // The reason we don't return the SetwindowLongPtr() value is that it returns
261 // the orignal window procedure and not the current one. I don't know if it is
262 // a bug or an intended feature.
263 WNDPROC oldwindow_proc =
264 reinterpret_cast<WNDPROC>(GetWindowLongPtr(hwnd, GWLP_WNDPROC));
265 SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(proc));
266 return oldwindow_proc;
267 }
268
269 void* SetWindowUserData(HWND hwnd, void* user_data) {
270 return
271 reinterpret_cast<void*>(SetWindowLongPtr(hwnd, GWLP_USERDATA,
272 reinterpret_cast<LONG_PTR>(user_data)));
273 }
274
275 void* GetWindowUserData(HWND hwnd) {
276 return reinterpret_cast<void*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
277 }
278
279 // Maps to the WNDPROC for a window that was active before the subclass was
280 // installed.
281 static const wchar_t* const kHandlerKey = L"__ORIGINAL_MESSAGE_HANDLER__";
282
283 bool IsSubclassed(HWND window, WNDPROC subclass_proc) {
284 WNDPROC original_handler =
285 reinterpret_cast<WNDPROC>(GetWindowLongPtr(window, GWLP_WNDPROC));
286 return original_handler == subclass_proc;
287 }
288
289 bool Subclass(HWND window, WNDPROC subclass_proc) {
290 WNDPROC original_handler =
291 reinterpret_cast<WNDPROC>(GetWindowLongPtr(window, GWLP_WNDPROC));
292 if (original_handler != subclass_proc) {
293 win_util::SetWindowProc(window, subclass_proc);
294 SetProp(window, kHandlerKey, original_handler);
295 return true;
296 }
297 return false;
298 }
299
300 bool Unsubclass(HWND window, WNDPROC subclass_proc) {
301 WNDPROC current_handler =
302 reinterpret_cast<WNDPROC>(GetWindowLongPtr(window, GWLP_WNDPROC));
303 if (current_handler == subclass_proc) {
304 HANDLE original_handler = GetProp(window, kHandlerKey);
305 if (original_handler) {
306 RemoveProp(window, kHandlerKey);
307 win_util::SetWindowProc(window,
308 reinterpret_cast<WNDPROC>(original_handler));
309 return true;
310 }
311 }
312 return false;
313 }
314
315 WNDPROC GetSuperclassWNDPROC(HWND window) {
316 return reinterpret_cast<WNDPROC>(GetProp(window, kHandlerKey));
317 }
318
319 #pragma warning(pop)
320
321 bool IsShiftPressed() {
322 return (::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000;
323 }
324
325 bool IsCtrlPressed() {
326 return (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000;
327 }
328
329 bool IsAltPressed() {
330 return (::GetKeyState(VK_MENU) & 0x8000) == 0x8000;
331 }
332
333 std::wstring GetClassName(HWND window) {
334 // GetClassNameW will return a truncated result (properly null terminated) if
335 // the given buffer is not large enough. So, it is not possible to determine
336 // that we got the entire class name if the result is exactly equal to the
337 // size of the buffer minus one.
338 DWORD buffer_size = MAX_PATH;
339 while (true) {
340 std::wstring output;
341 DWORD size_ret =
342 GetClassNameW(window, WriteInto(&output, buffer_size), buffer_size);
343 if (size_ret == 0)
344 break;
345 if (size_ret < (buffer_size - 1)) {
346 output.resize(size_ret);
347 return output;
348 }
349 buffer_size *= 2;
350 }
351 return std::wstring(); // error
352 }
353
354 bool UserAccountControlIsEnabled() {
355 RegKey key(HKEY_LOCAL_MACHINE,
356 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
357 KEY_READ);
358 DWORD uac_enabled;
359 if (!key.ReadValueDW(L"EnableLUA", &uac_enabled))
360 return true;
361 // Users can set the EnableLUA value to something arbitrary, like 2, which
362 // Vista will treat as UAC enabled, so we make sure it is not set to 0.
363 return (uac_enabled != 0);
364 }
365
366 std::wstring FormatMessage(unsigned messageid) {
367 wchar_t* string_buffer = NULL;
368 unsigned string_length = ::FormatMessage(
369 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
370 FORMAT_MESSAGE_IGNORE_INSERTS, NULL, messageid, 0,
371 reinterpret_cast<wchar_t *>(&string_buffer), 0, NULL);
372
373 std::wstring formatted_string;
374 if (string_buffer) {
375 formatted_string = string_buffer;
376 LocalFree(reinterpret_cast<HLOCAL>(string_buffer));
377 } else {
378 // The formating failed. simply convert the message value into a string.
379 base::SStringPrintf(&formatted_string, L"message number %d", messageid);
380 }
381 return formatted_string;
382 }
383
384 std::wstring FormatLastWin32Error() {
385 return FormatMessage(GetLastError());
386 }
387
388 bool SetAppIdForPropertyStore(IPropertyStore* property_store,
389 const wchar_t* app_id) {
390 DCHECK(property_store);
391
392 // App id should be less than 128 chars and contain no space. And recommended
393 // format is CompanyName.ProductName[.SubProduct.ProductNumber].
394 // See http://msdn.microsoft.com/en-us/library/dd378459%28VS.85%29.aspx
395 DCHECK(lstrlen(app_id) < 128 && wcschr(app_id, L' ') == NULL);
396
397 PROPVARIANT property_value;
398 if (FAILED(InitPropVariantFromString(app_id, &property_value)))
399 return false;
400
401 HRESULT result = property_store->SetValue(kPKEYAppUserModelID,
402 property_value);
403 if (S_OK == result)
404 result = property_store->Commit();
405
406 PropVariantClear(&property_value);
407 return SUCCEEDED(result);
408 }
409
410 static const char16 kAutoRunKeyPath[] =
411 L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
412
413 bool AddCommandToAutoRun(HKEY root_key, const string16& name,
414 const string16& command) {
415 RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
416 return autorun_key.WriteValue(name.c_str(), command.c_str());
417 }
418
419 bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name) {
420 RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
421 return autorun_key.DeleteValue(name.c_str());
422 }
423
424 } // namespace win_util
425
426 #ifdef _MSC_VER
427 //
428 // If the ASSERT below fails, please install Visual Studio 2005 Service Pack 1.
429 //
430 extern char VisualStudio2005ServicePack1Detection[10];
431 COMPILE_ASSERT(sizeof(&VisualStudio2005ServicePack1Detection) == sizeof(void*),
432 VS2005SP1Detect);
433 //
434 // Chrome requires at least Service Pack 1 for Visual Studio 2005.
435 //
436 #endif // _MSC_VER
437
438 #ifndef COPY_FILE_COPY_SYMLINK
439 #error You must install the Windows 2008 or Vista Software Development Kit and \
440 set it as your default include path to build this library. You can grab it by \
441 searching for "download windows sdk 2008" in your favorite web search engine. \
442 Also make sure you register the SDK with Visual Studio, by selecting \
443 "Integrate Windows SDK with Visual Studio 2005" from the Windows SDK \
444 menu (see Start - All Programs - Microsoft Windows SDK - \
445 Visual Studio Registration).
446 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698