1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // =============================================================================
6 // PLEASE READ
7 //
8 // In general, you should not be adding stuff to this file.
9 //
10 // - If your thing is only used in one place, just put it in a reasonable
11 // location in or near that one place. It's nice you want people to be able
12 // to re-use your function, but realistically, if it hasn't been necessary
13 // before after so many years of development, it's probably not going to be
14 // used in other places in the future unless you know of them now.
15 //
16 // - If your thing is used by multiple callers and is UI-related, it should
17 // probably be in app/win/ instead. Try to put it in the most specific file
18 // possible (avoiding the *_util files when practical).
19 //
20 // =============================================================================
21
22 #ifndef BASE_WIN_WIN_UTIL_H_
23 #define BASE_WIN_WIN_UTIL_H_
24
25 #include <stdint.h>
26
27 #include <optional>
28 #include <string>
29 #include <string_view>
30 #include <vector>
31
32 #include "base/auto_reset.h"
33 #include "base/base_export.h"
34 #include "base/strings/cstring_view.h"
35 #include "base/win/windows_types.h"
36
37 struct IPropertyStore;
38 struct _tagpropertykey;
39 using PROPERTYKEY = _tagpropertykey;
40 struct tagPOINTER_DEVICE_INFO;
41 using POINTER_DEVICE_INFO = tagPOINTER_DEVICE_INFO;
42
43 namespace base {
44
45 struct NativeLibraryLoadError;
46
47 namespace win {
48
HandleToUint32(HANDLE h)49 inline uint32_t HandleToUint32(HANDLE h) {
50 // Cast through uintptr_t and then unsigned int to make the truncation to
51 // 32 bits explicit. Handles are size of-pointer but are always 32-bit values.
52 // https://msdn.microsoft.com/en-us/library/aa384203(VS.85).aspx says:
53 // 64-bit versions of Windows use 32-bit handles for interoperability.
54 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(h));
55 }
56
Uint32ToHandle(uint32_t h)57 inline HANDLE Uint32ToHandle(uint32_t h) {
58 return reinterpret_cast<HANDLE>(
59 static_cast<uintptr_t>(static_cast<int32_t>(h)));
60 }
61
62 // Returns the string representing the current user sid. Does not modify
63 // |user_sid| on failure.
64 BASE_EXPORT bool GetUserSidString(std::wstring* user_sid);
65
66 // Returns false if user account control (UAC) has been disabled with the
67 // EnableLUA registry flag. Returns true if user account control is enabled.
68 // NOTE: The EnableLUA registry flag, which is ignored on Windows XP
69 // machines, might still exist and be set to 0 (UAC disabled), in which case
70 // this function will return false. You should therefore check this flag only
71 // if the OS is Vista or later.
72 BASE_EXPORT bool UserAccountControlIsEnabled();
73
74 // Sets the boolean value for a given key in given IPropertyStore.
75 BASE_EXPORT bool SetBooleanValueForPropertyStore(
76 IPropertyStore* property_store,
77 const PROPERTYKEY& property_key,
78 bool property_bool_value);
79
80 // Sets the string value for a given key in given IPropertyStore.
81 BASE_EXPORT bool SetStringValueForPropertyStore(
82 IPropertyStore* property_store,
83 const PROPERTYKEY& property_key,
84 const wchar_t* property_string_value);
85
86 // Sets the CLSID value for a given key in a given IPropertyStore.
87 BASE_EXPORT bool SetClsidForPropertyStore(IPropertyStore* property_store,
88 const PROPERTYKEY& property_key,
89 const CLSID& property_clsid_value);
90
91 // Sets the application id in given IPropertyStore. The function is used to tag
92 // application/Chrome shortcuts, and set app details for Chrome windows.
93 BASE_EXPORT bool SetAppIdForPropertyStore(IPropertyStore* property_store,
94 const wchar_t* app_id);
95
96 // Adds the specified |command| using the specified |name| to the AutoRun key.
97 // |root_key| could be HKCU or HKLM or the root of any user hive.
98 BASE_EXPORT bool AddCommandToAutoRun(HKEY root_key,
99 const std::wstring& name,
100 const std::wstring& command);
101 // Removes the command specified by |name| from the AutoRun key. |root_key|
102 // could be HKCU or HKLM or the root of any user hive.
103 BASE_EXPORT bool RemoveCommandFromAutoRun(HKEY root_key,
104 const std::wstring& name);
105
106 // Reads the command specified by |name| from the AutoRun key. |root_key|
107 // could be HKCU or HKLM or the root of any user hive. Used for unit-tests.
108 BASE_EXPORT bool ReadCommandFromAutoRun(HKEY root_key,
109 const std::wstring& name,
110 std::wstring* command);
111
112 // Sets whether to crash the process during exit. This is inspected by DLLMain
113 // and used to intercept unexpected terminations of the process (via calls to
114 // exit(), abort(), _exit(), ExitProcess()) and convert them into crashes.
115 // Note that not all mechanisms for terminating the process are covered by
116 // this. In particular, TerminateProcess() is not caught.
117 BASE_EXPORT void SetShouldCrashOnProcessDetach(bool crash);
118 BASE_EXPORT bool ShouldCrashOnProcessDetach();
119
120 // Adjusts the abort behavior so that crash reports can be generated when the
121 // process is aborted.
122 BASE_EXPORT void SetAbortBehaviorForCrashReporting();
123
124 // Checks whether the supplied |hwnd| is in Windows 10 tablet mode. Will return
125 // false on versions below 10.
126 // While tablet mode isn't officially supported in Windows 11, the function will
127 // make an attempt to inspect other signals for tablet mode.
128 BASE_EXPORT bool IsWindows10OrGreaterTabletMode(HWND hwnd);
129
130 // The device convertibility functions below return references to cached data
131 // to allow for complete test scenarios. See:
132 // ScopedDeviceConvertibilityStateForTesting.
133 //
134 // Returns a reference to a cached value computed on first-use that is true only
135 // if the device is a tablet, convertible, or detachable according to
136 // RtlGetDeviceFamilyInfoEnum. Looks for the following values: Tablet(2),
137 // Convertible(5), or Detachable(6).
138 // https://learn.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-deployment-deviceform
139 BASE_EXPORT bool& IsDeviceFormConvertible();
140
141 // Returns a reference to a cached boolean that is true if the device hardware
142 // is convertible. The value is determined via a WMI query for
143 // Win32_SystemEnclosure. This should only be executed for a small amount of
144 // devices that don't have ConvertibleChassis or ConvertibilityEnabled keys set.
145 // https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-systemenclosure
146 BASE_EXPORT bool& IsChassisConvertible();
147
148 // Returns a reference to a cached boolean optional. If a value exists, it means
149 // that the queried registry key, ConvertibilityEnabled, exists. Used by Surface
150 // for devices that can't set deviceForm or ChassisType. The RegKey need not
151 // exist, but if it does it will override other checks.
152 BASE_EXPORT std::optional<bool>& GetConvertibilityEnabledOverride();
153
154 // Returns a reference to a cached boolean optional. If a value exists, it means
155 // that the queried registry key, ConvertibleChassis, exists. Windows may cache
156 // the results of convertible chassis queries, preventing the need for running
157 // the expensive WMI query. This should always be checked prior to running
158 // `IsChassisConvertible()`.
159 BASE_EXPORT std::optional<bool>& GetConvertibleChassisKeyValue();
160
161 // Returns a function pointer that points to the lambda function that
162 // tracks if the device's convertible slate mode state has ever changed, which
163 // would indicate that proper GPIO drivers are available for a convertible
164 // machine. A pointer is used so that the function at the address can be
165 // replaced for testing purposes.
166 bool (*&HasCSMStateChanged(void))();
167
168 // Returns true if the device can be converted between table and desktop modes.
169 // This function may make blocking calls to system facilities to make this
170 // determination. As such, it must not be called from contexts that disallow
171 // blocking (i.e., the UI thread). The steps to determine the convertibility are
172 // based on the following publication:
173 // https://learn.microsoft.com/en-us/windows-hardware/customize/desktop/settings-for-better-tablet-experiences?source=recommendations
174 BASE_EXPORT BASE_EXPORT bool QueryDeviceConvertibility();
175
176 // A tablet is a device that is touch enabled and also is being used
177 // "like a tablet". This is used by the following:
178 // 1. Metrics: To gain insight into how users use Chrome.
179 // 2. Physical keyboard presence: If a device is in tablet mode, it means
180 // that there is no physical keyboard attached.
181 // This function optionally sets the |reason| parameter to determine as to why
182 // or why not a device was deemed to be a tablet.
183 // Returns true if the user has set Windows 10 in tablet mode.
184 BASE_EXPORT bool IsTabletDevice(std::string* reason, HWND hwnd);
185
186 // Return true if the device is physically used as a tablet independently of
187 // Windows tablet mode. It checks if the device:
188 // - Is running Windows 8 or newer,
189 // - Has a touch digitizer,
190 // - Is not docked,
191 // - Has a supported rotation sensor,
192 // - Is not in laptop mode,
193 // - prefers the mobile or slate power management profile (per OEM choice), and
194 // - Is in slate mode.
195 // This function optionally sets the |reason| parameter to determine as to why
196 // or why not a device was deemed to be a tablet.
197 BASE_EXPORT bool IsDeviceUsedAsATablet(std::string* reason);
198
199 // A slate is a touch device that may have a keyboard attached. This function
200 // returns true if a keyboard is attached and optionally will set the |reason|
201 // parameter to the detection method that was used to detect the keyboard.
202 BASE_EXPORT bool IsKeyboardPresentOnSlate(HWND hwnd, std::string* reason);
203
204 // Get the size of a struct up to and including the specified member.
205 // This is necessary to set compatible struct sizes for different versions
206 // of certain Windows APIs (e.g. SystemParametersInfo).
207 #define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(struct_name, member) \
208 offsetof(struct_name, member) + \
209 (sizeof static_cast<struct_name*>(NULL)->member)
210
211 // Returns true if the machine is enrolled to a domain.
212 BASE_EXPORT bool IsEnrolledToDomain();
213
214 // Returns true if either the device is joined to Azure Active Directory (AD) or
215 // one or more Azure AD work accounts have been added on the device. This call
216 // trigger some I/O when loading netapi32.dll to determine the management state.
217 BASE_EXPORT bool IsJoinedToAzureAD();
218
219 // Returns true if the machine is being managed by an MDM system.
220 BASE_EXPORT bool IsDeviceRegisteredWithManagement();
221
222 // Returns true if the current process can make USER32 or GDI32 calls such as
223 // CreateWindow and CreateDC. Windows 8 and above allow the kernel component
224 // of these calls to be disabled (also known as win32k lockdown) which can
225 // cause undefined behaviour such as crashes. This function can be used to
226 // guard areas of code using these calls and provide a fallback path if
227 // necessary.
228 // Because they are not always needed (and not needed at all in processes that
229 // have the win32k lockdown), USER32 and GDI32 are delayloaded. Attempts to
230 // load them in those processes will cause a crash. Any code which uses USER32
231 // or GDI32 and may run in a locked-down process MUST be guarded using this
232 // method. Before the dlls were delayloaded, method calls into USER32 and GDI32
233 // did not work, so adding calls to this method to guard them simply avoids
234 // unnecessary method calls.
235 BASE_EXPORT bool IsUser32AndGdi32Available();
236
237 // Takes a snapshot of the modules loaded in the |process|. The returned
238 // HMODULEs are not add-ref'd, so they should not be closed and may be
239 // invalidated at any time (should a module be unloaded). |process| requires
240 // the PROCESS_QUERY_INFORMATION and PROCESS_VM_READ permissions.
241 BASE_EXPORT bool GetLoadedModulesSnapshot(HANDLE process,
242 std::vector<HMODULE>* snapshot);
243
244 // Adds or removes the MICROSOFT_TABLETPENSERVICE_PROPERTY property with the
245 // TABLET_DISABLE_FLICKS & TABLET_DISABLE_FLICKFALLBACKKEYS flags in order to
246 // disable pen flick gestures for the given HWND.
247 BASE_EXPORT void EnableFlicks(HWND hwnd);
248 BASE_EXPORT void DisableFlicks(HWND hwnd);
249
250 // Enable high-DPI support for the current process.
251 BASE_EXPORT void EnableHighDPISupport();
252
253 // Returns a string representation of |rguid|.
254 BASE_EXPORT std::wstring WStringFromGUID(const ::GUID& rguid);
255
256 // Attempts to pin user32.dll to ensure it remains loaded. If it isn't loaded
257 // yet, the module will first be loaded and then the pin will be attempted. If
258 // pinning is successful, returns true. If the module cannot be loaded and/or
259 // pinned, |error| is set and the method returns false.
260 BASE_EXPORT bool PinUser32(NativeLibraryLoadError* error = nullptr);
261
262 // Gets a pointer to a function within user32.dll, if available. If user32.dll
263 // cannot be loaded or the function cannot be found, this function returns
264 // nullptr and sets |error|. Once loaded, user32.dll is pinned, and therefore
265 // the function pointer returned by this function will never change and can be
266 // cached.
267 BASE_EXPORT void* GetUser32FunctionPointer(
268 const char* function_name,
269 NativeLibraryLoadError* error = nullptr);
270
271 // Returns the name of a desktop or a window station.
272 BASE_EXPORT std::wstring GetWindowObjectName(HANDLE handle);
273
274 // Gets information about the pointer device. When successful, updates `result`
275 // and returns true, otherwise returns false without modifying `result`.
276 // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getpointerdevice
277 BASE_EXPORT bool GetPointerDevice(HANDLE device, POINTER_DEVICE_INFO& result);
278
279 // Gets information about the pointer devices attached to the system.
280 // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getpointerdevices
281 BASE_EXPORT std::optional<std::vector<POINTER_DEVICE_INFO>> GetPointerDevices();
282
283 // Registers a window to process the WM_POINTERDEVICECHANGE event, and
284 // optionally WM_POINTERDEVICEINRANGE and WM_POINTERDEVICEOUTOFRANGE events when
285 // `notify_proximity_changes` is set.
286 // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerpointerdevicenotifications
287 BASE_EXPORT bool RegisterPointerDeviceNotifications(
288 HWND hwnd,
289 bool notify_proximity_changes = false);
290
291 // Checks if the calling thread is running under a desktop with the name
292 // given by |desktop_name|. |desktop_name| is ASCII case insensitive (non-ASCII
293 // characters will be compared with exact matches).
294 BASE_EXPORT bool IsRunningUnderDesktopName(std::wstring_view desktop_name);
295
296 // Returns true if current session is a remote session.
297 BASE_EXPORT bool IsCurrentSessionRemote();
298
299 // IsAppVerifierLoaded() indicates whether Application Verifier is *already*
300 // loaded into the current process.
301 BASE_EXPORT bool IsAppVerifierLoaded();
302
303 // Replaces the name of each environment variable embedded in the specified
304 // string with the string equivalent of the value of the variable, then returns
305 // the resulting string.
306 //
307 // The implementation calls the `ExpandEnvironmentStrings` WinAPI, meaning:
308 // * Each %variableName% portion is replaced with the current value of that
309 // environment variable.
310 // * Case is ignored when looking up the environment-variable name.
311 // * If the name is not found, the %variableName% portion is left unexpanded.
312 //
313 // If `ExpandEnvironmentStrings` fails, `std::nullopt` is returned.
314 BASE_EXPORT std::optional<std::wstring> ExpandEnvironmentVariables(
315 wcstring_view str);
316
317 // Allows changing the domain enrolled state for the life time of the object.
318 // The original state is restored upon destruction.
319 class BASE_EXPORT ScopedDomainStateForTesting {
320 public:
321 explicit ScopedDomainStateForTesting(bool state);
322
323 ScopedDomainStateForTesting(const ScopedDomainStateForTesting&) = delete;
324 ScopedDomainStateForTesting& operator=(const ScopedDomainStateForTesting&) =
325 delete;
326
327 ~ScopedDomainStateForTesting();
328
329 private:
330 bool initial_state_;
331 };
332
333 // Allows changing the management registration state for the life time of the
334 // object. The original state is restored upon destruction.
335 class BASE_EXPORT ScopedDeviceRegisteredWithManagementForTesting {
336 public:
337 explicit ScopedDeviceRegisteredWithManagementForTesting(bool state);
338
339 ScopedDeviceRegisteredWithManagementForTesting(
340 const ScopedDeviceRegisteredWithManagementForTesting&) = delete;
341 ScopedDeviceRegisteredWithManagementForTesting& operator=(
342 const ScopedDeviceRegisteredWithManagementForTesting&) = delete;
343
344 ~ScopedDeviceRegisteredWithManagementForTesting();
345
346 private:
347 bool initial_state_;
348 };
349
350 // Allows changing the Azure Active Directory join state for the lifetime of the
351 // object. The original state is restored upon destruction.
352 class BASE_EXPORT ScopedAzureADJoinStateForTesting {
353 public:
354 explicit ScopedAzureADJoinStateForTesting(bool state);
355 ScopedAzureADJoinStateForTesting(const ScopedAzureADJoinStateForTesting&) =
356 delete;
357 ScopedAzureADJoinStateForTesting& operator=(
358 const ScopedAzureADJoinStateForTesting&) = delete;
359 ~ScopedAzureADJoinStateForTesting();
360
361 private:
362 const bool initial_state_;
363 };
364
365 // Allows changing the return values of convertibility functions for the
366 // lifetime of the object. The original state is restored upon destruction.
367 class BASE_EXPORT
368 [[maybe_unused, nodiscard]] ScopedDeviceConvertibilityStateForTesting {
369 public:
370 using QueryFunction = bool (*)();
371 ScopedDeviceConvertibilityStateForTesting(
372 bool form_convertible,
373 bool chassis_convertible,
374 QueryFunction csm_changed,
375 std::optional<bool> convertible_chassis_key,
376 std::optional<bool> convertibility_enabled);
377 ScopedDeviceConvertibilityStateForTesting(
378 const ScopedDeviceConvertibilityStateForTesting&) = delete;
379 ScopedDeviceConvertibilityStateForTesting& operator=(
380 const ScopedDeviceConvertibilityStateForTesting&) = delete;
381 ~ScopedDeviceConvertibilityStateForTesting();
382
383 private:
384 AutoReset<bool> initial_form_convertible_;
385 AutoReset<bool> initial_chassis_convertible_;
386 AutoReset<QueryFunction> initial_csm_changed_;
387 AutoReset<std::optional<bool>> initial_convertible_chassis_key_;
388 AutoReset<std::optional<bool>> initial_convertibility_enabled_;
389 };
390
391 } // namespace win
392 } // namespace base
393
394 #endif // BASE_WIN_WIN_UTIL_H_
395