1 // Copyright (c) 2011 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 <shobjidl.h> // Must be before propkey. 9 #include <propkey.h> 10 #include <propvarutil.h> 11 #include <sddl.h> 12 #include <shlobj.h> 13 14 #include "base/logging.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/win/registry.h" 17 #include "base/string_util.h" 18 #include "base/stringprintf.h" 19 #include "base/threading/thread_restrictions.h" 20 #include "base/win/scoped_handle.h" 21 #include "base/win/windows_version.h" 22 23 namespace base { 24 namespace win { 25 26 #define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(struct_name, member) \ 27 offsetof(struct_name, member) + \ 28 (sizeof static_cast<struct_name*>(NULL)->member) 29 #define NONCLIENTMETRICS_SIZE_PRE_VISTA \ 30 SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont) 31 32 void GetNonClientMetrics(NONCLIENTMETRICS* metrics) { 33 DCHECK(metrics); 34 35 static const UINT SIZEOF_NONCLIENTMETRICS = 36 (base::win::GetVersion() >= base::win::VERSION_VISTA) ? 37 sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; 38 metrics->cbSize = SIZEOF_NONCLIENTMETRICS; 39 const bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 40 SIZEOF_NONCLIENTMETRICS, metrics, 41 0); 42 DCHECK(success); 43 } 44 45 bool GetUserSidString(std::wstring* user_sid) { 46 // Get the current token. 47 HANDLE token = NULL; 48 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token)) 49 return false; 50 base::win::ScopedHandle token_scoped(token); 51 52 DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE; 53 scoped_array<BYTE> user_bytes(new BYTE[size]); 54 TOKEN_USER* user = reinterpret_cast<TOKEN_USER*>(user_bytes.get()); 55 56 if (!::GetTokenInformation(token, TokenUser, user, size, &size)) 57 return false; 58 59 if (!user->User.Sid) 60 return false; 61 62 // Convert the data to a string. 63 wchar_t* sid_string; 64 if (!::ConvertSidToStringSid(user->User.Sid, &sid_string)) 65 return false; 66 67 *user_sid = sid_string; 68 69 ::LocalFree(sid_string); 70 71 return true; 72 } 73 74 bool IsShiftPressed() { 75 return (::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000; 76 } 77 78 bool IsCtrlPressed() { 79 return (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000; 80 } 81 82 bool IsAltPressed() { 83 return (::GetKeyState(VK_MENU) & 0x8000) == 0x8000; 84 } 85 86 bool UserAccountControlIsEnabled() { 87 // This can be slow if Windows ends up going to disk. Should watch this key 88 // for changes and only read it once, preferably on the file thread. 89 // http://code.google.com/p/chromium/issues/detail?id=61644 90 base::ThreadRestrictions::ScopedAllowIO allow_io; 91 92 base::win::RegKey key(HKEY_LOCAL_MACHINE, 93 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", 94 KEY_READ); 95 DWORD uac_enabled; 96 if (key.ReadValueDW(L"EnableLUA", &uac_enabled) != ERROR_SUCCESS) 97 return true; 98 // Users can set the EnableLUA value to something arbitrary, like 2, which 99 // Vista will treat as UAC enabled, so we make sure it is not set to 0. 100 return (uac_enabled != 0); 101 } 102 103 bool SetAppIdForPropertyStore(IPropertyStore* property_store, 104 const wchar_t* app_id) { 105 DCHECK(property_store); 106 107 // App id should be less than 128 chars and contain no space. And recommended 108 // format is CompanyName.ProductName[.SubProduct.ProductNumber]. 109 // See http://msdn.microsoft.com/en-us/library/dd378459%28VS.85%29.aspx 110 DCHECK(lstrlen(app_id) < 128 && wcschr(app_id, L' ') == NULL); 111 112 PROPVARIANT property_value; 113 if (FAILED(InitPropVariantFromString(app_id, &property_value))) 114 return false; 115 116 HRESULT result = property_store->SetValue(PKEY_AppUserModel_ID, 117 property_value); 118 if (S_OK == result) 119 result = property_store->Commit(); 120 121 PropVariantClear(&property_value); 122 return SUCCEEDED(result); 123 } 124 125 static const char16 kAutoRunKeyPath[] = 126 L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; 127 128 bool AddCommandToAutoRun(HKEY root_key, const string16& name, 129 const string16& command) { 130 base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE); 131 return (autorun_key.WriteValue(name.c_str(), command.c_str()) == 132 ERROR_SUCCESS); 133 } 134 135 bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name) { 136 base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE); 137 return (autorun_key.DeleteValue(name.c_str()) == ERROR_SUCCESS); 138 } 139 140 bool ReadCommandFromAutoRun(HKEY root_key, 141 const string16& name, 142 string16* command) { 143 base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_QUERY_VALUE); 144 return (autorun_key.ReadValue(name.c_str(), command) == ERROR_SUCCESS); 145 } 146 147 } // namespace win 148 } // namespace base 149 150 #ifdef _MSC_VER 151 // 152 // If the ASSERT below fails, please install Visual Studio 2005 Service Pack 1. 153 // 154 extern char VisualStudio2005ServicePack1Detection[10]; 155 COMPILE_ASSERT(sizeof(&VisualStudio2005ServicePack1Detection) == sizeof(void*), 156 VS2005SP1Detect); 157 // 158 // Chrome requires at least Service Pack 1 for Visual Studio 2005. 159 // 160 #endif // _MSC_VER 161 162 #ifndef COPY_FILE_COPY_SYMLINK 163 #error You must install the Windows 2008 or Vista Software Development Kit and \ 164 set it as your default include path to build this library. You can grab it by \ 165 searching for "download windows sdk 2008" in your favorite web search engine. \ 166 Also make sure you register the SDK with Visual Studio, by selecting \ 167 "Integrate Windows SDK with Visual Studio 2005" from the Windows SDK \ 168 menu (see Start - All Programs - Microsoft Windows SDK - \ 169 Visual Studio Registration). 170 #endif 171