summaryrefslogtreecommitdiffstats
path: root/base/win_util.cc
diff options
context:
space:
mode:
Diffstat (limited to 'base/win_util.cc')
-rw-r--r--base/win_util.cc359
1 files changed, 359 insertions, 0 deletions
diff --git a/base/win_util.cc b/base/win_util.cc
new file mode 100644
index 0000000..478a5a6
--- /dev/null
+++ b/base/win_util.cc
@@ -0,0 +1,359 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "base/win_util.h"
+
+#include <sddl.h>
+
+#include "base/logging.h"
+#include "base/registry.h"
+#include "base/scoped_handle.h"
+#include "base/string_util.h"
+
+namespace win_util {
+
+#define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(struct_name, member) \
+ offsetof(struct_name, member) + \
+ (sizeof static_cast<struct_name*>(NULL)->member)
+#define NONCLIENTMETRICS_SIZE_PRE_VISTA \
+ SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont)
+
+void GetNonClientMetrics(NONCLIENTMETRICS* metrics) {
+ DCHECK(metrics);
+
+ static const UINT SIZEOF_NONCLIENTMETRICS =
+ (GetWinVersion() == WINVERSION_VISTA) ?
+ sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA;
+ metrics->cbSize = SIZEOF_NONCLIENTMETRICS;
+ const bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
+ SIZEOF_NONCLIENTMETRICS, metrics,
+ 0);
+ DCHECK(success);
+}
+
+WinVersion GetWinVersion() {
+ static bool checked_version = false;
+ static WinVersion win_version = WINVERSION_PRE_2000;
+ if (!checked_version) {
+ OSVERSIONINFO version_info;
+ version_info.dwOSVersionInfoSize = sizeof version_info;
+ GetVersionEx(&version_info);
+ if (version_info.dwMajorVersion == 5) {
+ switch (version_info.dwMinorVersion) {
+ case 0:
+ win_version = WINVERSION_2000;
+ break;
+ case 1:
+ win_version = WINVERSION_XP;
+ break;
+ case 2:
+ default:
+ win_version = WINVERSION_SERVER_2003;
+ break;
+ }
+ } else if (version_info.dwMajorVersion >= 6) {
+ win_version = WINVERSION_VISTA;
+ }
+ checked_version = true;
+ }
+ return win_version;
+}
+
+bool AddAccessToKernelObject(HANDLE handle, WELL_KNOWN_SID_TYPE known_sid,
+ ACCESS_MASK access) {
+ PSECURITY_DESCRIPTOR descriptor = NULL;
+ PACL old_dacl = NULL;
+ PACL new_dacl = NULL;
+
+ if (ERROR_SUCCESS != GetSecurityInfo(handle, SE_KERNEL_OBJECT,
+ DACL_SECURITY_INFORMATION, NULL, NULL, &old_dacl, NULL,
+ &descriptor))
+ return false;
+
+ BYTE sid[SECURITY_MAX_SID_SIZE] = {0};
+ DWORD size_sid = SECURITY_MAX_SID_SIZE;
+
+ if (known_sid == WinSelfSid) {
+ // We hijack WinSelfSid when we want to add the current user instead of
+ // a known sid.
+ HANDLE token = NULL;
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) {
+ LocalFree(descriptor);
+ return false;
+ }
+
+ DWORD size = sizeof(TOKEN_USER) + size_sid;
+ TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]);
+ scoped_ptr<TOKEN_USER> token_user_ptr(token_user);
+ BOOL ret = GetTokenInformation(token, TokenUser, token_user, size, &size);
+
+ CloseHandle(token);
+
+ if (!ret) {
+ LocalFree(descriptor);
+ return false;
+ }
+ memcpy(sid, token_user->User.Sid, size_sid);
+ } else {
+ if (!CreateWellKnownSid(known_sid , NULL, sid, &size_sid)) {
+ LocalFree(descriptor);
+ return false;
+ }
+ }
+
+ EXPLICIT_ACCESS new_access = {0};
+ new_access.grfAccessMode = GRANT_ACCESS;
+ new_access.grfAccessPermissions = access;
+ new_access.grfInheritance = NO_INHERITANCE;
+
+ new_access.Trustee.pMultipleTrustee = NULL;
+ new_access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+ new_access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ new_access.Trustee.ptstrName = reinterpret_cast<LPWSTR>(&sid);
+
+ if (ERROR_SUCCESS != SetEntriesInAcl(1, &new_access, old_dacl, &new_dacl)) {
+ LocalFree(descriptor);
+ return false;
+ }
+
+ DWORD result = SetSecurityInfo(handle, SE_KERNEL_OBJECT,
+ DACL_SECURITY_INFORMATION, NULL, NULL,
+ new_dacl, NULL);
+
+ LocalFree(new_dacl);
+ LocalFree(descriptor);
+
+ if (ERROR_SUCCESS != result)
+ return false;
+
+ return true;
+}
+
+bool GetUserSidString(std::wstring* user_sid) {
+ // Get the current token.
+ HANDLE token = NULL;
+ if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token))
+ return false;
+ ScopedHandle token_scoped(token);
+
+ DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
+ scoped_ptr<TOKEN_USER> user(reinterpret_cast<TOKEN_USER*>(new BYTE[size]));
+
+ if (!::GetTokenInformation(token, TokenUser, user.get(), size, &size))
+ return false;
+
+ if (!user->User.Sid)
+ return false;
+
+ // Convert the data to a string.
+ wchar_t* sid_string;
+ if (!::ConvertSidToStringSid(user->User.Sid, &sid_string))
+ return false;
+
+ *user_sid = sid_string;
+
+ ::LocalFree(sid_string);
+
+ return true;
+}
+
+bool GetLogonSessionOnlyDACL(SECURITY_DESCRIPTOR** security_descriptor) {
+ // Get the current token.
+ HANDLE token = NULL;
+ if (!OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token))
+ return false;
+ ScopedHandle token_scoped(token);
+
+ // Get the size of the TokenGroups structure.
+ DWORD size = 0;
+ BOOL result = GetTokenInformation(token, TokenGroups, NULL, 0, &size);
+ if (result != FALSE && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ return false;
+
+ // Get the data.
+ scoped_ptr<TOKEN_GROUPS> token_groups;
+ token_groups.reset(reinterpret_cast<TOKEN_GROUPS*>(new char[size]));
+
+ if (!GetTokenInformation(token, TokenGroups, token_groups.get(), size, &size))
+ return false;
+
+ // Look for the logon sid.
+ SID* logon_sid = NULL;
+ for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
+ if ((token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) != 0) {
+ logon_sid = static_cast<SID*>(token_groups->Groups[i].Sid);
+ break;
+ }
+ }
+
+ if (!logon_sid)
+ return false;
+
+ // Convert the data to a string.
+ wchar_t* sid_string;
+ if (!ConvertSidToStringSid(logon_sid, &sid_string))
+ return false;
+
+ static const wchar_t dacl_format[] = L"D:(A;OICI;GA;;;%s)";
+ wchar_t dacl[SECURITY_MAX_SID_SIZE + arraysize(dacl_format) + 1] = {0};
+ wsprintf(dacl, dacl_format, sid_string);
+
+ LocalFree(sid_string);
+
+ // Convert the string to a security descriptor
+ if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
+ dacl,
+ SDDL_REVISION_1,
+ reinterpret_cast<PSECURITY_DESCRIPTOR*>(security_descriptor),
+ NULL)) {
+ return false;
+ }
+
+ return true;
+}
+
+#pragma warning(push)
+#pragma warning(disable:4312 4244)
+WNDPROC SetWindowProc(HWND hwnd, WNDPROC proc) {
+ // The reason we don't return the SetwindowLongPtr() value is that it returns
+ // the orignal window procedure and not the current one. I don't know if it is
+ // a bug or an intended feature.
+ WNDPROC oldwindow_proc =
+ reinterpret_cast<WNDPROC>(GetWindowLongPtr(hwnd, GWLP_WNDPROC));
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(proc));
+ return oldwindow_proc;
+}
+
+void* SetWindowUserData(HWND hwnd, void* user_data) {
+ return
+ reinterpret_cast<void*>(SetWindowLongPtr(hwnd, GWLP_USERDATA,
+ reinterpret_cast<LONG_PTR>(user_data)));
+}
+
+void* GetWindowUserData(HWND hwnd) {
+ return reinterpret_cast<void*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
+}
+
+// Maps to the WNDPROC for a window that was active before the subclass was
+// installed.
+static const wchar_t* const kHandlerKey = L"__ORIGINAL_MESSAGE_HANDLER__";
+
+bool Subclass(HWND window, WNDPROC subclass_proc) {
+ WNDPROC original_handler =
+ reinterpret_cast<WNDPROC>(GetWindowLongPtr(window, GWLP_WNDPROC));
+ if (original_handler != subclass_proc) {
+ win_util::SetWindowProc(window, subclass_proc);
+ SetProp(window, kHandlerKey, original_handler);
+ return true;
+ }
+ return false;
+}
+
+bool Unsubclass(HWND window, WNDPROC subclass_proc) {
+ WNDPROC current_handler =
+ reinterpret_cast<WNDPROC>(GetWindowLongPtr(window, GWLP_WNDPROC));
+ if (current_handler == subclass_proc) {
+ HANDLE original_handler = GetProp(window, kHandlerKey);
+ if (original_handler) {
+ RemoveProp(window, kHandlerKey);
+ win_util::SetWindowProc(window,
+ reinterpret_cast<WNDPROC>(original_handler));
+ return true;
+ }
+ }
+ return false;
+}
+
+WNDPROC GetSuperclassWNDPROC(HWND window) {
+ return reinterpret_cast<WNDPROC>(GetProp(window, kHandlerKey));
+}
+
+#pragma warning(pop)
+
+bool IsShiftPressed() {
+ return (::GetKeyState(VK_SHIFT) & 0x80) == 0x80;
+}
+
+bool IsCtrlPressed() {
+ return (::GetKeyState(VK_CONTROL) & 0x80) == 0x80;
+}
+
+bool IsAltPressed() {
+ return (::GetKeyState(VK_MENU) & 0x80) == 0x80;
+}
+
+std::wstring GetClassName(HWND window) {
+ // GetClassNameW will return a truncated result (properly null terminated) if
+ // the given buffer is not large enough. So, it is not possible to determine
+ // that we got the entire class name if the result is exactly equal to the
+ // size of the buffer minus one.
+ DWORD buffer_size = MAX_PATH;
+ while (true) {
+ std::wstring output;
+ DWORD size_ret =
+ GetClassNameW(window, WriteInto(&output, buffer_size), buffer_size);
+ if (size_ret == 0)
+ break;
+ if (size_ret < (buffer_size - 1)) {
+ output.resize(size_ret);
+ return output;
+ }
+ buffer_size *= 2;
+ }
+ return std::wstring(); // error
+}
+
+bool UserAccountControlIsEnabled() {
+ RegKey key(HKEY_LOCAL_MACHINE,
+ L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System");
+ DWORD uac_enabled;
+ if (!key.ReadValueDW(L"EnableLUA", &uac_enabled))
+ return true;
+ return (uac_enabled == 1);
+}
+
+} // namespace win_util
+
+#ifdef _MSC_VER
+//
+// If the ASSERT below fails, please install Visual Studio 2005 Service Pack 1.
+//
+extern char VisualStudio2005ServicePack1Detection[10];
+COMPILE_ASSERT(sizeof(&VisualStudio2005ServicePack1Detection) == 4,
+ VS2005SP1Detect);
+//
+// Chrome requires at least Service Pack 1 for Visual Studio 2005.
+//
+#endif // _MSC_VER
+
+#ifndef COPY_FILE_COPY_SYMLINK
+#error You must install the Windows 2008 or Vista Software Development Kit and \
+set it as your default include path to build this library. You can grab it by \
+searching for "download windows sdk 2008" in your favorite web search engine.
+#endif