• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2010 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 #include "base/win/win_util.h"
6 
7 #include <objbase.h>
8 
9 #include <string_view>
10 
11 #include "base/containers/contains.h"
12 #include "base/files/file_path.h"
13 #include "base/scoped_environment_variable_override.h"
14 #include "base/scoped_native_library.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/win/registry.h"
18 #include "base/win/scoped_co_mem.h"
19 #include "base/win/scoped_com_initializer.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 
22 namespace base {
23 namespace win {
24 
25 namespace {
26 
27 // Saves the current thread's locale ID when initialized, and restores it when
28 // the instance is going out of scope.
29 class ThreadLocaleSaver {
30  public:
ThreadLocaleSaver()31   ThreadLocaleSaver() : original_locale_id_(GetThreadLocale()) {}
32 
33   ThreadLocaleSaver(const ThreadLocaleSaver&) = delete;
34   ThreadLocaleSaver& operator=(const ThreadLocaleSaver&) = delete;
35 
~ThreadLocaleSaver()36   ~ThreadLocaleSaver() { SetThreadLocale(original_locale_id_); }
37 
38  private:
39   LCID original_locale_id_;
40 };
41 
__anon7377086c0202() 42 auto* csm_false = static_cast<bool (*)()>([]() -> bool { return false; });
43 
__anon7377086c0302() 44 auto* csm_true = static_cast<bool (*)()>([]() -> bool { return true; });
45 
46 }  // namespace
47 
48 // The test is somewhat silly, because some bots some have UAC enabled and some
49 // have it disabled. At least we check that it does not crash.
TEST(BaseWinUtilTest,TestIsUACEnabled)50 TEST(BaseWinUtilTest, TestIsUACEnabled) {
51   UserAccountControlIsEnabled();
52 }
53 
TEST(BaseWinUtilTest,TestGetUserSidString)54 TEST(BaseWinUtilTest, TestGetUserSidString) {
55   std::wstring user_sid;
56   EXPECT_TRUE(GetUserSidString(&user_sid));
57   EXPECT_TRUE(!user_sid.empty());
58 }
59 
TEST(BaseWinUtilTest,TestGetLoadedModulesSnapshot)60 TEST(BaseWinUtilTest, TestGetLoadedModulesSnapshot) {
61   std::vector<HMODULE> snapshot;
62 
63   ASSERT_TRUE(GetLoadedModulesSnapshot(::GetCurrentProcess(), &snapshot));
64   size_t original_snapshot_size = snapshot.size();
65   ASSERT_GT(original_snapshot_size, 0u);
66   snapshot.clear();
67 
68   // Load in a new module. Pick zipfldr.dll as it is present from WinXP to
69   // Win10, including ARM64 Win10, and yet rarely used.
70   const FilePath::CharType dll_name[] = FILE_PATH_LITERAL("zipfldr.dll");
71   ASSERT_EQ(nullptr, ::GetModuleHandle(dll_name));
72 
73   ScopedNativeLibrary new_dll((FilePath(dll_name)));
74   ASSERT_NE(static_cast<HMODULE>(nullptr), new_dll.get());
75   ASSERT_TRUE(GetLoadedModulesSnapshot(::GetCurrentProcess(), &snapshot));
76   ASSERT_GT(snapshot.size(), original_snapshot_size);
77   ASSERT_TRUE(Contains(snapshot, new_dll.get()));
78 }
79 
TEST(BaseWinUtilTest,TestUint32ToInvalidHandle)80 TEST(BaseWinUtilTest, TestUint32ToInvalidHandle) {
81   // Ensure that INVALID_HANDLE_VALUE is preserved when going to a 32-bit value
82   // and back on 64-bit platforms.
83   uint32_t invalid_handle = HandleToUint32(INVALID_HANDLE_VALUE);
84   EXPECT_EQ(INVALID_HANDLE_VALUE, Uint32ToHandle(invalid_handle));
85 }
86 
TEST(BaseWinUtilTest,WStringFromGUID)87 TEST(BaseWinUtilTest, WStringFromGUID) {
88   const GUID kGuid = {0x7698f759,
89                       0xf5b0,
90                       0x4328,
91                       {0x92, 0x38, 0xbd, 0x70, 0x8a, 0x6d, 0xc9, 0x63}};
92   const std::wstring_view kGuidStr = L"{7698F759-F5B0-4328-9238-BD708A6DC963}";
93   auto guid_wstring = WStringFromGUID(kGuid);
94   EXPECT_EQ(guid_wstring, kGuidStr);
95   wchar_t guid_wchar[39];
96   ::StringFromGUID2(kGuid, guid_wchar, std::size(guid_wchar));
97   EXPECT_STREQ(guid_wstring.c_str(), guid_wchar);
98   ScopedCoMem<OLECHAR> clsid_string;
99   ::StringFromCLSID(kGuid, &clsid_string);
100   EXPECT_STREQ(guid_wstring.c_str(), clsid_string.get());
101 }
102 
TEST(BaseWinUtilTest,GetWindowObjectName)103 TEST(BaseWinUtilTest, GetWindowObjectName) {
104   std::wstring created_desktop_name(L"test_desktop");
105   HDESK desktop_handle =
106       ::CreateDesktop(created_desktop_name.c_str(), nullptr, nullptr, 0,
107                       DESKTOP_CREATEWINDOW | DESKTOP_READOBJECTS |
108                           READ_CONTROL | WRITE_DAC | WRITE_OWNER,
109                       nullptr);
110 
111   ASSERT_NE(desktop_handle, nullptr);
112   EXPECT_EQ(created_desktop_name, GetWindowObjectName(desktop_handle));
113   ASSERT_TRUE(::CloseDesktop(desktop_handle));
114 }
115 
TEST(BaseWinUtilTest,IsRunningUnderDesktopName)116 TEST(BaseWinUtilTest, IsRunningUnderDesktopName) {
117   HDESK thread_desktop = ::GetThreadDesktop(::GetCurrentThreadId());
118 
119   ASSERT_NE(thread_desktop, nullptr);
120   std::wstring desktop_name = GetWindowObjectName(thread_desktop);
121 
122   EXPECT_TRUE(IsRunningUnderDesktopName(desktop_name));
123   EXPECT_TRUE(IsRunningUnderDesktopName(
124       AsWString(ToLowerASCII(AsStringPiece16(desktop_name)))));
125   EXPECT_TRUE(IsRunningUnderDesktopName(
126       AsWString(ToUpperASCII(AsStringPiece16(desktop_name)))));
127   EXPECT_FALSE(
128       IsRunningUnderDesktopName(desktop_name + L"_non_existent_desktop_name"));
129 }
130 
TEST(BaseWinUtilTest,ExpandEnvironmentVariables)131 TEST(BaseWinUtilTest, ExpandEnvironmentVariables) {
132   constexpr char kTestEnvVar[] = "TEST_ENV_VAR";
133   constexpr char kTestEnvVarValue[] = "TEST_VALUE";
134   ScopedEnvironmentVariableOverride scoped_env(kTestEnvVar, kTestEnvVarValue);
135 
136   auto path_with_env_var = UTF8ToWide(std::string("C:\\%") + kTestEnvVar + "%");
137   auto path_expanded = UTF8ToWide(std::string("C:\\") + kTestEnvVarValue);
138 
139   EXPECT_EQ(ExpandEnvironmentVariables(path_with_env_var).value(),
140             path_expanded);
141 }
142 
TEST(BaseWinUtilTest,ExpandEnvironmentVariablesEmptyValue)143 TEST(BaseWinUtilTest, ExpandEnvironmentVariablesEmptyValue) {
144   constexpr char kTestEnvVar[] = "TEST_ENV_VAR";
145   constexpr char kTestEnvVarValue[] = "";
146   ScopedEnvironmentVariableOverride scoped_env(kTestEnvVar, kTestEnvVarValue);
147 
148   auto path_with_env_var = UTF8ToWide(std::string("C:\\%") + kTestEnvVar + "%");
149   auto path_expanded = UTF8ToWide(std::string("C:\\") + kTestEnvVarValue);
150 
151   EXPECT_EQ(ExpandEnvironmentVariables(path_with_env_var).value(),
152             path_expanded);
153 }
154 
TEST(BaseWinUtilTest,ExpandEnvironmentVariablesUndefinedValue)155 TEST(BaseWinUtilTest, ExpandEnvironmentVariablesUndefinedValue) {
156   constexpr char kTestEnvVar[] = "TEST_ENV_VAR";
157 
158   auto path_with_env_var = UTF8ToWide(std::string("C:\\%") + kTestEnvVar + "%");
159 
160   // Undefined env vars are left unexpanded.
161   auto path_expanded = path_with_env_var;
162 
163   EXPECT_EQ(ExpandEnvironmentVariables(path_with_env_var).value(),
164             path_expanded);
165 }
166 
TEST(DeviceConvertibilityTest,None)167 TEST(DeviceConvertibilityTest, None) {
168   ScopedCOMInitializer com_initializer;
169   ASSERT_TRUE(com_initializer.Succeeded());
170   ScopedDeviceConvertibilityStateForTesting scoper(false, false, csm_false,
171                                                    std::nullopt, std::nullopt);
172   EXPECT_FALSE(QueryDeviceConvertibility());
173 }
174 
TEST(DeviceConvertibilityTest,ConvertibilityDisabled)175 TEST(DeviceConvertibilityTest, ConvertibilityDisabled) {
176   ScopedCOMInitializer com_initializer;
177   ASSERT_TRUE(com_initializer.Succeeded());
178   // If convertibility is not enabled but the key exists, other values shouldn't
179   // be checked. Device is not convertible.
180   ScopedDeviceConvertibilityStateForTesting scoper(
181       /*form_convertible=*/true, /*chassis_convertible=*/true,
182       /*csm_changed=*/csm_false, /*convertible_chassis_key=*/std::nullopt,
183       /*convertibility_enabled=*/std::optional<bool>{false});
184   EXPECT_FALSE(QueryDeviceConvertibility());
185 }
186 
TEST(DeviceConvertibilityTest,ConvertibilityEnabled)187 TEST(DeviceConvertibilityTest, ConvertibilityEnabled) {
188   ScopedCOMInitializer com_initializer;
189   ASSERT_TRUE(com_initializer.Succeeded());
190   ScopedDeviceConvertibilityStateForTesting scoper(
191       /*form_convertible=*/false, /*chassis_convertible=*/false,
192       /*csm_changed=*/csm_false, /*convertible_chassis_key=*/std::nullopt,
193       /*convertibility_enabled=*/std::optional<bool>{true});
194   EXPECT_TRUE(QueryDeviceConvertibility());
195 }
196 
TEST(DeviceConvertibilityTest,ChassisConvertibleKeyTrue)197 TEST(DeviceConvertibilityTest, ChassisConvertibleKeyTrue) {
198   ScopedCOMInitializer com_initializer;
199   ASSERT_TRUE(com_initializer.Succeeded());
200   ScopedDeviceConvertibilityStateForTesting scoper(
201       /*form_convertible=*/false, /*chassis_convertible=*/false,
202       /*csm_changed=*/csm_false,
203       /*convertible_chassis_key=*/std::optional<bool>{true},
204       /*convertibility_enabled=*/std::nullopt);
205   EXPECT_TRUE(QueryDeviceConvertibility());
206 }
207 
TEST(DeviceConvertibilityTest,ChassisConvertibleKeyFalse)208 TEST(DeviceConvertibilityTest, ChassisConvertibleKeyFalse) {
209   ScopedCOMInitializer com_initializer;
210   ASSERT_TRUE(com_initializer.Succeeded());
211   ScopedDeviceConvertibilityStateForTesting scoper(
212       /*form_convertible=*/false, /*chassis_convertible=*/true,
213       /*csm_changed=*/csm_true,
214       /*convertible_chassis_key=*/std::optional<bool>{false},
215       /*convertibility_enabled=*/std::nullopt);
216   EXPECT_FALSE(QueryDeviceConvertibility());
217 }
218 
TEST(DeviceConvertibilityTest,FormConvertibleTrue)219 TEST(DeviceConvertibilityTest, FormConvertibleTrue) {
220   ScopedCOMInitializer com_initializer;
221   ASSERT_TRUE(com_initializer.Succeeded());
222   ScopedDeviceConvertibilityStateForTesting scoper(
223       /*form_convertible=*/true, /*chassis_convertible=*/false,
224       /*csm_changed=*/csm_false,
225       /*convertible_chassis_key=*/std::nullopt,
226       /*convertibility_enabled=*/std::nullopt);
227   EXPECT_TRUE(QueryDeviceConvertibility());
228 }
229 
TEST(DeviceConvertibilityTest,ChassisConvertibleTrue)230 TEST(DeviceConvertibilityTest, ChassisConvertibleTrue) {
231   ScopedCOMInitializer com_initializer;
232   ASSERT_TRUE(com_initializer.Succeeded());
233   ScopedDeviceConvertibilityStateForTesting scoper(
234       /*form_convertible=*/false, /*chassis_convertible=*/true,
235       /*csm_changed=*/csm_false,
236       /*convertible_chassis_key=*/std::nullopt,
237       /*convertibility_enabled=*/std::nullopt);
238   EXPECT_TRUE(QueryDeviceConvertibility());
239 }
240 
TEST(DeviceConvertibilityTest,ConvertibleSlateModeChangeTrue)241 TEST(DeviceConvertibilityTest, ConvertibleSlateModeChangeTrue) {
242   ScopedCOMInitializer com_initializer;
243   ASSERT_TRUE(com_initializer.Succeeded());
244   ScopedDeviceConvertibilityStateForTesting scoper(
245       /*form_convertible=*/false, /*chassis_convertible=*/false,
246       /*csm_changed=*/csm_true,
247       /*convertible_chassis_key=*/std::nullopt,
248       /*convertibility_enabled=*/std::nullopt);
249   EXPECT_TRUE(QueryDeviceConvertibility());
250 }
251 
TEST(DeviceConvertibilityTest,ConvertibilityEnabledSanityCheck)252 TEST(DeviceConvertibilityTest, ConvertibilityEnabledSanityCheck) {
253   RegKey key(HKEY_LOCAL_MACHINE,
254              L"System\\CurrentControlSet\\Control\\PriorityControl", KEY_READ);
255   if (key.HasValue(L"ConvertibilityEnabled")) {
256     ASSERT_TRUE(GetConvertibilityEnabledOverride().has_value());
257   } else {
258     ASSERT_FALSE(GetConvertibilityEnabledOverride().has_value());
259   }
260 }
261 
TEST(DeviceConvertibilityTest,ConvertibilityKeySanityCheck)262 TEST(DeviceConvertibilityTest, ConvertibilityKeySanityCheck) {
263   RegKey key(HKEY_CURRENT_USER,
264              L"SOFTWARE\\Microsoft\\TabletTip\\ConvertibleChassis", KEY_READ);
265   if (key.HasValue(L"ConvertibleChassis")) {
266     ASSERT_TRUE(GetConvertibleChassisKeyValue().has_value());
267   } else {
268     ASSERT_FALSE(GetConvertibleChassisKeyValue().has_value());
269   }
270 }
271 
TEST(DeviceConvertibilityTest,DeviceFormAndChassisConvertible)272 TEST(DeviceConvertibilityTest, DeviceFormAndChassisConvertible) {
273   ScopedCOMInitializer com_initializer;
274   ASSERT_TRUE(com_initializer.Succeeded());
275   EXPECT_FALSE(IsDeviceFormConvertible() || IsChassisConvertible());
276 }
277 
278 }  // namespace win
279 }  // namespace base
280