OLD | NEW |
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_util.h" |
6 | 6 |
7 #include <aclapi.h> | 7 #include <aclapi.h> |
| 8 #include <shobjidl.h> // Must be before propkey. |
| 9 #include <propkey.h> |
8 #include <propvarutil.h> | 10 #include <propvarutil.h> |
9 #include <sddl.h> | 11 #include <sddl.h> |
10 #include <shlobj.h> | 12 #include <shlobj.h> |
11 | 13 |
12 #include "base/logging.h" | 14 #include "base/logging.h" |
13 #include "base/registry.h" | 15 #include "base/registry.h" |
14 #include "base/scoped_handle.h" | 16 #include "base/scoped_handle.h" |
15 #include "base/scoped_ptr.h" | 17 #include "base/scoped_ptr.h" |
16 #include "base/string_util.h" | 18 #include "base/string_util.h" |
17 #include "base/stringprintf.h" | 19 #include "base/stringprintf.h" |
| 20 #include "base/win/windows_version.h" |
18 | 21 |
19 namespace win_util { | 22 namespace win_util { |
20 | 23 |
21 #define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(struct_name, member) \ | 24 #define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(struct_name, member) \ |
22 offsetof(struct_name, member) + \ | 25 offsetof(struct_name, member) + \ |
23 (sizeof static_cast<struct_name*>(NULL)->member) | 26 (sizeof static_cast<struct_name*>(NULL)->member) |
24 #define NONCLIENTMETRICS_SIZE_PRE_VISTA \ | 27 #define NONCLIENTMETRICS_SIZE_PRE_VISTA \ |
25 SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont) | 28 SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont) |
26 | 29 |
27 const PROPERTYKEY kPKEYAppUserModelID = | |
28 { { 0x9F4C2855, 0x9F79, 0x4B39, | |
29 { 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, } }, 5 }; | |
30 | |
31 void GetNonClientMetrics(NONCLIENTMETRICS* metrics) { | 30 void GetNonClientMetrics(NONCLIENTMETRICS* metrics) { |
32 DCHECK(metrics); | 31 DCHECK(metrics); |
33 | 32 |
34 static const UINT SIZEOF_NONCLIENTMETRICS = | 33 static const UINT SIZEOF_NONCLIENTMETRICS = |
35 (GetWinVersion() >= WINVERSION_VISTA) ? | 34 (base::win::GetVersion() >= base::win::VERSION_VISTA) ? |
36 sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; | 35 sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; |
37 metrics->cbSize = SIZEOF_NONCLIENTMETRICS; | 36 metrics->cbSize = SIZEOF_NONCLIENTMETRICS; |
38 const bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, | 37 const bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, |
39 SIZEOF_NONCLIENTMETRICS, metrics, | 38 SIZEOF_NONCLIENTMETRICS, metrics, |
40 0); | 39 0); |
41 DCHECK(success); | 40 DCHECK(success); |
42 } | 41 } |
43 | 42 |
44 WinVersion GetWinVersion() { | |
45 static bool checked_version = false; | |
46 static WinVersion win_version = WINVERSION_PRE_2000; | |
47 if (!checked_version) { | |
48 OSVERSIONINFOEX version_info; | |
49 version_info.dwOSVersionInfoSize = sizeof version_info; | |
50 GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info)); | |
51 if (version_info.dwMajorVersion == 5) { | |
52 switch (version_info.dwMinorVersion) { | |
53 case 0: | |
54 win_version = WINVERSION_2000; | |
55 break; | |
56 case 1: | |
57 win_version = WINVERSION_XP; | |
58 break; | |
59 case 2: | |
60 default: | |
61 win_version = WINVERSION_SERVER_2003; | |
62 break; | |
63 } | |
64 } else if (version_info.dwMajorVersion == 6) { | |
65 if (version_info.wProductType != VER_NT_WORKSTATION) { | |
66 // 2008 is 6.0, and 2008 R2 is 6.1. | |
67 win_version = WINVERSION_2008; | |
68 } else { | |
69 if (version_info.dwMinorVersion == 0) { | |
70 win_version = WINVERSION_VISTA; | |
71 } else { | |
72 win_version = WINVERSION_WIN7; | |
73 } | |
74 } | |
75 } else if (version_info.dwMajorVersion > 6) { | |
76 win_version = WINVERSION_WIN7; | |
77 } | |
78 checked_version = true; | |
79 } | |
80 return win_version; | |
81 } | |
82 | |
83 void GetServicePackLevel(int* major, int* minor) { | |
84 DCHECK(major && minor); | |
85 static bool checked_version = false; | |
86 static int service_pack_major = -1; | |
87 static int service_pack_minor = -1; | |
88 if (!checked_version) { | |
89 OSVERSIONINFOEX version_info = {0}; | |
90 version_info.dwOSVersionInfoSize = sizeof(version_info); | |
91 GetVersionEx(reinterpret_cast<OSVERSIONINFOW*>(&version_info)); | |
92 service_pack_major = version_info.wServicePackMajor; | |
93 service_pack_minor = version_info.wServicePackMinor; | |
94 checked_version = true; | |
95 } | |
96 | |
97 *major = service_pack_major; | |
98 *minor = service_pack_minor; | |
99 } | |
100 | |
101 bool AddAccessToKernelObject(HANDLE handle, WELL_KNOWN_SID_TYPE known_sid, | |
102 ACCESS_MASK access) { | |
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) { | 43 bool GetUserSidString(std::wstring* user_sid) { |
173 // Get the current token. | 44 // Get the current token. |
174 HANDLE token = NULL; | 45 HANDLE token = NULL; |
175 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token)) | 46 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token)) |
176 return false; | 47 return false; |
177 ScopedHandle token_scoped(token); | 48 ScopedHandle token_scoped(token); |
178 | 49 |
179 DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE; | 50 DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE; |
180 scoped_array<BYTE> user_bytes(new BYTE[size]); | 51 scoped_array<BYTE> user_bytes(new BYTE[size]); |
181 TOKEN_USER* user = reinterpret_cast<TOKEN_USER*>(user_bytes.get()); | 52 TOKEN_USER* user = reinterpret_cast<TOKEN_USER*>(user_bytes.get()); |
182 | 53 |
183 if (!::GetTokenInformation(token, TokenUser, user, size, &size)) | 54 if (!::GetTokenInformation(token, TokenUser, user, size, &size)) |
184 return false; | 55 return false; |
185 | 56 |
186 if (!user->User.Sid) | 57 if (!user->User.Sid) |
187 return false; | 58 return false; |
188 | 59 |
189 // Convert the data to a string. | 60 // Convert the data to a string. |
190 wchar_t* sid_string; | 61 wchar_t* sid_string; |
191 if (!::ConvertSidToStringSid(user->User.Sid, &sid_string)) | 62 if (!::ConvertSidToStringSid(user->User.Sid, &sid_string)) |
192 return false; | 63 return false; |
193 | 64 |
194 *user_sid = sid_string; | 65 *user_sid = sid_string; |
195 | 66 |
196 ::LocalFree(sid_string); | 67 ::LocalFree(sid_string); |
197 | 68 |
198 return true; | 69 return true; |
199 } | 70 } |
200 | 71 |
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) | 72 #pragma warning(push) |
258 #pragma warning(disable:4312 4244) | 73 #pragma warning(disable:4312 4244) |
259 WNDPROC SetWindowProc(HWND hwnd, WNDPROC proc) { | 74 WNDPROC SetWindowProc(HWND hwnd, WNDPROC proc) { |
260 // The reason we don't return the SetwindowLongPtr() value is that it returns | 75 // 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 | 76 // the orignal window procedure and not the current one. I don't know if it is |
262 // a bug or an intended feature. | 77 // a bug or an intended feature. |
263 WNDPROC oldwindow_proc = | 78 WNDPROC oldwindow_proc = |
264 reinterpret_cast<WNDPROC>(GetWindowLongPtr(hwnd, GWLP_WNDPROC)); | 79 reinterpret_cast<WNDPROC>(GetWindowLongPtr(hwnd, GWLP_WNDPROC)); |
265 SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(proc)); | 80 SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(proc)); |
266 return oldwindow_proc; | 81 return oldwindow_proc; |
267 } | 82 } |
268 | 83 |
269 void* SetWindowUserData(HWND hwnd, void* user_data) { | 84 void* SetWindowUserData(HWND hwnd, void* user_data) { |
270 return | 85 return |
271 reinterpret_cast<void*>(SetWindowLongPtr(hwnd, GWLP_USERDATA, | 86 reinterpret_cast<void*>(SetWindowLongPtr(hwnd, GWLP_USERDATA, |
272 reinterpret_cast<LONG_PTR>(user_data))); | 87 reinterpret_cast<LONG_PTR>(user_data))); |
273 } | 88 } |
274 | 89 |
275 void* GetWindowUserData(HWND hwnd) { | 90 void* GetWindowUserData(HWND hwnd) { |
276 return reinterpret_cast<void*>(GetWindowLongPtr(hwnd, GWLP_USERDATA)); | 91 return reinterpret_cast<void*>(GetWindowLongPtr(hwnd, GWLP_USERDATA)); |
277 } | 92 } |
278 | 93 |
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) | 94 #pragma warning(pop) |
320 | 95 |
321 bool IsShiftPressed() { | 96 bool IsShiftPressed() { |
322 return (::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000; | 97 return (::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000; |
323 } | 98 } |
324 | 99 |
325 bool IsCtrlPressed() { | 100 bool IsCtrlPressed() { |
326 return (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000; | 101 return (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000; |
327 } | 102 } |
328 | 103 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
391 | 166 |
392 // App id should be less than 128 chars and contain no space. And recommended | 167 // App id should be less than 128 chars and contain no space. And recommended |
393 // format is CompanyName.ProductName[.SubProduct.ProductNumber]. | 168 // format is CompanyName.ProductName[.SubProduct.ProductNumber]. |
394 // See http://msdn.microsoft.com/en-us/library/dd378459%28VS.85%29.aspx | 169 // See http://msdn.microsoft.com/en-us/library/dd378459%28VS.85%29.aspx |
395 DCHECK(lstrlen(app_id) < 128 && wcschr(app_id, L' ') == NULL); | 170 DCHECK(lstrlen(app_id) < 128 && wcschr(app_id, L' ') == NULL); |
396 | 171 |
397 PROPVARIANT property_value; | 172 PROPVARIANT property_value; |
398 if (FAILED(InitPropVariantFromString(app_id, &property_value))) | 173 if (FAILED(InitPropVariantFromString(app_id, &property_value))) |
399 return false; | 174 return false; |
400 | 175 |
401 HRESULT result = property_store->SetValue(kPKEYAppUserModelID, | 176 HRESULT result = property_store->SetValue(PKEY_AppUserModel_ID, |
402 property_value); | 177 property_value); |
403 if (S_OK == result) | 178 if (S_OK == result) |
404 result = property_store->Commit(); | 179 result = property_store->Commit(); |
405 | 180 |
406 PropVariantClear(&property_value); | 181 PropVariantClear(&property_value); |
407 return SUCCEEDED(result); | 182 return SUCCEEDED(result); |
408 } | 183 } |
409 | 184 |
410 static const char16 kAutoRunKeyPath[] = | 185 static const char16 kAutoRunKeyPath[] = |
411 L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; | 186 L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; |
(...skipping 25 matching lines...) Expand all Loading... |
437 | 212 |
438 #ifndef COPY_FILE_COPY_SYMLINK | 213 #ifndef COPY_FILE_COPY_SYMLINK |
439 #error You must install the Windows 2008 or Vista Software Development Kit and \ | 214 #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 \ | 215 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. \ | 216 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 \ | 217 Also make sure you register the SDK with Visual Studio, by selecting \ |
443 "Integrate Windows SDK with Visual Studio 2005" from the Windows SDK \ | 218 "Integrate Windows SDK with Visual Studio 2005" from the Windows SDK \ |
444 menu (see Start - All Programs - Microsoft Windows SDK - \ | 219 menu (see Start - All Programs - Microsoft Windows SDK - \ |
445 Visual Studio Registration). | 220 Visual Studio Registration). |
446 #endif | 221 #endif |
OLD | NEW |