Home | History | Annotate | Download | only in win
      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 <lm.h>
      9 #include <shellapi.h>
     10 #include <shlobj.h>
     11 #include <shobjidl.h>  // Must be before propkey.
     12 #include <initguid.h>
     13 #include <propkey.h>
     14 #include <propvarutil.h>
     15 #include <sddl.h>
     16 #include <signal.h>
     17 #include <stdlib.h>
     18 
     19 #include "base/lazy_instance.h"
     20 #include "base/logging.h"
     21 #include "base/memory/scoped_ptr.h"
     22 #include "base/strings/string_util.h"
     23 #include "base/strings/stringprintf.h"
     24 #include "base/threading/thread_restrictions.h"
     25 #include "base/win/metro.h"
     26 #include "base/win/registry.h"
     27 #include "base/win/scoped_co_mem.h"
     28 #include "base/win/scoped_handle.h"
     29 #include "base/win/scoped_propvariant.h"
     30 #include "base/win/windows_version.h"
     31 
     32 namespace {
     33 
     34 // Sets the value of |property_key| to |property_value| in |property_store|.
     35 bool SetPropVariantValueForPropertyStore(
     36     IPropertyStore* property_store,
     37     const PROPERTYKEY& property_key,
     38     const base::win::ScopedPropVariant& property_value) {
     39   DCHECK(property_store);
     40 
     41   HRESULT result = property_store->SetValue(property_key, property_value.get());
     42   if (result == S_OK)
     43     result = property_store->Commit();
     44   return SUCCEEDED(result);
     45 }
     46 
     47 void __cdecl ForceCrashOnSigAbort(int) {
     48   *((int*)0) = 0x1337;
     49 }
     50 
     51 const wchar_t kWindows8OSKRegPath[] =
     52     L"Software\\Classes\\CLSID\\{054AAE20-4BEA-4347-8A35-64A533254A9D}"
     53     L"\\LocalServer32";
     54 
     55 }  // namespace
     56 
     57 namespace base {
     58 namespace win {
     59 
     60 static bool g_crash_on_process_detach = false;
     61 
     62 #define NONCLIENTMETRICS_SIZE_PRE_VISTA \
     63     SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont)
     64 
     65 void GetNonClientMetrics(NONCLIENTMETRICS* metrics) {
     66   DCHECK(metrics);
     67 
     68   static const UINT SIZEOF_NONCLIENTMETRICS =
     69       (base::win::GetVersion() >= base::win::VERSION_VISTA) ?
     70       sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA;
     71   metrics->cbSize = SIZEOF_NONCLIENTMETRICS;
     72   const bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
     73                                               SIZEOF_NONCLIENTMETRICS, metrics,
     74                                               0);
     75   DCHECK(success);
     76 }
     77 
     78 bool GetUserSidString(std::wstring* user_sid) {
     79   // Get the current token.
     80   HANDLE token = NULL;
     81   if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token))
     82     return false;
     83   base::win::ScopedHandle token_scoped(token);
     84 
     85   DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
     86   scoped_ptr<BYTE[]> user_bytes(new BYTE[size]);
     87   TOKEN_USER* user = reinterpret_cast<TOKEN_USER*>(user_bytes.get());
     88 
     89   if (!::GetTokenInformation(token, TokenUser, user, size, &size))
     90     return false;
     91 
     92   if (!user->User.Sid)
     93     return false;
     94 
     95   // Convert the data to a string.
     96   wchar_t* sid_string;
     97   if (!::ConvertSidToStringSid(user->User.Sid, &sid_string))
     98     return false;
     99 
    100   *user_sid = sid_string;
    101 
    102   ::LocalFree(sid_string);
    103 
    104   return true;
    105 }
    106 
    107 bool IsShiftPressed() {
    108   return (::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000;
    109 }
    110 
    111 bool IsCtrlPressed() {
    112   return (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000;
    113 }
    114 
    115 bool IsAltPressed() {
    116   return (::GetKeyState(VK_MENU) & 0x8000) == 0x8000;
    117 }
    118 
    119 bool IsAltGrPressed() {
    120   return (::GetKeyState(VK_MENU) & 0x8000) == 0x8000 &&
    121       (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000;
    122 }
    123 
    124 bool UserAccountControlIsEnabled() {
    125   // This can be slow if Windows ends up going to disk.  Should watch this key
    126   // for changes and only read it once, preferably on the file thread.
    127   //   http://code.google.com/p/chromium/issues/detail?id=61644
    128   base::ThreadRestrictions::ScopedAllowIO allow_io;
    129 
    130   base::win::RegKey key(HKEY_LOCAL_MACHINE,
    131       L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
    132       KEY_READ);
    133   DWORD uac_enabled;
    134   if (key.ReadValueDW(L"EnableLUA", &uac_enabled) != ERROR_SUCCESS)
    135     return true;
    136   // Users can set the EnableLUA value to something arbitrary, like 2, which
    137   // Vista will treat as UAC enabled, so we make sure it is not set to 0.
    138   return (uac_enabled != 0);
    139 }
    140 
    141 bool SetBooleanValueForPropertyStore(IPropertyStore* property_store,
    142                                      const PROPERTYKEY& property_key,
    143                                      bool property_bool_value) {
    144   ScopedPropVariant property_value;
    145   if (FAILED(InitPropVariantFromBoolean(property_bool_value,
    146                                         property_value.Receive()))) {
    147     return false;
    148   }
    149 
    150   return SetPropVariantValueForPropertyStore(property_store,
    151                                              property_key,
    152                                              property_value);
    153 }
    154 
    155 bool SetStringValueForPropertyStore(IPropertyStore* property_store,
    156                                     const PROPERTYKEY& property_key,
    157                                     const wchar_t* property_string_value) {
    158   ScopedPropVariant property_value;
    159   if (FAILED(InitPropVariantFromString(property_string_value,
    160                                        property_value.Receive()))) {
    161     return false;
    162   }
    163 
    164   return SetPropVariantValueForPropertyStore(property_store,
    165                                              property_key,
    166                                              property_value);
    167 }
    168 
    169 bool SetAppIdForPropertyStore(IPropertyStore* property_store,
    170                               const wchar_t* app_id) {
    171   // App id should be less than 64 chars and contain no space. And recommended
    172   // format is CompanyName.ProductName[.SubProduct.ProductNumber].
    173   // See http://msdn.microsoft.com/en-us/library/dd378459%28VS.85%29.aspx
    174   DCHECK(lstrlen(app_id) < 64 && wcschr(app_id, L' ') == NULL);
    175 
    176   return SetStringValueForPropertyStore(property_store,
    177                                         PKEY_AppUserModel_ID,
    178                                         app_id);
    179 }
    180 
    181 static const char16 kAutoRunKeyPath[] =
    182     L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
    183 
    184 bool AddCommandToAutoRun(HKEY root_key, const string16& name,
    185                          const string16& command) {
    186   base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
    187   return (autorun_key.WriteValue(name.c_str(), command.c_str()) ==
    188       ERROR_SUCCESS);
    189 }
    190 
    191 bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name) {
    192   base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
    193   return (autorun_key.DeleteValue(name.c_str()) == ERROR_SUCCESS);
    194 }
    195 
    196 bool ReadCommandFromAutoRun(HKEY root_key,
    197                             const string16& name,
    198                             string16* command) {
    199   base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_QUERY_VALUE);
    200   return (autorun_key.ReadValue(name.c_str(), command) == ERROR_SUCCESS);
    201 }
    202 
    203 void SetShouldCrashOnProcessDetach(bool crash) {
    204   g_crash_on_process_detach = crash;
    205 }
    206 
    207 bool ShouldCrashOnProcessDetach() {
    208   return g_crash_on_process_detach;
    209 }
    210 
    211 void SetAbortBehaviorForCrashReporting() {
    212   // Prevent CRT's abort code from prompting a dialog or trying to "report" it.
    213   // Disabling the _CALL_REPORTFAULT behavior is important since otherwise it
    214   // has the sideffect of clearing our exception filter, which means we
    215   // don't get any crash.
    216   _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
    217 
    218   // Set a SIGABRT handler for good measure. We will crash even if the default
    219   // is left in place, however this allows us to crash earlier. And it also
    220   // lets us crash in response to code which might directly call raise(SIGABRT)
    221   signal(SIGABRT, ForceCrashOnSigAbort);
    222 }
    223 
    224 bool IsTouchEnabledDevice() {
    225   if (base::win::GetVersion() < base::win::VERSION_WIN7)
    226     return false;
    227   const int kMultiTouch = NID_INTEGRATED_TOUCH | NID_MULTI_INPUT | NID_READY;
    228   int sm = GetSystemMetrics(SM_DIGITIZER);
    229   if ((sm & kMultiTouch) == kMultiTouch) {
    230     return true;
    231   }
    232   return false;
    233 }
    234 
    235 bool DisplayVirtualKeyboard() {
    236   if (base::win::GetVersion() < base::win::VERSION_WIN8)
    237     return false;
    238 
    239   static base::LazyInstance<string16>::Leaky osk_path =
    240       LAZY_INSTANCE_INITIALIZER;
    241 
    242   if (osk_path.Get().empty()) {
    243     // We need to launch TabTip.exe from the location specified under the
    244     // LocalServer32 key for the {{054AAE20-4BEA-4347-8A35-64A533254A9D}}
    245     // CLSID.
    246     // TabTip.exe is typically found at
    247     // c:\program files\common files\microsoft shared\ink on English Windows.
    248     // We don't want to launch TabTip.exe from
    249     // c:\program files (x86)\common files\microsoft shared\ink. This path is
    250     // normally found on 64 bit Windows.
    251     base::win::RegKey key(HKEY_LOCAL_MACHINE,
    252                           kWindows8OSKRegPath,
    253                           KEY_READ | KEY_WOW64_64KEY);
    254     DWORD osk_path_length = 1024;
    255     if (key.ReadValue(NULL,
    256                       WriteInto(&osk_path.Get(), osk_path_length),
    257                       &osk_path_length,
    258                       NULL) != ERROR_SUCCESS) {
    259       DLOG(WARNING) << "Failed to read on screen keyboard path from registry";
    260       return false;
    261     }
    262     size_t common_program_files_offset =
    263         osk_path.Get().find(L"%CommonProgramFiles%");
    264     // Typically the path to TabTip.exe read from the registry will start with
    265     // %CommonProgramFiles% which needs to be replaced with the corrsponding
    266     // expanded string.
    267     // If the path does not begin with %CommonProgramFiles% we use it as is.
    268     if (common_program_files_offset != string16::npos) {
    269       // Preserve the beginning quote in the path.
    270       osk_path.Get().erase(common_program_files_offset,
    271                            wcslen(L"%CommonProgramFiles%"));
    272       // The path read from the registry contains the %CommonProgramFiles%
    273       // environment variable prefix. On 64 bit Windows the SHGetKnownFolderPath
    274       // function returns the common program files path with the X86 suffix for
    275       // the FOLDERID_ProgramFilesCommon value.
    276       // To get the correct path to TabTip.exe we first read the environment
    277       // variable CommonProgramW6432 which points to the desired common
    278       // files path. Failing that we fallback to the SHGetKnownFolderPath API.
    279 
    280       // We then replace the %CommonProgramFiles% value with the actual common
    281       // files path found in the process.
    282       string16 common_program_files_path;
    283       scoped_ptr<wchar_t[]> common_program_files_wow6432;
    284       DWORD buffer_size =
    285           GetEnvironmentVariable(L"CommonProgramW6432", NULL, 0);
    286       if (buffer_size) {
    287         common_program_files_wow6432.reset(new wchar_t[buffer_size]);
    288         GetEnvironmentVariable(L"CommonProgramW6432",
    289                                common_program_files_wow6432.get(),
    290                                buffer_size);
    291         common_program_files_path = common_program_files_wow6432.get();
    292         DCHECK(!common_program_files_path.empty());
    293       } else {
    294         base::win::ScopedCoMem<wchar_t> common_program_files;
    295         if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, NULL,
    296                                         &common_program_files))) {
    297           return false;
    298         }
    299         common_program_files_path = common_program_files;
    300       }
    301 
    302       osk_path.Get().insert(1, common_program_files_path);
    303     }
    304   }
    305 
    306   HINSTANCE ret = ::ShellExecuteW(NULL,
    307                                   L"",
    308                                   osk_path.Get().c_str(),
    309                                   NULL,
    310                                   NULL,
    311                                   SW_SHOW);
    312   return reinterpret_cast<int>(ret) > 32;
    313 }
    314 
    315 bool DismissVirtualKeyboard() {
    316   if (base::win::GetVersion() < base::win::VERSION_WIN8)
    317     return false;
    318 
    319   // We dismiss the virtual keyboard by generating the ESC keystroke
    320   // programmatically.
    321   const wchar_t kOSKClassName[] = L"IPTip_Main_Window";
    322   HWND osk = ::FindWindow(kOSKClassName, NULL);
    323   if (::IsWindow(osk) && ::IsWindowEnabled(osk)) {
    324     PostMessage(osk, WM_SYSCOMMAND, SC_CLOSE, 0);
    325     return true;
    326   }
    327   return false;
    328 }
    329 
    330 typedef HWND (*MetroRootWindow) ();
    331 
    332 // As of this writing, GetMonitorInfo function seem to return wrong values
    333 // for rcWork.left and rcWork.top in case of split screen situation inside
    334 // metro mode. In order to get required values we query for core window screen
    335 // coordinates.
    336 // TODO(shrikant): Remove detour code once GetMonitorInfo is fixed for 8.1.
    337 BOOL GetMonitorInfoWrapper(HMONITOR monitor, MONITORINFO* mi) {
    338   BOOL ret = ::GetMonitorInfo(monitor, mi);
    339 #if !defined(USE_ASH)
    340   if (base::win::IsMetroProcess() &&
    341       base::win::GetVersion() >= base::win::VERSION_WIN8_1) {
    342     static MetroRootWindow root_window = NULL;
    343     if (!root_window) {
    344       HMODULE metro = base::win::GetMetroModule();
    345       // There are apparently instances when current process is inside metro
    346       // environment but metro driver dll is not loaded.
    347       if (!metro) {
    348         return ret;
    349       }
    350       root_window = reinterpret_cast<MetroRootWindow>(
    351           ::GetProcAddress(metro, "GetRootWindow"));
    352     }
    353     ret = ::GetWindowRect(root_window(), &(mi->rcWork));
    354   }
    355 #endif
    356   return ret;
    357 }
    358 
    359 bool IsEnrolledToDomain() {
    360   LPWSTR domain;
    361   NETSETUP_JOIN_STATUS join_status;
    362   if(::NetGetJoinInformation(NULL, &domain, &join_status) != NERR_Success)
    363     return false;
    364   ::NetApiBufferFree(domain);
    365 
    366   return join_status == ::NetSetupDomainName;
    367 }
    368 
    369 }  // namespace win
    370 }  // namespace base
    371 
    372 #ifdef _MSC_VER
    373 
    374 // There are optimizer bugs in x86 VS2012 pre-Update 1.
    375 #if _MSC_VER == 1700 && defined _M_IX86 && _MSC_FULL_VER < 170051106
    376 
    377 #pragma message("Relevant defines:")
    378 #define __STR2__(x) #x
    379 #define __STR1__(x) __STR2__(x)
    380 #define __PPOUT__(x) "#define " #x " " __STR1__(x)
    381 #if defined(_M_IX86)
    382   #pragma message(__PPOUT__(_M_IX86))
    383 #endif
    384 #if defined(_M_X64)
    385   #pragma message(__PPOUT__(_M_X64))
    386 #endif
    387 #if defined(_MSC_FULL_VER)
    388   #pragma message(__PPOUT__(_MSC_FULL_VER))
    389 #endif
    390 
    391 #pragma message("Visual Studio 2012 x86 must be updated to at least Update 1")
    392 #error Must install Update 1 to Visual Studio 2012.
    393 #endif
    394 
    395 #endif  // _MSC_VER
    396 
    397