| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "base/win/win_util.h" | |
| 6 | |
| 7 #include <aclapi.h> | |
| 8 #include <cfgmgr32.h> | |
| 9 #include <lm.h> | |
| 10 #include <powrprof.h> | |
| 11 #include <shellapi.h> | |
| 12 #include <shlobj.h> | |
| 13 #include <shobjidl.h> // Must be before propkey. | |
| 14 #include <initguid.h> | |
| 15 #include <propkey.h> | |
| 16 #include <propvarutil.h> | |
| 17 #include <sddl.h> | |
| 18 #include <setupapi.h> | |
| 19 #include <signal.h> | |
| 20 #include <stdlib.h> | |
| 21 | |
| 22 #include "base/base_switches.h" | |
| 23 #include "base/command_line.h" | |
| 24 #include "base/lazy_instance.h" | |
| 25 #include "base/logging.h" | |
| 26 #include "base/memory/scoped_ptr.h" | |
| 27 #include "base/strings/string_util.h" | |
| 28 #include "base/strings/stringprintf.h" | |
| 29 #include "base/strings/utf_string_conversions.h" | |
| 30 #include "base/threading/thread_restrictions.h" | |
| 31 #include "base/win/metro.h" | |
| 32 #include "base/win/registry.h" | |
| 33 #include "base/win/scoped_co_mem.h" | |
| 34 #include "base/win/scoped_handle.h" | |
| 35 #include "base/win/scoped_propvariant.h" | |
| 36 #include "base/win/windows_version.h" | |
| 37 | |
| 38 namespace base { | |
| 39 namespace win { | |
| 40 | |
| 41 namespace { | |
| 42 | |
| 43 // Sets the value of |property_key| to |property_value| in |property_store|. | |
| 44 bool SetPropVariantValueForPropertyStore( | |
| 45 IPropertyStore* property_store, | |
| 46 const PROPERTYKEY& property_key, | |
| 47 const ScopedPropVariant& property_value) { | |
| 48 DCHECK(property_store); | |
| 49 | |
| 50 HRESULT result = property_store->SetValue(property_key, property_value.get()); | |
| 51 if (result == S_OK) | |
| 52 result = property_store->Commit(); | |
| 53 return SUCCEEDED(result); | |
| 54 } | |
| 55 | |
| 56 void __cdecl ForceCrashOnSigAbort(int) { | |
| 57 *((volatile int*)0) = 0x1337; | |
| 58 } | |
| 59 | |
| 60 const wchar_t kWindows8OSKRegPath[] = | |
| 61 L"Software\\Classes\\CLSID\\{054AAE20-4BEA-4347-8A35-64A533254A9D}" | |
| 62 L"\\LocalServer32"; | |
| 63 | |
| 64 } // namespace | |
| 65 | |
| 66 // Returns true if a physical keyboard is detected on Windows 8 and up. | |
| 67 // Uses the Setup APIs to enumerate the attached keyboards and returns true | |
| 68 // if the keyboard count is 1 or more.. While this will work in most cases | |
| 69 // it won't work if there are devices which expose keyboard interfaces which | |
| 70 // are attached to the machine. | |
| 71 bool IsKeyboardPresentOnSlate(std::string* reason) { | |
| 72 bool result = false; | |
| 73 | |
| 74 if (GetVersion() < VERSION_WIN7) { | |
| 75 *reason = "Detection not supported"; | |
| 76 return false; | |
| 77 } | |
| 78 | |
| 79 // This function is only supported for Windows 8 and up. | |
| 80 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 81 switches::kDisableUsbKeyboardDetect)) { | |
| 82 if (reason) | |
| 83 *reason = "Detection disabled"; | |
| 84 return false; | |
| 85 } | |
| 86 | |
| 87 // This function should be only invoked for machines with touch screens. | |
| 88 if ((GetSystemMetrics(SM_DIGITIZER) & NID_INTEGRATED_TOUCH) | |
| 89 != NID_INTEGRATED_TOUCH) { | |
| 90 if (reason) { | |
| 91 *reason += "NID_INTEGRATED_TOUCH\n"; | |
| 92 result = true; | |
| 93 } else { | |
| 94 return true; | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 // If the device is docked, the user is treating the device as a PC. | |
| 99 if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0) { | |
| 100 if (reason) { | |
| 101 *reason += "SM_SYSTEMDOCKED\n"; | |
| 102 result = true; | |
| 103 } else { | |
| 104 return true; | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 // To determine whether a keyboard is present on the device, we do the | |
| 109 // following:- | |
| 110 // 1. Check whether the device supports auto rotation. If it does then | |
| 111 // it possibly supports flipping from laptop to slate mode. If it | |
| 112 // does not support auto rotation, then we assume it is a desktop | |
| 113 // or a normal laptop and assume that there is a keyboard. | |
| 114 | |
| 115 // 2. If the device supports auto rotation, then we get its platform role | |
| 116 // and check the system metric SM_CONVERTIBLESLATEMODE to see if it is | |
| 117 // being used in slate mode. If yes then we return false here to ensure | |
| 118 // that the OSK is displayed. | |
| 119 | |
| 120 // 3. If step 1 and 2 fail then we check attached keyboards and return true | |
| 121 // if we find ACPI\* or HID\VID* keyboards. | |
| 122 | |
| 123 typedef BOOL (WINAPI* GetAutoRotationState)(PAR_STATE state); | |
| 124 | |
| 125 GetAutoRotationState get_rotation_state = | |
| 126 reinterpret_cast<GetAutoRotationState>(::GetProcAddress( | |
| 127 GetModuleHandle(L"user32.dll"), "GetAutoRotationState")); | |
| 128 | |
| 129 if (get_rotation_state) { | |
| 130 AR_STATE auto_rotation_state = AR_ENABLED; | |
| 131 get_rotation_state(&auto_rotation_state); | |
| 132 if ((auto_rotation_state & AR_NOSENSOR) || | |
| 133 (auto_rotation_state & AR_NOT_SUPPORTED)) { | |
| 134 // If there is no auto rotation sensor or rotation is not supported in | |
| 135 // the current configuration, then we can assume that this is a desktop | |
| 136 // or a traditional laptop. | |
| 137 if (reason) { | |
| 138 *reason += (auto_rotation_state & AR_NOSENSOR) ? "AR_NOSENSOR\n" | |
| 139 : "AR_NOT_SUPPORTED\n"; | |
| 140 result = true; | |
| 141 } else { | |
| 142 return true; | |
| 143 } | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 // Check if the device is being used as a laptop or a tablet. This can be | |
| 148 // checked by first checking the role of the device and then the | |
| 149 // corresponding system metric (SM_CONVERTIBLESLATEMODE). If it is being used | |
| 150 // as a tablet then we want the OSK to show up. | |
| 151 POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole(); | |
| 152 | |
| 153 if (((role == PlatformRoleMobile) || (role == PlatformRoleSlate)) && | |
| 154 (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0)) { | |
| 155 if (reason) { | |
| 156 *reason += (role == PlatformRoleMobile) ? "PlatformRoleMobile\n" | |
| 157 : "PlatformRoleSlate\n"; | |
| 158 // Don't change result here if it's already true. | |
| 159 } else { | |
| 160 return false; | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 const GUID KEYBOARD_CLASS_GUID = | |
| 165 { 0x4D36E96B, 0xE325, 0x11CE, | |
| 166 { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } }; | |
| 167 | |
| 168 // Query for all the keyboard devices. | |
| 169 HDEVINFO device_info = | |
| 170 SetupDiGetClassDevs(&KEYBOARD_CLASS_GUID, NULL, NULL, DIGCF_PRESENT); | |
| 171 if (device_info == INVALID_HANDLE_VALUE) { | |
| 172 if (reason) | |
| 173 *reason += "No keyboard info\n"; | |
| 174 return result; | |
| 175 } | |
| 176 | |
| 177 // Enumerate all keyboards and look for ACPI\PNP and HID\VID devices. If | |
| 178 // the count is more than 1 we assume that a keyboard is present. This is | |
| 179 // under the assumption that there will always be one keyboard device. | |
| 180 for (DWORD i = 0;; ++i) { | |
| 181 SP_DEVINFO_DATA device_info_data = { 0 }; | |
| 182 device_info_data.cbSize = sizeof(device_info_data); | |
| 183 if (!SetupDiEnumDeviceInfo(device_info, i, &device_info_data)) | |
| 184 break; | |
| 185 | |
| 186 // Get the device ID. | |
| 187 wchar_t device_id[MAX_DEVICE_ID_LEN]; | |
| 188 CONFIGRET status = CM_Get_Device_ID(device_info_data.DevInst, | |
| 189 device_id, | |
| 190 MAX_DEVICE_ID_LEN, | |
| 191 0); | |
| 192 if (status == CR_SUCCESS) { | |
| 193 // To reduce the scope of the hack we only look for ACPI and HID\\VID | |
| 194 // prefixes in the keyboard device ids. | |
| 195 if (StartsWith(device_id, L"ACPI", CompareCase::INSENSITIVE_ASCII) || | |
| 196 StartsWith(device_id, L"HID\\VID", CompareCase::INSENSITIVE_ASCII)) { | |
| 197 if (reason) { | |
| 198 *reason += "device: "; | |
| 199 *reason += WideToUTF8(device_id); | |
| 200 *reason += '\n'; | |
| 201 } | |
| 202 // The heuristic we are using is to check the count of keyboards and | |
| 203 // return true if the API's report one or more keyboards. Please note | |
| 204 // that this will break for non keyboard devices which expose a | |
| 205 // keyboard PDO. | |
| 206 result = true; | |
| 207 } | |
| 208 } | |
| 209 } | |
| 210 return result; | |
| 211 } | |
| 212 | |
| 213 static bool g_crash_on_process_detach = false; | |
| 214 | |
| 215 void GetNonClientMetrics(NONCLIENTMETRICS_XP* metrics) { | |
| 216 DCHECK(metrics); | |
| 217 metrics->cbSize = sizeof(*metrics); | |
| 218 const bool success = !!SystemParametersInfo( | |
| 219 SPI_GETNONCLIENTMETRICS, | |
| 220 metrics->cbSize, | |
| 221 reinterpret_cast<NONCLIENTMETRICS*>(metrics), | |
| 222 0); | |
| 223 DCHECK(success); | |
| 224 } | |
| 225 | |
| 226 bool GetUserSidString(std::wstring* user_sid) { | |
| 227 // Get the current token. | |
| 228 HANDLE token = NULL; | |
| 229 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token)) | |
| 230 return false; | |
| 231 ScopedHandle token_scoped(token); | |
| 232 | |
| 233 DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE; | |
| 234 scoped_ptr<BYTE[]> user_bytes(new BYTE[size]); | |
| 235 TOKEN_USER* user = reinterpret_cast<TOKEN_USER*>(user_bytes.get()); | |
| 236 | |
| 237 if (!::GetTokenInformation(token, TokenUser, user, size, &size)) | |
| 238 return false; | |
| 239 | |
| 240 if (!user->User.Sid) | |
| 241 return false; | |
| 242 | |
| 243 // Convert the data to a string. | |
| 244 wchar_t* sid_string; | |
| 245 if (!::ConvertSidToStringSid(user->User.Sid, &sid_string)) | |
| 246 return false; | |
| 247 | |
| 248 *user_sid = sid_string; | |
| 249 | |
| 250 ::LocalFree(sid_string); | |
| 251 | |
| 252 return true; | |
| 253 } | |
| 254 | |
| 255 bool IsShiftPressed() { | |
| 256 return (::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000; | |
| 257 } | |
| 258 | |
| 259 bool IsCtrlPressed() { | |
| 260 return (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000; | |
| 261 } | |
| 262 | |
| 263 bool IsAltPressed() { | |
| 264 return (::GetKeyState(VK_MENU) & 0x8000) == 0x8000; | |
| 265 } | |
| 266 | |
| 267 bool IsAltGrPressed() { | |
| 268 return (::GetKeyState(VK_MENU) & 0x8000) == 0x8000 && | |
| 269 (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000; | |
| 270 } | |
| 271 | |
| 272 bool UserAccountControlIsEnabled() { | |
| 273 // This can be slow if Windows ends up going to disk. Should watch this key | |
| 274 // for changes and only read it once, preferably on the file thread. | |
| 275 // http://code.google.com/p/chromium/issues/detail?id=61644 | |
| 276 ThreadRestrictions::ScopedAllowIO allow_io; | |
| 277 | |
| 278 RegKey key(HKEY_LOCAL_MACHINE, | |
| 279 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", | |
| 280 KEY_READ); | |
| 281 DWORD uac_enabled; | |
| 282 if (key.ReadValueDW(L"EnableLUA", &uac_enabled) != ERROR_SUCCESS) | |
| 283 return true; | |
| 284 // Users can set the EnableLUA value to something arbitrary, like 2, which | |
| 285 // Vista will treat as UAC enabled, so we make sure it is not set to 0. | |
| 286 return (uac_enabled != 0); | |
| 287 } | |
| 288 | |
| 289 bool SetBooleanValueForPropertyStore(IPropertyStore* property_store, | |
| 290 const PROPERTYKEY& property_key, | |
| 291 bool property_bool_value) { | |
| 292 ScopedPropVariant property_value; | |
| 293 if (FAILED(InitPropVariantFromBoolean(property_bool_value, | |
| 294 property_value.Receive()))) { | |
| 295 return false; | |
| 296 } | |
| 297 | |
| 298 return SetPropVariantValueForPropertyStore(property_store, | |
| 299 property_key, | |
| 300 property_value); | |
| 301 } | |
| 302 | |
| 303 bool SetStringValueForPropertyStore(IPropertyStore* property_store, | |
| 304 const PROPERTYKEY& property_key, | |
| 305 const wchar_t* property_string_value) { | |
| 306 ScopedPropVariant property_value; | |
| 307 if (FAILED(InitPropVariantFromString(property_string_value, | |
| 308 property_value.Receive()))) { | |
| 309 return false; | |
| 310 } | |
| 311 | |
| 312 return SetPropVariantValueForPropertyStore(property_store, | |
| 313 property_key, | |
| 314 property_value); | |
| 315 } | |
| 316 | |
| 317 bool SetAppIdForPropertyStore(IPropertyStore* property_store, | |
| 318 const wchar_t* app_id) { | |
| 319 // App id should be less than 64 chars and contain no space. And recommended | |
| 320 // format is CompanyName.ProductName[.SubProduct.ProductNumber]. | |
| 321 // See http://msdn.microsoft.com/en-us/library/dd378459%28VS.85%29.aspx | |
| 322 DCHECK(lstrlen(app_id) < 64 && wcschr(app_id, L' ') == NULL); | |
| 323 | |
| 324 return SetStringValueForPropertyStore(property_store, | |
| 325 PKEY_AppUserModel_ID, | |
| 326 app_id); | |
| 327 } | |
| 328 | |
| 329 static const char16 kAutoRunKeyPath[] = | |
| 330 L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; | |
| 331 | |
| 332 bool AddCommandToAutoRun(HKEY root_key, const string16& name, | |
| 333 const string16& command) { | |
| 334 RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE); | |
| 335 return (autorun_key.WriteValue(name.c_str(), command.c_str()) == | |
| 336 ERROR_SUCCESS); | |
| 337 } | |
| 338 | |
| 339 bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name) { | |
| 340 RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE); | |
| 341 return (autorun_key.DeleteValue(name.c_str()) == ERROR_SUCCESS); | |
| 342 } | |
| 343 | |
| 344 bool ReadCommandFromAutoRun(HKEY root_key, | |
| 345 const string16& name, | |
| 346 string16* command) { | |
| 347 RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_QUERY_VALUE); | |
| 348 return (autorun_key.ReadValue(name.c_str(), command) == ERROR_SUCCESS); | |
| 349 } | |
| 350 | |
| 351 void SetShouldCrashOnProcessDetach(bool crash) { | |
| 352 g_crash_on_process_detach = crash; | |
| 353 } | |
| 354 | |
| 355 bool ShouldCrashOnProcessDetach() { | |
| 356 return g_crash_on_process_detach; | |
| 357 } | |
| 358 | |
| 359 void SetAbortBehaviorForCrashReporting() { | |
| 360 // Prevent CRT's abort code from prompting a dialog or trying to "report" it. | |
| 361 // Disabling the _CALL_REPORTFAULT behavior is important since otherwise it | |
| 362 // has the sideffect of clearing our exception filter, which means we | |
| 363 // don't get any crash. | |
| 364 _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); | |
| 365 | |
| 366 // Set a SIGABRT handler for good measure. We will crash even if the default | |
| 367 // is left in place, however this allows us to crash earlier. And it also | |
| 368 // lets us crash in response to code which might directly call raise(SIGABRT) | |
| 369 signal(SIGABRT, ForceCrashOnSigAbort); | |
| 370 } | |
| 371 | |
| 372 bool IsTabletDevice() { | |
| 373 if (GetSystemMetrics(SM_MAXIMUMTOUCHES) == 0) | |
| 374 return false; | |
| 375 | |
| 376 Version version = GetVersion(); | |
| 377 if (version == VERSION_XP) | |
| 378 return (GetSystemMetrics(SM_TABLETPC) != 0); | |
| 379 | |
| 380 // If the device is docked, the user is treating the device as a PC. | |
| 381 if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0) | |
| 382 return false; | |
| 383 | |
| 384 // PlatformRoleSlate was only added in Windows 8, but prior to Win8 it is | |
| 385 // still possible to check for a mobile power profile. | |
| 386 POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole(); | |
| 387 bool mobile_power_profile = (role == PlatformRoleMobile); | |
| 388 bool slate_power_profile = false; | |
| 389 if (version >= VERSION_WIN8) | |
| 390 slate_power_profile = (role == PlatformRoleSlate); | |
| 391 | |
| 392 if (mobile_power_profile || slate_power_profile) | |
| 393 return (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0); | |
| 394 | |
| 395 return false; | |
| 396 } | |
| 397 | |
| 398 bool DisplayVirtualKeyboard() { | |
| 399 if (GetVersion() < VERSION_WIN8) | |
| 400 return false; | |
| 401 | |
| 402 if (IsKeyboardPresentOnSlate(nullptr)) | |
| 403 return false; | |
| 404 | |
| 405 static LazyInstance<string16>::Leaky osk_path = LAZY_INSTANCE_INITIALIZER; | |
| 406 | |
| 407 if (osk_path.Get().empty()) { | |
| 408 // We need to launch TabTip.exe from the location specified under the | |
| 409 // LocalServer32 key for the {{054AAE20-4BEA-4347-8A35-64A533254A9D}} | |
| 410 // CLSID. | |
| 411 // TabTip.exe is typically found at | |
| 412 // c:\program files\common files\microsoft shared\ink on English Windows. | |
| 413 // We don't want to launch TabTip.exe from | |
| 414 // c:\program files (x86)\common files\microsoft shared\ink. This path is | |
| 415 // normally found on 64 bit Windows. | |
| 416 RegKey key(HKEY_LOCAL_MACHINE, kWindows8OSKRegPath, | |
| 417 KEY_READ | KEY_WOW64_64KEY); | |
| 418 DWORD osk_path_length = 1024; | |
| 419 if (key.ReadValue(NULL, | |
| 420 WriteInto(&osk_path.Get(), osk_path_length), | |
| 421 &osk_path_length, | |
| 422 NULL) != ERROR_SUCCESS) { | |
| 423 DLOG(WARNING) << "Failed to read on screen keyboard path from registry"; | |
| 424 return false; | |
| 425 } | |
| 426 size_t common_program_files_offset = | |
| 427 osk_path.Get().find(L"%CommonProgramFiles%"); | |
| 428 // Typically the path to TabTip.exe read from the registry will start with | |
| 429 // %CommonProgramFiles% which needs to be replaced with the corrsponding | |
| 430 // expanded string. | |
| 431 // If the path does not begin with %CommonProgramFiles% we use it as is. | |
| 432 if (common_program_files_offset != string16::npos) { | |
| 433 // Preserve the beginning quote in the path. | |
| 434 osk_path.Get().erase(common_program_files_offset, | |
| 435 wcslen(L"%CommonProgramFiles%")); | |
| 436 // The path read from the registry contains the %CommonProgramFiles% | |
| 437 // environment variable prefix. On 64 bit Windows the SHGetKnownFolderPath | |
| 438 // function returns the common program files path with the X86 suffix for | |
| 439 // the FOLDERID_ProgramFilesCommon value. | |
| 440 // To get the correct path to TabTip.exe we first read the environment | |
| 441 // variable CommonProgramW6432 which points to the desired common | |
| 442 // files path. Failing that we fallback to the SHGetKnownFolderPath API. | |
| 443 | |
| 444 // We then replace the %CommonProgramFiles% value with the actual common | |
| 445 // files path found in the process. | |
| 446 string16 common_program_files_path; | |
| 447 scoped_ptr<wchar_t[]> common_program_files_wow6432; | |
| 448 DWORD buffer_size = | |
| 449 GetEnvironmentVariable(L"CommonProgramW6432", NULL, 0); | |
| 450 if (buffer_size) { | |
| 451 common_program_files_wow6432.reset(new wchar_t[buffer_size]); | |
| 452 GetEnvironmentVariable(L"CommonProgramW6432", | |
| 453 common_program_files_wow6432.get(), | |
| 454 buffer_size); | |
| 455 common_program_files_path = common_program_files_wow6432.get(); | |
| 456 DCHECK(!common_program_files_path.empty()); | |
| 457 } else { | |
| 458 ScopedCoMem<wchar_t> common_program_files; | |
| 459 if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, NULL, | |
| 460 &common_program_files))) { | |
| 461 return false; | |
| 462 } | |
| 463 common_program_files_path = common_program_files; | |
| 464 } | |
| 465 | |
| 466 osk_path.Get().insert(1, common_program_files_path); | |
| 467 } | |
| 468 } | |
| 469 | |
| 470 HINSTANCE ret = ::ShellExecuteW(NULL, | |
| 471 L"", | |
| 472 osk_path.Get().c_str(), | |
| 473 NULL, | |
| 474 NULL, | |
| 475 SW_SHOW); | |
| 476 return reinterpret_cast<intptr_t>(ret) > 32; | |
| 477 } | |
| 478 | |
| 479 bool DismissVirtualKeyboard() { | |
| 480 if (GetVersion() < VERSION_WIN8) | |
| 481 return false; | |
| 482 | |
| 483 // We dismiss the virtual keyboard by generating the ESC keystroke | |
| 484 // programmatically. | |
| 485 const wchar_t kOSKClassName[] = L"IPTip_Main_Window"; | |
| 486 HWND osk = ::FindWindow(kOSKClassName, NULL); | |
| 487 if (::IsWindow(osk) && ::IsWindowEnabled(osk)) { | |
| 488 PostMessage(osk, WM_SYSCOMMAND, SC_CLOSE, 0); | |
| 489 return true; | |
| 490 } | |
| 491 return false; | |
| 492 } | |
| 493 | |
| 494 typedef HWND (*MetroRootWindow) (); | |
| 495 | |
| 496 enum DomainEnrollementState {UNKNOWN = -1, NOT_ENROLLED, ENROLLED}; | |
| 497 static volatile long int g_domain_state = UNKNOWN; | |
| 498 | |
| 499 bool IsEnrolledToDomain() { | |
| 500 // Doesn't make any sense to retry inside a user session because joining a | |
| 501 // domain will only kick in on a restart. | |
| 502 if (g_domain_state == UNKNOWN) { | |
| 503 LPWSTR domain; | |
| 504 NETSETUP_JOIN_STATUS join_status; | |
| 505 if(::NetGetJoinInformation(NULL, &domain, &join_status) != NERR_Success) | |
| 506 return false; | |
| 507 ::NetApiBufferFree(domain); | |
| 508 ::InterlockedCompareExchange(&g_domain_state, | |
| 509 join_status == ::NetSetupDomainName ? | |
| 510 ENROLLED : NOT_ENROLLED, | |
| 511 UNKNOWN); | |
| 512 } | |
| 513 | |
| 514 return g_domain_state == ENROLLED; | |
| 515 } | |
| 516 | |
| 517 void SetDomainStateForTesting(bool state) { | |
| 518 g_domain_state = state ? ENROLLED : NOT_ENROLLED; | |
| 519 } | |
| 520 | |
| 521 bool MaybeHasSHA256Support() { | |
| 522 const OSInfo* os_info = OSInfo::GetInstance(); | |
| 523 | |
| 524 if (os_info->version() == VERSION_PRE_XP) | |
| 525 return false; // Too old to have it and this OS is not supported anyway. | |
| 526 | |
| 527 if (os_info->version() == VERSION_XP) | |
| 528 return os_info->service_pack().major >= 3; // Windows XP SP3 has it. | |
| 529 | |
| 530 // Assume it is missing in this case, although it may not be. This category | |
| 531 // includes Windows XP x64, and Windows Server, where a hotfix could be | |
| 532 // deployed. | |
| 533 if (os_info->version() == VERSION_SERVER_2003) | |
| 534 return false; | |
| 535 | |
| 536 DCHECK(os_info->version() >= VERSION_VISTA); | |
| 537 return true; // New enough to have SHA-256 support. | |
| 538 } | |
| 539 | |
| 540 } // namespace win | |
| 541 } // namespace base | |
| OLD | NEW |