win_util.cc 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  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. #include "base/win/win_util.h"
  5. #include <aclapi.h>
  6. #include <cfgmgr32.h>
  7. #include <initguid.h>
  8. #include <lm.h>
  9. #include <powrprof.h>
  10. #include <shobjidl.h> // Must be before propkey.
  11. #include <inspectable.h>
  12. #include <mdmregistration.h>
  13. #include <objbase.h>
  14. #include <propkey.h>
  15. #include <psapi.h>
  16. #include <roapi.h>
  17. #include <sddl.h>
  18. #include <setupapi.h>
  19. #include <shellscalingapi.h>
  20. #include <signal.h>
  21. #include <stddef.h>
  22. #include <stdlib.h>
  23. #include <strsafe.h>
  24. #include <tchar.h> // Must be before tpcshrd.h or for any use of _T macro
  25. #include <tpcshrd.h>
  26. #include <uiviewsettingsinterop.h>
  27. #include <windows.ui.viewmanagement.h>
  28. #include <winstring.h>
  29. #include <wrl/client.h>
  30. #include <wrl/wrappers/corewrappers.h>
  31. #include <limits>
  32. #include <memory>
  33. #include <utility>
  34. #include "base/base_switches.h"
  35. #include "base/command_line.h"
  36. #include "base/files/file_path.h"
  37. #include "base/logging.h"
  38. #include "base/metrics/histogram_functions.h"
  39. #include "base/notreached.h"
  40. #include "base/scoped_native_library.h"
  41. #include "base/strings/string_util.h"
  42. #include "base/strings/string_util_win.h"
  43. #include "base/strings/utf_string_conversions.h"
  44. #include "base/threading/scoped_thread_priority.h"
  45. #include "base/threading/thread_restrictions.h"
  46. #include "base/timer/elapsed_timer.h"
  47. #include "base/win/access_token.h"
  48. #include "base/win/core_winrt_util.h"
  49. #include "base/win/propvarutil.h"
  50. #include "base/win/registry.h"
  51. #include "base/win/scoped_co_mem.h"
  52. #include "base/win/scoped_handle.h"
  53. #include "base/win/scoped_hstring.h"
  54. #include "base/win/scoped_propvariant.h"
  55. #include "base/win/shlwapi.h"
  56. #include "base/win/static_constants.h"
  57. #include "base/win/windows_version.h"
  58. #include "third_party/abseil-cpp/absl/types/optional.h"
  59. namespace base {
  60. namespace win {
  61. namespace {
  62. // Sets the value of |property_key| to |property_value| in |property_store|.
  63. bool SetPropVariantValueForPropertyStore(
  64. IPropertyStore* property_store,
  65. const PROPERTYKEY& property_key,
  66. const ScopedPropVariant& property_value) {
  67. DCHECK(property_store);
  68. HRESULT result = property_store->SetValue(property_key, property_value.get());
  69. if (result == S_OK)
  70. result = property_store->Commit();
  71. if (SUCCEEDED(result))
  72. return true;
  73. #if DCHECK_IS_ON()
  74. if (HRESULT_FACILITY(result) == FACILITY_WIN32)
  75. ::SetLastError(HRESULT_CODE(result));
  76. // See third_party/perl/c/i686-w64-mingw32/include/propkey.h for GUID and
  77. // PID definitions.
  78. DPLOG(ERROR) << "Failed to set property with GUID "
  79. << WStringFromGUID(property_key.fmtid) << " PID "
  80. << property_key.pid;
  81. #endif
  82. return false;
  83. }
  84. void __cdecl ForceCrashOnSigAbort(int) {
  85. *((volatile int*)nullptr) = 0x1337;
  86. }
  87. // Returns the current platform role. We use the PowerDeterminePlatformRoleEx
  88. // API for that.
  89. POWER_PLATFORM_ROLE GetPlatformRole() {
  90. return PowerDeterminePlatformRoleEx(POWER_PLATFORM_ROLE_V2);
  91. }
  92. // Method used for Windows 8.1 and later.
  93. // Since we support versions earlier than 8.1, we must dynamically load this
  94. // function from user32.dll, so it won't fail to load in runtime. For earlier
  95. // Windows versions GetProcAddress will return null and report failure so that
  96. // callers can fall back on the deprecated SetProcessDPIAware.
  97. bool SetProcessDpiAwarenessWrapper(PROCESS_DPI_AWARENESS value) {
  98. if (!IsUser32AndGdi32Available())
  99. return false;
  100. static const auto set_process_dpi_awareness_func =
  101. reinterpret_cast<decltype(&::SetProcessDpiAwareness)>(
  102. GetUser32FunctionPointer("SetProcessDpiAwarenessInternal"));
  103. if (set_process_dpi_awareness_func) {
  104. HRESULT hr = set_process_dpi_awareness_func(value);
  105. if (SUCCEEDED(hr))
  106. return true;
  107. DLOG_IF(ERROR, hr == E_ACCESSDENIED)
  108. << "Access denied error from SetProcessDpiAwarenessInternal. "
  109. "Function called twice, or manifest was used.";
  110. NOTREACHED()
  111. << "SetProcessDpiAwarenessInternal failed with unexpected error: "
  112. << hr;
  113. return false;
  114. }
  115. DCHECK_LT(GetVersion(), Version::WIN8_1) << "SetProcessDpiAwarenessInternal "
  116. "should be available on all "
  117. "platforms >= Windows 8.1";
  118. return false;
  119. }
  120. // Enable V2 per-monitor high-DPI support for the process. This will cause
  121. // Windows to scale dialogs, comctl32 controls, context menus, and non-client
  122. // area owned by this process on a per-monitor basis. If per-monitor V2 is not
  123. // available (i.e., prior to Windows 10 1703) or fails, returns false.
  124. // https://docs.microsoft.com/en-us/windows/desktop/hidpi/dpi-awareness-context
  125. bool EnablePerMonitorV2() {
  126. if (!IsUser32AndGdi32Available())
  127. return false;
  128. static const auto set_process_dpi_awareness_context_func =
  129. reinterpret_cast<decltype(&::SetProcessDpiAwarenessContext)>(
  130. GetUser32FunctionPointer("SetProcessDpiAwarenessContext"));
  131. if (set_process_dpi_awareness_context_func) {
  132. return set_process_dpi_awareness_context_func(
  133. DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
  134. }
  135. DCHECK_LT(GetVersion(), Version::WIN10_RS2)
  136. << "SetProcessDpiAwarenessContext should be available on all platforms"
  137. " >= Windows 10 Redstone 2";
  138. return false;
  139. }
  140. bool* GetDomainEnrollmentStateStorage() {
  141. static bool state = IsOS(OS_DOMAINMEMBER);
  142. return &state;
  143. }
  144. bool* GetRegisteredWithManagementStateStorage() {
  145. static bool state = []() {
  146. // Mitigate the issues caused by loading DLLs on a background thread
  147. // (http://crbug/973868).
  148. SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
  149. ScopedNativeLibrary library(
  150. FilePath(FILE_PATH_LITERAL("MDMRegistration.dll")));
  151. if (!library.is_valid())
  152. return false;
  153. using IsDeviceRegisteredWithManagementFunction =
  154. decltype(&::IsDeviceRegisteredWithManagement);
  155. IsDeviceRegisteredWithManagementFunction
  156. is_device_registered_with_management_function =
  157. reinterpret_cast<IsDeviceRegisteredWithManagementFunction>(
  158. library.GetFunctionPointer("IsDeviceRegisteredWithManagement"));
  159. if (!is_device_registered_with_management_function)
  160. return false;
  161. BOOL is_managed = FALSE;
  162. HRESULT hr =
  163. is_device_registered_with_management_function(&is_managed, 0, nullptr);
  164. return SUCCEEDED(hr) && is_managed;
  165. }();
  166. return &state;
  167. }
  168. // TODO (crbug/1300219): return a DSREG_JOIN_TYPE* instead of bool*.
  169. bool* GetAzureADJoinStateStorage() {
  170. static bool state = []() {
  171. base::ElapsedTimer timer;
  172. // Mitigate the issues caused by loading DLLs on a background thread
  173. // (http://crbug/973868).
  174. SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
  175. ScopedNativeLibrary netapi32(
  176. base::LoadSystemLibrary(FILE_PATH_LITERAL("netapi32.dll")));
  177. if (!netapi32.is_valid())
  178. return false;
  179. const auto net_get_aad_join_information_function =
  180. reinterpret_cast<decltype(&::NetGetAadJoinInformation)>(
  181. netapi32.GetFunctionPointer("NetGetAadJoinInformation"));
  182. if (!net_get_aad_join_information_function)
  183. return false;
  184. const auto net_free_aad_join_information_function =
  185. reinterpret_cast<decltype(&::NetFreeAadJoinInformation)>(
  186. netapi32.GetFunctionPointer("NetFreeAadJoinInformation"));
  187. DPCHECK(net_free_aad_join_information_function);
  188. DSREG_JOIN_INFO* join_info = nullptr;
  189. HRESULT hr = net_get_aad_join_information_function(/*pcszTenantId=*/nullptr,
  190. &join_info);
  191. const bool is_aad_joined = SUCCEEDED(hr) && join_info;
  192. if (join_info) {
  193. net_free_aad_join_information_function(join_info);
  194. }
  195. base::UmaHistogramTimes("EnterpriseCheck.AzureADJoinStatusCheckTime",
  196. timer.Elapsed());
  197. return is_aad_joined;
  198. }();
  199. return &state;
  200. }
  201. NativeLibrary PinUser32Internal(NativeLibraryLoadError* error) {
  202. static NativeLibraryLoadError load_error;
  203. static const NativeLibrary user32_module =
  204. PinSystemLibrary(FILE_PATH_LITERAL("user32.dll"), &load_error);
  205. if (!user32_module && error)
  206. error->code = load_error.code;
  207. return user32_module;
  208. }
  209. } // namespace
  210. // Uses the Windows 10 WRL API's to query the current system state. The API's
  211. // we are using in the function below are supported in Win32 apps as per msdn.
  212. // It looks like the API implementation is buggy at least on Surface 4 causing
  213. // it to always return UserInteractionMode_Touch which as per documentation
  214. // indicates tablet mode.
  215. bool IsWindows10OrGreaterTabletMode(HWND hwnd) {
  216. if (GetVersion() >= Version::WIN11) {
  217. // Only Win10 supports explicit tablet mode. On Win11,
  218. // get_UserInteractionMode always returns UserInteractionMode_Mouse, so
  219. // instead we check if we're in slate mode or not - 0 value means slate
  220. // mode. See
  221. // https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-gpiobuttons-convertibleslatemode
  222. constexpr int kKeyboardPresent = 1;
  223. base::win::RegKey registry_key(
  224. HKEY_LOCAL_MACHINE,
  225. L"System\\CurrentControlSet\\Control\\PriorityControl", KEY_READ);
  226. DWORD slate_mode = 0;
  227. bool value_exists = registry_key.ReadValueDW(L"ConvertibleSlateMode",
  228. &slate_mode) == ERROR_SUCCESS;
  229. // Some devices don't set the reg key to 1 for keyboard-only devices, so
  230. // also check if the device is used as a tablet if it is not 1. Some devices
  231. // don't set the registry key at all; fall back to checking if the device
  232. // is used as a tablet for them as well.
  233. return !(value_exists && slate_mode == kKeyboardPresent) &&
  234. IsDeviceUsedAsATablet(/*reason=*/nullptr);
  235. }
  236. if (!ResolveCoreWinRTDelayload() ||
  237. !ScopedHString::ResolveCoreWinRTStringDelayload()) {
  238. return false;
  239. }
  240. ScopedHString view_settings_guid = ScopedHString::Create(
  241. RuntimeClass_Windows_UI_ViewManagement_UIViewSettings);
  242. Microsoft::WRL::ComPtr<IUIViewSettingsInterop> view_settings_interop;
  243. HRESULT hr = win::RoGetActivationFactory(
  244. view_settings_guid.get(), IID_PPV_ARGS(&view_settings_interop));
  245. if (FAILED(hr))
  246. return false;
  247. Microsoft::WRL::ComPtr<ABI::Windows::UI::ViewManagement::IUIViewSettings>
  248. view_settings;
  249. hr = view_settings_interop->GetForWindow(hwnd, IID_PPV_ARGS(&view_settings));
  250. if (FAILED(hr))
  251. return false;
  252. ABI::Windows::UI::ViewManagement::UserInteractionMode mode =
  253. ABI::Windows::UI::ViewManagement::UserInteractionMode_Mouse;
  254. view_settings->get_UserInteractionMode(&mode);
  255. return mode == ABI::Windows::UI::ViewManagement::UserInteractionMode_Touch;
  256. }
  257. // Returns true if a physical keyboard is detected on Windows 8 and up.
  258. // Uses the Setup APIs to enumerate the attached keyboards and returns true
  259. // if the keyboard count is 1 or more.. While this will work in most cases
  260. // it won't work if there are devices which expose keyboard interfaces which
  261. // are attached to the machine.
  262. bool IsKeyboardPresentOnSlate(HWND hwnd, std::string* reason) {
  263. bool result = false;
  264. if (GetVersion() < Version::WIN8) {
  265. if (reason)
  266. *reason = "Detection not supported";
  267. return false;
  268. }
  269. // This function is only supported for Windows 8 and up.
  270. if (CommandLine::ForCurrentProcess()->HasSwitch(
  271. switches::kDisableUsbKeyboardDetect)) {
  272. if (reason)
  273. *reason = "Detection disabled";
  274. return false;
  275. }
  276. // This function should be only invoked for machines with touch screens.
  277. if ((GetSystemMetrics(SM_DIGITIZER) & NID_INTEGRATED_TOUCH) !=
  278. NID_INTEGRATED_TOUCH) {
  279. if (reason) {
  280. *reason += "NID_INTEGRATED_TOUCH\n";
  281. result = true;
  282. } else {
  283. return true;
  284. }
  285. }
  286. // If it is a tablet device we assume that there is no keyboard attached.
  287. if (IsTabletDevice(reason, hwnd)) {
  288. if (reason)
  289. *reason += "Tablet device.\n";
  290. return false;
  291. }
  292. if (!reason)
  293. return true;
  294. *reason += "Not a tablet device";
  295. result = true;
  296. // To determine whether a keyboard is present on the device, we do the
  297. // following:-
  298. // 1. Check whether the device supports auto rotation. If it does then
  299. // it possibly supports flipping from laptop to slate mode. If it
  300. // does not support auto rotation, then we assume it is a desktop
  301. // or a normal laptop and assume that there is a keyboard.
  302. // 2. If the device supports auto rotation, then we get its platform role
  303. // and check the system metric SM_CONVERTIBLESLATEMODE to see if it is
  304. // being used in slate mode. If yes then we return false here to ensure
  305. // that the OSK is displayed.
  306. // 3. If step 1 and 2 fail then we check attached keyboards and return true
  307. // if we find ACPI\* or HID\VID* keyboards.
  308. using GetAutoRotationState = decltype(&::GetAutoRotationState);
  309. static const auto get_rotation_state = reinterpret_cast<GetAutoRotationState>(
  310. GetUser32FunctionPointer("GetAutoRotationState"));
  311. if (get_rotation_state) {
  312. AR_STATE auto_rotation_state = AR_ENABLED;
  313. get_rotation_state(&auto_rotation_state);
  314. if ((auto_rotation_state & AR_NOSENSOR) ||
  315. (auto_rotation_state & AR_NOT_SUPPORTED)) {
  316. // If there is no auto rotation sensor or rotation is not supported in
  317. // the current configuration, then we can assume that this is a desktop
  318. // or a traditional laptop.
  319. if (!reason)
  320. return true;
  321. *reason += (auto_rotation_state & AR_NOSENSOR) ? "AR_NOSENSOR\n"
  322. : "AR_NOT_SUPPORTED\n";
  323. result = true;
  324. }
  325. }
  326. const GUID KEYBOARD_CLASS_GUID = {
  327. 0x4D36E96B,
  328. 0xE325,
  329. 0x11CE,
  330. {0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18}};
  331. // Query for all the keyboard devices.
  332. HDEVINFO device_info = SetupDiGetClassDevs(&KEYBOARD_CLASS_GUID, nullptr,
  333. nullptr, DIGCF_PRESENT);
  334. if (device_info == INVALID_HANDLE_VALUE) {
  335. if (reason)
  336. *reason += "No keyboard info\n";
  337. return result;
  338. }
  339. // Enumerate all keyboards and look for ACPI\PNP and HID\VID devices. If
  340. // the count is more than 1 we assume that a keyboard is present. This is
  341. // under the assumption that there will always be one keyboard device.
  342. for (DWORD i = 0;; ++i) {
  343. SP_DEVINFO_DATA device_info_data = {0};
  344. device_info_data.cbSize = sizeof(device_info_data);
  345. if (!SetupDiEnumDeviceInfo(device_info, i, &device_info_data))
  346. break;
  347. // Get the device ID.
  348. wchar_t device_id[MAX_DEVICE_ID_LEN];
  349. CONFIGRET status = CM_Get_Device_ID(device_info_data.DevInst, device_id,
  350. MAX_DEVICE_ID_LEN, 0);
  351. if (status == CR_SUCCESS) {
  352. // To reduce the scope of the hack we only look for ACPI and HID\\VID
  353. // prefixes in the keyboard device ids.
  354. if (StartsWith(device_id, L"ACPI", CompareCase::INSENSITIVE_ASCII) ||
  355. StartsWith(device_id, L"HID\\VID", CompareCase::INSENSITIVE_ASCII)) {
  356. if (reason) {
  357. *reason += "device: ";
  358. *reason += WideToUTF8(device_id);
  359. *reason += '\n';
  360. }
  361. // The heuristic we are using is to check the count of keyboards and
  362. // return true if the API's report one or more keyboards. Please note
  363. // that this will break for non keyboard devices which expose a
  364. // keyboard PDO.
  365. result = true;
  366. }
  367. }
  368. }
  369. return result;
  370. }
  371. static bool g_crash_on_process_detach = false;
  372. bool GetUserSidString(std::wstring* user_sid) {
  373. absl::optional<AccessToken> token = AccessToken::FromCurrentProcess();
  374. if (!token)
  375. return false;
  376. absl::optional<std::wstring> sid_string = token->User().ToSddlString();
  377. if (!sid_string)
  378. return false;
  379. *user_sid = *sid_string;
  380. return true;
  381. }
  382. bool UserAccountControlIsEnabled() {
  383. // This can be slow if Windows ends up going to disk. Should watch this key
  384. // for changes and only read it once, preferably on the file thread.
  385. // http://code.google.com/p/chromium/issues/detail?id=61644
  386. ThreadRestrictions::ScopedAllowIO allow_io;
  387. RegKey key(HKEY_LOCAL_MACHINE,
  388. L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
  389. KEY_READ);
  390. DWORD uac_enabled;
  391. if (key.ReadValueDW(L"EnableLUA", &uac_enabled) != ERROR_SUCCESS) {
  392. return true;
  393. }
  394. // Users can set the EnableLUA value to something arbitrary, like 2, which
  395. // Vista will treat as UAC enabled, so we make sure it is not set to 0.
  396. return (uac_enabled != 0);
  397. }
  398. bool SetBooleanValueForPropertyStore(IPropertyStore* property_store,
  399. const PROPERTYKEY& property_key,
  400. bool property_bool_value) {
  401. ScopedPropVariant property_value;
  402. if (FAILED(InitPropVariantFromBoolean(property_bool_value,
  403. property_value.Receive()))) {
  404. return false;
  405. }
  406. return SetPropVariantValueForPropertyStore(property_store, property_key,
  407. property_value);
  408. }
  409. bool SetStringValueForPropertyStore(IPropertyStore* property_store,
  410. const PROPERTYKEY& property_key,
  411. const wchar_t* property_string_value) {
  412. ScopedPropVariant property_value;
  413. if (FAILED(InitPropVariantFromString(property_string_value,
  414. property_value.Receive()))) {
  415. return false;
  416. }
  417. return SetPropVariantValueForPropertyStore(property_store, property_key,
  418. property_value);
  419. }
  420. bool SetClsidForPropertyStore(IPropertyStore* property_store,
  421. const PROPERTYKEY& property_key,
  422. const CLSID& property_clsid_value) {
  423. ScopedPropVariant property_value;
  424. if (FAILED(InitPropVariantFromCLSID(property_clsid_value,
  425. property_value.Receive()))) {
  426. return false;
  427. }
  428. return SetPropVariantValueForPropertyStore(property_store, property_key,
  429. property_value);
  430. }
  431. bool SetAppIdForPropertyStore(IPropertyStore* property_store,
  432. const wchar_t* app_id) {
  433. // App id should be less than 128 chars and contain no space. And recommended
  434. // format is CompanyName.ProductName[.SubProduct.ProductNumber].
  435. // See
  436. // https://docs.microsoft.com/en-us/windows/win32/shell/appids#how-to-form-an-application-defined-appusermodelid
  437. DCHECK_LT(lstrlen(app_id), 128);
  438. DCHECK_EQ(wcschr(app_id, L' '), nullptr);
  439. return SetStringValueForPropertyStore(property_store, PKEY_AppUserModel_ID,
  440. app_id);
  441. }
  442. static const wchar_t kAutoRunKeyPath[] =
  443. L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
  444. bool AddCommandToAutoRun(HKEY root_key,
  445. const std::wstring& name,
  446. const std::wstring& command) {
  447. RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
  448. return (autorun_key.WriteValue(name.c_str(), command.c_str()) ==
  449. ERROR_SUCCESS);
  450. }
  451. bool RemoveCommandFromAutoRun(HKEY root_key, const std::wstring& name) {
  452. RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
  453. return (autorun_key.DeleteValue(name.c_str()) == ERROR_SUCCESS);
  454. }
  455. bool ReadCommandFromAutoRun(HKEY root_key,
  456. const std::wstring& name,
  457. std::wstring* command) {
  458. RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_QUERY_VALUE);
  459. return (autorun_key.ReadValue(name.c_str(), command) == ERROR_SUCCESS);
  460. }
  461. void SetShouldCrashOnProcessDetach(bool crash) {
  462. g_crash_on_process_detach = crash;
  463. }
  464. bool ShouldCrashOnProcessDetach() {
  465. return g_crash_on_process_detach;
  466. }
  467. void SetAbortBehaviorForCrashReporting() {
  468. // Prevent CRT's abort code from prompting a dialog or trying to "report" it.
  469. // Disabling the _CALL_REPORTFAULT behavior is important since otherwise it
  470. // has the sideffect of clearing our exception filter, which means we
  471. // don't get any crash.
  472. _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
  473. // Set a SIGABRT handler for good measure. We will crash even if the default
  474. // is left in place, however this allows us to crash earlier. And it also
  475. // lets us crash in response to code which might directly call raise(SIGABRT)
  476. signal(SIGABRT, ForceCrashOnSigAbort);
  477. }
  478. bool IsTabletDevice(std::string* reason, HWND hwnd) {
  479. if (GetVersion() < Version::WIN8) {
  480. if (reason)
  481. *reason = "Tablet device detection not supported below Windows 8\n";
  482. return false;
  483. }
  484. if (IsWindows10OrGreaterTabletMode(hwnd))
  485. return true;
  486. return IsDeviceUsedAsATablet(reason);
  487. }
  488. // This method is used to set the right interactions media queries,
  489. // see https://drafts.csswg.org/mediaqueries-4/#mf-interaction. It doesn't
  490. // check the Windows 10 tablet mode because it doesn't reflect the actual
  491. // input configuration of the device and can be manually triggered by the user
  492. // independently from the hardware state.
  493. bool IsDeviceUsedAsATablet(std::string* reason) {
  494. // Once this is set, it shouldn't be overridden, and it should be the ultimate
  495. // return value, so that this method returns the same result whether or not
  496. // reason is NULL.
  497. absl::optional<bool> ret;
  498. if (GetVersion() < Version::WIN8) {
  499. if (reason)
  500. *reason = "Tablet device detection not supported below Windows 8\n";
  501. return false;
  502. }
  503. if (GetSystemMetrics(SM_MAXIMUMTOUCHES) == 0) {
  504. if (reason) {
  505. *reason += "Device does not support touch.\n";
  506. ret = false;
  507. } else {
  508. return false;
  509. }
  510. }
  511. // If the device is docked, the user is treating the device as a PC.
  512. if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0) {
  513. if (reason) {
  514. *reason += "SM_SYSTEMDOCKED\n";
  515. if (!ret.has_value())
  516. ret = false;
  517. } else {
  518. return false;
  519. }
  520. }
  521. // If the device is not supporting rotation, it's unlikely to be a tablet,
  522. // a convertible or a detachable.
  523. // See
  524. // https://msdn.microsoft.com/en-us/library/windows/desktop/dn629263(v=vs.85).aspx
  525. using GetAutoRotationStateType = decltype(GetAutoRotationState)*;
  526. static const auto get_auto_rotation_state_func =
  527. reinterpret_cast<GetAutoRotationStateType>(
  528. GetUser32FunctionPointer("GetAutoRotationState"));
  529. if (get_auto_rotation_state_func) {
  530. AR_STATE rotation_state = AR_ENABLED;
  531. if (get_auto_rotation_state_func(&rotation_state) &&
  532. (rotation_state & (AR_NOT_SUPPORTED | AR_LAPTOP | AR_NOSENSOR)) != 0)
  533. return ret.has_value() ? ret.value() : false;
  534. }
  535. // PlatformRoleSlate was added in Windows 8+.
  536. POWER_PLATFORM_ROLE role = GetPlatformRole();
  537. bool is_tablet = false;
  538. if (role == PlatformRoleMobile || role == PlatformRoleSlate) {
  539. is_tablet = !GetSystemMetrics(SM_CONVERTIBLESLATEMODE);
  540. if (!is_tablet) {
  541. if (reason) {
  542. *reason += "Not in slate mode.\n";
  543. if (!ret.has_value())
  544. ret = false;
  545. } else {
  546. return false;
  547. }
  548. } else if (reason) {
  549. *reason += (role == PlatformRoleMobile) ? "PlatformRoleMobile\n"
  550. : "PlatformRoleSlate\n";
  551. }
  552. } else if (reason) {
  553. *reason += "Device role is not mobile or slate.\n";
  554. }
  555. return ret.has_value() ? ret.value() : is_tablet;
  556. }
  557. bool IsEnrolledToDomain() {
  558. return *GetDomainEnrollmentStateStorage();
  559. }
  560. bool IsDeviceRegisteredWithManagement() {
  561. return *GetRegisteredWithManagementStateStorage();
  562. }
  563. bool IsJoinedToAzureAD() {
  564. return *GetAzureADJoinStateStorage();
  565. }
  566. bool IsUser32AndGdi32Available() {
  567. static auto is_user32_and_gdi32_available = []() {
  568. // If win32k syscalls aren't disabled, then user32 and gdi32 are available.
  569. // Can't disable win32k prior to windows 8.
  570. if (GetVersion() < Version::WIN8)
  571. return true;
  572. using GetProcessMitigationPolicyType =
  573. decltype(GetProcessMitigationPolicy)*;
  574. GetProcessMitigationPolicyType get_process_mitigation_policy_func =
  575. reinterpret_cast<GetProcessMitigationPolicyType>(GetProcAddress(
  576. GetModuleHandle(L"kernel32.dll"), "GetProcessMitigationPolicy"));
  577. if (!get_process_mitigation_policy_func)
  578. return true;
  579. PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = {};
  580. if (get_process_mitigation_policy_func(GetCurrentProcess(),
  581. ProcessSystemCallDisablePolicy,
  582. &policy, sizeof(policy))) {
  583. return policy.DisallowWin32kSystemCalls == 0;
  584. }
  585. return true;
  586. }();
  587. return is_user32_and_gdi32_available;
  588. }
  589. bool GetLoadedModulesSnapshot(HANDLE process, std::vector<HMODULE>* snapshot) {
  590. DCHECK(snapshot);
  591. DCHECK_EQ(0u, snapshot->size());
  592. snapshot->resize(128);
  593. // We will retry at least once after first determining |bytes_required|. If
  594. // the list of modules changes after we receive |bytes_required| we may retry
  595. // more than once.
  596. int retries_remaining = 5;
  597. do {
  598. DWORD bytes_required = 0;
  599. // EnumProcessModules returns 'success' even if the buffer size is too
  600. // small.
  601. DCHECK_GE(std::numeric_limits<DWORD>::max(),
  602. snapshot->size() * sizeof(HMODULE));
  603. if (!::EnumProcessModules(
  604. process, &(*snapshot)[0],
  605. static_cast<DWORD>(snapshot->size() * sizeof(HMODULE)),
  606. &bytes_required)) {
  607. DPLOG(ERROR) << "::EnumProcessModules failed.";
  608. return false;
  609. }
  610. DCHECK_EQ(0u, bytes_required % sizeof(HMODULE));
  611. size_t num_modules = bytes_required / sizeof(HMODULE);
  612. if (num_modules <= snapshot->size()) {
  613. // Buffer size was too big, presumably because a module was unloaded.
  614. snapshot->erase(snapshot->begin() + static_cast<ptrdiff_t>(num_modules),
  615. snapshot->end());
  616. return true;
  617. } else if (num_modules == 0) {
  618. DLOG(ERROR) << "Can't determine the module list size.";
  619. return false;
  620. } else {
  621. // Buffer size was too small. Try again with a larger buffer. A little
  622. // more room is given to avoid multiple expensive calls to
  623. // ::EnumProcessModules() just because one module has been added.
  624. snapshot->resize(num_modules + 8, nullptr);
  625. }
  626. } while (--retries_remaining);
  627. DLOG(ERROR) << "Failed to enumerate modules.";
  628. return false;
  629. }
  630. void EnableFlicks(HWND hwnd) {
  631. ::RemoveProp(hwnd, MICROSOFT_TABLETPENSERVICE_PROPERTY);
  632. }
  633. void DisableFlicks(HWND hwnd) {
  634. ::SetProp(hwnd, MICROSOFT_TABLETPENSERVICE_PROPERTY,
  635. reinterpret_cast<HANDLE>(TABLET_DISABLE_FLICKS |
  636. TABLET_DISABLE_FLICKFALLBACKKEYS));
  637. }
  638. bool IsProcessPerMonitorDpiAware() {
  639. enum class PerMonitorDpiAware {
  640. UNKNOWN = 0,
  641. PER_MONITOR_DPI_UNAWARE,
  642. PER_MONITOR_DPI_AWARE,
  643. };
  644. static PerMonitorDpiAware per_monitor_dpi_aware = PerMonitorDpiAware::UNKNOWN;
  645. if (per_monitor_dpi_aware == PerMonitorDpiAware::UNKNOWN) {
  646. per_monitor_dpi_aware = PerMonitorDpiAware::PER_MONITOR_DPI_UNAWARE;
  647. HMODULE shcore_dll = ::LoadLibrary(L"shcore.dll");
  648. if (shcore_dll) {
  649. auto get_process_dpi_awareness_func =
  650. reinterpret_cast<decltype(::GetProcessDpiAwareness)*>(
  651. ::GetProcAddress(shcore_dll, "GetProcessDpiAwareness"));
  652. if (get_process_dpi_awareness_func) {
  653. PROCESS_DPI_AWARENESS awareness;
  654. if (SUCCEEDED(get_process_dpi_awareness_func(nullptr, &awareness)) &&
  655. awareness == PROCESS_PER_MONITOR_DPI_AWARE)
  656. per_monitor_dpi_aware = PerMonitorDpiAware::PER_MONITOR_DPI_AWARE;
  657. }
  658. }
  659. }
  660. return per_monitor_dpi_aware == PerMonitorDpiAware::PER_MONITOR_DPI_AWARE;
  661. }
  662. void EnableHighDPISupport() {
  663. if (!IsUser32AndGdi32Available())
  664. return;
  665. // Enable per-monitor V2 if it is available (Win10 1703 or later).
  666. if (EnablePerMonitorV2())
  667. return;
  668. // Fall back to per-monitor DPI for older versions of Win10 instead of
  669. // Win8.1 since Win8.1 does not have EnableChildWindowDpiMessage,
  670. // necessary for correct non-client area scaling across monitors.
  671. PROCESS_DPI_AWARENESS process_dpi_awareness =
  672. GetVersion() >= Version::WIN10 ? PROCESS_PER_MONITOR_DPI_AWARE
  673. : PROCESS_SYSTEM_DPI_AWARE;
  674. if (!SetProcessDpiAwarenessWrapper(process_dpi_awareness)) {
  675. // For windows versions where SetProcessDpiAwareness is not available or
  676. // failed, try its predecessor.
  677. BOOL result = ::SetProcessDPIAware();
  678. DCHECK(result) << "SetProcessDPIAware failed.";
  679. }
  680. }
  681. std::wstring WStringFromGUID(REFGUID rguid) {
  682. // This constant counts the number of characters in the formatted string,
  683. // including the null termination character.
  684. constexpr int kGuidStringCharacters =
  685. 1 + 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1;
  686. wchar_t guid_string[kGuidStringCharacters];
  687. CHECK(SUCCEEDED(StringCchPrintfW(
  688. guid_string, kGuidStringCharacters,
  689. L"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", rguid.Data1,
  690. rguid.Data2, rguid.Data3, rguid.Data4[0], rguid.Data4[1], rguid.Data4[2],
  691. rguid.Data4[3], rguid.Data4[4], rguid.Data4[5], rguid.Data4[6],
  692. rguid.Data4[7])));
  693. return std::wstring(guid_string, kGuidStringCharacters - 1);
  694. }
  695. bool PinUser32(NativeLibraryLoadError* error) {
  696. return PinUser32Internal(error) != nullptr;
  697. }
  698. void* GetUser32FunctionPointer(const char* function_name,
  699. NativeLibraryLoadError* error) {
  700. NativeLibrary user32_module = PinUser32Internal(error);
  701. if (user32_module)
  702. return GetFunctionPointerFromNativeLibrary(user32_module, function_name);
  703. return nullptr;
  704. }
  705. std::wstring GetWindowObjectName(HANDLE handle) {
  706. // Get the size of the name.
  707. std::wstring object_name;
  708. DWORD size = 0;
  709. ::GetUserObjectInformation(handle, UOI_NAME, nullptr, 0, &size);
  710. if (!size) {
  711. DPCHECK(false);
  712. return object_name;
  713. }
  714. LOG_ASSERT(size % sizeof(wchar_t) == 0u);
  715. // Query the name of the object.
  716. if (!::GetUserObjectInformation(
  717. handle, UOI_NAME, WriteInto(&object_name, size / sizeof(wchar_t)),
  718. size, &size)) {
  719. DPCHECK(false);
  720. }
  721. return object_name;
  722. }
  723. bool IsRunningUnderDesktopName(WStringPiece desktop_name) {
  724. HDESK thread_desktop = ::GetThreadDesktop(::GetCurrentThreadId());
  725. if (!thread_desktop)
  726. return false;
  727. std::wstring current_desktop_name = GetWindowObjectName(thread_desktop);
  728. return EqualsCaseInsensitiveASCII(AsStringPiece16(current_desktop_name),
  729. AsStringPiece16(desktop_name));
  730. }
  731. // This method is used to detect whether current session is a remote session.
  732. // See:
  733. // https://docs.microsoft.com/en-us/windows/desktop/TermServ/detecting-the-terminal-services-environment
  734. bool IsCurrentSessionRemote() {
  735. if (::GetSystemMetrics(SM_REMOTESESSION))
  736. return true;
  737. DWORD current_session_id = 0;
  738. if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &current_session_id))
  739. return false;
  740. static constexpr wchar_t kRdpSettingsKeyName[] =
  741. L"SYSTEM\\CurrentControlSet\\Control\\Terminal Server";
  742. RegKey key(HKEY_LOCAL_MACHINE, kRdpSettingsKeyName, KEY_READ);
  743. if (!key.Valid())
  744. return false;
  745. static constexpr wchar_t kGlassSessionIdValueName[] = L"GlassSessionId";
  746. DWORD glass_session_id = 0;
  747. if (key.ReadValueDW(kGlassSessionIdValueName, &glass_session_id) !=
  748. ERROR_SUCCESS)
  749. return false;
  750. return current_session_id != glass_session_id;
  751. }
  752. #if !defined(OFFICIAL_BUILD)
  753. bool IsAppVerifierEnabled(const std::wstring& process_name) {
  754. RegKey key;
  755. // Look for GlobalFlag in the IFEO\chrome.exe key. If it is present then
  756. // Application Verifier or gflags.exe are configured. Most GlobalFlag
  757. // settings are experimentally determined to be incompatible with renderer
  758. // code integrity and a safe set is not known so any GlobalFlag entry is
  759. // assumed to mean that Application Verifier (or pageheap) are enabled.
  760. // The settings are propagated to both 64-bit WOW6432Node versions of the
  761. // registry on 64-bit Windows, so only one check is needed.
  762. return key.Open(
  763. HKEY_LOCAL_MACHINE,
  764. (L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File "
  765. L"Execution Options\\" +
  766. process_name)
  767. .c_str(),
  768. KEY_READ | KEY_WOW64_64KEY) == ERROR_SUCCESS &&
  769. key.HasValue(L"GlobalFlag");
  770. }
  771. #endif // !defined(OFFICIAL_BUILD)
  772. bool IsAppVerifierLoaded() {
  773. return GetModuleHandleA(kApplicationVerifierDllName);
  774. }
  775. ScopedDomainStateForTesting::ScopedDomainStateForTesting(bool state)
  776. : initial_state_(IsEnrolledToDomain()) {
  777. *GetDomainEnrollmentStateStorage() = state;
  778. }
  779. ScopedDomainStateForTesting::~ScopedDomainStateForTesting() {
  780. *GetDomainEnrollmentStateStorage() = initial_state_;
  781. }
  782. ScopedDeviceRegisteredWithManagementForTesting::
  783. ScopedDeviceRegisteredWithManagementForTesting(bool state)
  784. : initial_state_(IsDeviceRegisteredWithManagement()) {
  785. *GetRegisteredWithManagementStateStorage() = state;
  786. }
  787. ScopedDeviceRegisteredWithManagementForTesting::
  788. ~ScopedDeviceRegisteredWithManagementForTesting() {
  789. *GetRegisteredWithManagementStateStorage() = initial_state_;
  790. }
  791. ScopedAzureADJoinStateForTesting::ScopedAzureADJoinStateForTesting(bool state)
  792. : initial_state_(std::exchange(*GetAzureADJoinStateStorage(), state)) {}
  793. ScopedAzureADJoinStateForTesting::~ScopedAzureADJoinStateForTesting() {
  794. *GetAzureADJoinStateStorage() = initial_state_;
  795. }
  796. } // namespace win
  797. } // namespace base