summaryrefslogtreecommitdiffstats
path: root/chromium/base/win
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-08 14:30:41 +0200
committerJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-12 13:49:54 +0200
commitab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch)
tree498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/base/win
parent4ce69f7403811819800e7c5ae1318b2647e778d1 (diff)
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/base/win')
-rw-r--r--chromium/base/win/OWNERS1
-rw-r--r--chromium/base/win/dllmain.cc6
-rw-r--r--chromium/base/win/event_trace_consumer.h2
-rw-r--r--chromium/base/win/event_trace_consumer_unittest.cc66
-rw-r--r--chromium/base/win/event_trace_controller.cc2
-rw-r--r--chromium/base/win/iat_patch_function.cc20
-rw-r--r--chromium/base/win/iat_patch_function.h2
-rw-r--r--chromium/base/win/message_window.cc4
-rw-r--r--chromium/base/win/metro.cc38
-rw-r--r--chromium/base/win/metro.h11
-rw-r--r--chromium/base/win/object_watcher.cc4
-rw-r--r--chromium/base/win/registry.cc189
-rw-r--r--chromium/base/win/registry.h20
-rw-r--r--chromium/base/win/registry_unittest.cc201
-rw-r--r--chromium/base/win/scoped_com_initializer.h5
-rw-r--r--chromium/base/win/scoped_gdi_object.h2
-rw-r--r--chromium/base/win/scoped_handle.h6
-rw-r--r--chromium/base/win/scoped_process_information_unittest.cc3
-rw-r--r--chromium/base/win/shortcut.cc133
-rw-r--r--chromium/base/win/shortcut.h49
-rw-r--r--chromium/base/win/shortcut_unittest.cc59
-rw-r--r--chromium/base/win/startup_information_unittest.cc2
-rw-r--r--chromium/base/win/text_services_message_filter.cc82
-rw-r--r--chromium/base/win/text_services_message_filter.h48
-rw-r--r--chromium/base/win/win_util.cc82
-rw-r--r--chromium/base/win/win_util.h15
26 files changed, 699 insertions, 353 deletions
diff --git a/chromium/base/win/OWNERS b/chromium/base/win/OWNERS
index 3aae3d6bec8..65ed72168fd 100644
--- a/chromium/base/win/OWNERS
+++ b/chromium/base/win/OWNERS
@@ -1 +1,2 @@
cpu@chromium.org
+rvargas@chromium.org
diff --git a/chromium/base/win/dllmain.cc b/chromium/base/win/dllmain.cc
index 9d2a6dc76ce..907c7f4034e 100644
--- a/chromium/base/win/dllmain.cc
+++ b/chromium/base/win/dllmain.cc
@@ -54,9 +54,9 @@ static void NTAPI on_callback(PVOID h, DWORD reason, PVOID reserved);
#endif // _WIN64
-// Explicitly depend on tlssup.cc variable to bracket the list of TLS callbacks.
-extern "C" PIMAGE_TLS_CALLBACK __xl_a;
-extern "C" PIMAGE_TLS_CALLBACK __xl_z;
+// Explicitly depend on VC\crt\src\tlssup.c variables
+// to bracket the list of TLS callbacks.
+extern "C" PIMAGE_TLS_CALLBACK __xl_a, __xl_z;
// extern "C" suppresses C++ name mangling so we know the symbol names for the
// linker /INCLUDE:symbol pragmas above.
diff --git a/chromium/base/win/event_trace_consumer.h b/chromium/base/win/event_trace_consumer.h
index c1b42b4fd93..9322e1e9b4f 100644
--- a/chromium/base/win/event_trace_consumer.h
+++ b/chromium/base/win/event_trace_consumer.h
@@ -16,7 +16,7 @@ namespace base {
namespace win {
// This class is a base class that makes it easier to consume events
-// from realtime or file sessions. Concrete consumers need to sublass
+// from realtime or file sessions. Concrete consumers need to subclass
// a specialization of this class and override the ProcessEvent and/or
// the ProcessBuffer methods to implement the event consumption logic.
// Usage might look like:
diff --git a/chromium/base/win/event_trace_consumer_unittest.cc b/chromium/base/win/event_trace_consumer_unittest.cc
index d238192c4f8..9066a7c8ff0 100644
--- a/chromium/base/win/event_trace_consumer_unittest.cc
+++ b/chromium/base/win/event_trace_consumer_unittest.cc
@@ -43,10 +43,9 @@ class TestConsumer: public EtwTraceConsumerBase<TestConsumer> {
}
void ClearQueue() {
- EventQueue::const_iterator it(events_.begin()), end(events_.end());
-
- for (; it != end; ++it) {
- delete [] it->MofData;
+ for (EventQueue::const_iterator it(events_.begin()), end(events_.end());
+ it != end; ++it) {
+ delete[] it->MofData;
}
events_.clear();
@@ -56,7 +55,7 @@ class TestConsumer: public EtwTraceConsumerBase<TestConsumer> {
events_.push_back(*event);
EVENT_TRACE& back = events_.back();
- if (NULL != event->MofData && 0 != event->MofLength) {
+ if (event->MofData != NULL && event->MofLength != 0) {
back.MofData = new char[event->MofLength];
memcpy(back.MofData, event->MofData, event->MofLength);
}
@@ -94,7 +93,7 @@ class EtwTraceConsumerBaseTest: public testing::Test {
}
virtual void TearDown() {
- // Cleanup any potentially danging sessions.
+ // Cleanup any potentially dangling sessions.
EtwTraceProperties ignore;
EtwTraceController::Stop(session_name_.c_str(), &ignore);
}
@@ -112,14 +111,12 @@ TEST_F(EtwTraceConsumerBaseTest, Initialize) {
TEST_F(EtwTraceConsumerBaseTest, OpenRealtimeSucceedsWhenNoSession) {
TestConsumer consumer_;
-
ASSERT_HRESULT_SUCCEEDED(
consumer_.OpenRealtimeSession(session_name_.c_str()));
}
TEST_F(EtwTraceConsumerBaseTest, ConsumerImmediateFailureWhenNoSession) {
TestConsumer consumer_;
-
ASSERT_HRESULT_SUCCEEDED(
consumer_.OpenRealtimeSession(session_name_.c_str()));
ASSERT_HRESULT_FAILED(consumer_.Consume());
@@ -131,22 +128,18 @@ class EtwTraceConsumerRealtimeTest: public EtwTraceConsumerBaseTest {
public:
virtual void SetUp() {
EtwTraceConsumerBaseTest::SetUp();
-
ASSERT_HRESULT_SUCCEEDED(
consumer_.OpenRealtimeSession(session_name_.c_str()));
}
virtual void TearDown() {
consumer_.Close();
-
EtwTraceConsumerBaseTest::TearDown();
}
DWORD ConsumerThread() {
::SetEvent(consumer_ready_.Get());
-
- HRESULT hr = consumer_.Consume();
- return hr;
+ return consumer_.Consume();
}
static DWORD WINAPI ConsumerThreadMainProc(void* arg) {
@@ -157,12 +150,11 @@ class EtwTraceConsumerRealtimeTest: public EtwTraceConsumerBaseTest {
HRESULT StartConsumerThread() {
consumer_ready_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
EXPECT_TRUE(consumer_ready_ != NULL);
- consumer_thread_.Set(::CreateThread(NULL, 0, ConsumerThreadMainProc,
- this, 0, NULL));
- if (NULL == consumer_thread_.Get())
+ consumer_thread_.Set(::CreateThread(NULL, 0, ConsumerThreadMainProc, this,
+ 0, NULL));
+ if (consumer_thread_.Get() == NULL)
return HRESULT_FROM_WIN32(::GetLastError());
- HRESULT hr = S_OK;
HANDLE events[] = { consumer_ready_, consumer_thread_ };
DWORD result = ::WaitForMultipleObjects(arraysize(events), events,
FALSE, INFINITE);
@@ -173,26 +165,21 @@ class EtwTraceConsumerRealtimeTest: public EtwTraceConsumerBaseTest {
case WAIT_OBJECT_0 + 1: {
// The thread finished. This may race with the event, so check
// explicitly for the event here, before concluding there's trouble.
- if (WAIT_OBJECT_0 == ::WaitForSingleObject(consumer_ready_, 0))
+ if (::WaitForSingleObject(consumer_ready_, 0) == WAIT_OBJECT_0)
return S_OK;
DWORD exit_code = 0;
if (::GetExitCodeThread(consumer_thread_, &exit_code))
return exit_code;
- else
- return HRESULT_FROM_WIN32(::GetLastError());
- break;
+ return HRESULT_FROM_WIN32(::GetLastError());
}
default:
return E_UNEXPECTED;
- break;
}
-
- return hr;
}
// Waits for consumer_ thread to exit, and returns its exit code.
HRESULT JoinConsumerThread() {
- if (WAIT_OBJECT_0 != ::WaitForSingleObject(consumer_thread_, INFINITE))
+ if (::WaitForSingleObject(consumer_thread_, INFINITE) != WAIT_OBJECT_0)
return HRESULT_FROM_WIN32(::GetLastError());
DWORD exit_code = 0;
@@ -211,10 +198,8 @@ class EtwTraceConsumerRealtimeTest: public EtwTraceConsumerBaseTest {
TEST_F(EtwTraceConsumerRealtimeTest, ConsumerReturnsWhenSessionClosed) {
EtwTraceController controller;
-
- HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(),
- 100 * 1024);
- if (hr == E_ACCESSDENIED) {
+ if (controller.StartRealtimeSession(session_name_.c_str(), 100 * 1024) ==
+ E_ACCESSDENIED) {
VLOG(1) << "You must be an administrator to run this test on Vista";
return;
}
@@ -224,7 +209,6 @@ TEST_F(EtwTraceConsumerRealtimeTest, ConsumerReturnsWhenSessionClosed) {
// Wait around for the consumer_ thread a bit.
ASSERT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(consumer_thread_, 50));
-
ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
// The consumer_ returns success on session stop.
@@ -234,34 +218,32 @@ TEST_F(EtwTraceConsumerRealtimeTest, ConsumerReturnsWhenSessionClosed) {
namespace {
// {57E47923-A549-476f-86CA-503D57F59E62}
-DEFINE_GUID(kTestEventType,
- 0x57e47923, 0xa549, 0x476f, 0x86, 0xca, 0x50, 0x3d, 0x57, 0xf5, 0x9e, 0x62);
+DEFINE_GUID(
+ kTestEventType,
+ 0x57e47923, 0xa549, 0x476f, 0x86, 0xca, 0x50, 0x3d, 0x57, 0xf5, 0x9e, 0x62);
} // namespace
TEST_F(EtwTraceConsumerRealtimeTest, ConsumeEvent) {
EtwTraceController controller;
- HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(),
- 100 * 1024);
- if (hr == E_ACCESSDENIED) {
+ if (controller.StartRealtimeSession(session_name_.c_str(), 100 * 1024) ==
+ E_ACCESSDENIED) {
VLOG(1) << "You must be an administrator to run this test on Vista";
return;
}
- ASSERT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_,
- TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
+ ASSERT_HRESULT_SUCCEEDED(controller.EnableProvider(
+ test_provider_, TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
EtwTraceProvider provider(test_provider_);
ASSERT_EQ(ERROR_SUCCESS, provider.Register());
// Start the consumer_.
ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
-
ASSERT_EQ(0, TestConsumer::events_.size());
EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR);
EXPECT_EQ(ERROR_SUCCESS, provider.Log(&event.header));
-
EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(TestConsumer::sank_event_,
INFINITE));
ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
@@ -306,8 +288,8 @@ class EtwTraceConsumerDataTest: public EtwTraceConsumerBaseTest {
return hr;
// Enable our provider.
- EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_,
- TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
+ EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(
+ test_provider_, TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
EtwTraceProvider provider(test_provider_);
// Then register our provider, means we get a session handle immediately.
@@ -374,7 +356,7 @@ TEST_F(EtwTraceConsumerDataTest, RoundTrip) {
return;
}
ASSERT_HRESULT_SUCCEEDED(hr) << "RoundTripEvent failed";
- ASSERT_TRUE(NULL != trace);
+ ASSERT_TRUE(trace != NULL);
ASSERT_EQ(sizeof(kData), trace->MofLength);
ASSERT_STREQ(kData, reinterpret_cast<const char*>(trace->MofData));
}
diff --git a/chromium/base/win/event_trace_controller.cc b/chromium/base/win/event_trace_controller.cc
index 0391fbc3016..9a35a6bd57a 100644
--- a/chromium/base/win/event_trace_controller.cc
+++ b/chromium/base/win/event_trace_controller.cc
@@ -64,7 +64,7 @@ HRESULT EtwTraceController::Start(const wchar_t* session_name,
}
HRESULT EtwTraceController::StartFileSession(const wchar_t* session_name,
- const wchar_t* logfile_path, bool realtime) {
+ const wchar_t* logfile_path, bool realtime) {
DCHECK(NULL == session_ && session_name_.empty());
EtwTraceProperties prop;
diff --git a/chromium/base/win/iat_patch_function.cc b/chromium/base/win/iat_patch_function.cc
index a4a89028b87..21c39950cc3 100644
--- a/chromium/base/win/iat_patch_function.cc
+++ b/chromium/base/win/iat_patch_function.cc
@@ -56,11 +56,23 @@ DWORD ModifyCode(void* old_code, void* new_code, int length) {
}
// Change the page protection so that we can write.
+ MEMORY_BASIC_INFORMATION memory_info;
DWORD error = NO_ERROR;
DWORD old_page_protection = 0;
+
+ if (!VirtualQuery(old_code, &memory_info, sizeof(memory_info))) {
+ error = GetLastError();
+ return error;
+ }
+
+ DWORD is_executable = (PAGE_EXECUTE | PAGE_EXECUTE_READ |
+ PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) &
+ memory_info.Protect;
+
if (VirtualProtect(old_code,
length,
- PAGE_READWRITE,
+ is_executable ? PAGE_EXECUTE_READWRITE :
+ PAGE_READWRITE,
&old_page_protection)) {
// Write the data.
@@ -74,7 +86,6 @@ DWORD ModifyCode(void* old_code, void* new_code, int length) {
&old_page_protection);
} else {
error = GetLastError();
- NOTREACHED();
}
return error;
@@ -274,5 +285,10 @@ DWORD IATPatchFunction::Unpatch() {
return error;
}
+void* IATPatchFunction::original_function() const {
+ DCHECK(is_patched());
+ return original_function_;
+}
+
} // namespace win
} // namespace base
diff --git a/chromium/base/win/iat_patch_function.h b/chromium/base/win/iat_patch_function.h
index 3ae1f3c460a..5026e0eb954 100644
--- a/chromium/base/win/iat_patch_function.h
+++ b/chromium/base/win/iat_patch_function.h
@@ -57,6 +57,8 @@ class BASE_EXPORT IATPatchFunction {
return (NULL != intercept_function_);
}
+ void* original_function() const;
+
private:
HMODULE module_handle_;
void* intercept_function_;
diff --git a/chromium/base/win/message_window.cc b/chromium/base/win/message_window.cc
index 56660740fc1..57fe64c7981 100644
--- a/chromium/base/win/message_window.cc
+++ b/chromium/base/win/message_window.cc
@@ -52,7 +52,7 @@ MessageWindow::WindowClass::WindowClass()
window_class.hIconSm = NULL;
atom_ = RegisterClassEx(&window_class);
if (atom_ == 0) {
- LOG_GETLASTERROR(ERROR)
+ PLOG(ERROR)
<< "Failed to register the window class for a message-only window";
}
}
@@ -108,7 +108,7 @@ bool MessageWindow::DoCreate(const MessageCallback& message_callback,
window_ = CreateWindow(MAKEINTATOM(window_class.atom()), window_name, 0, 0, 0,
0, 0, HWND_MESSAGE, 0, window_class.instance(), this);
if (!window_) {
- LOG_GETLASTERROR(ERROR) << "Failed to create a message-only window";
+ PLOG(ERROR) << "Failed to create a message-only window";
return false;
}
diff --git a/chromium/base/win/metro.cc b/chromium/base/win/metro.cc
index c78cc0946ee..62743c799b5 100644
--- a/chromium/base/win/metro.cc
+++ b/chromium/base/win/metro.cc
@@ -12,10 +12,6 @@
namespace base {
namespace win {
-namespace {
-bool g_should_tsf_aware_required = false;
-}
-
HMODULE GetMetroModule() {
const HMODULE kUninitialized = reinterpret_cast<HMODULE>(1);
static HMODULE metro_module = kUninitialized;
@@ -70,40 +66,6 @@ bool IsProcessImmersive(HANDLE process) {
return false;
}
-bool IsTSFAwareRequired() {
- // Although this function is equal to IsMetroProcess at this moment,
- // Chrome for Win7 and Vista may support TSF in the future.
- return g_should_tsf_aware_required || IsMetroProcess();
-}
-
-void SetForceToUseTSF() {
- g_should_tsf_aware_required = true;
-
- // Since Windows 8 Metro mode disables CUAS (Cicero Unaware Application
- // Support) via ImmDisableLegacyIME API, Chrome must be fully TSF-aware on
- // Metro mode. For debugging purposes, explicitly call ImmDisableLegacyIME so
- // that one can test TSF functionality even on Windows 8 desktop mode. Note
- // that CUAS cannot be disabled on Windows Vista/7 where ImmDisableLegacyIME
- // is not available.
- typedef BOOL (* ImmDisableLegacyIMEFunc)();
- HMODULE imm32 = ::GetModuleHandleA("imm32.dll");
- if (imm32 == NULL)
- return;
-
- ImmDisableLegacyIMEFunc imm_disable_legacy_ime =
- reinterpret_cast<ImmDisableLegacyIMEFunc>(
- ::GetProcAddress(imm32, "ImmDisableLegacyIME"));
-
- if (imm_disable_legacy_ime == NULL) {
- // Unsupported API, just do nothing.
- return;
- }
-
- if (!imm_disable_legacy_ime()) {
- DVLOG(1) << "Failed to disable legacy IME.";
- }
-}
-
wchar_t* LocalAllocAndCopyString(const string16& src) {
size_t dest_size = (src.length() + 1) * sizeof(wchar_t);
wchar_t* dest = reinterpret_cast<wchar_t*>(LocalAlloc(LPTR, dest_size));
diff --git a/chromium/base/win/metro.h b/chromium/base/win/metro.h
index b2208fcb49c..5894ef06dae 100644
--- a/chromium/base/win/metro.h
+++ b/chromium/base/win/metro.h
@@ -76,17 +76,6 @@ BASE_EXPORT bool IsMetroProcess();
// immersive (Metro) process.
BASE_EXPORT bool IsProcessImmersive(HANDLE process);
-// Returns true if this process is running under Text Services Framework (TSF)
-// and browser must be TSF-aware.
-BASE_EXPORT bool IsTSFAwareRequired();
-
-// Sets browser to use Text Services Framework (TSF) regardless of process
-// status. On Windows 8, this function also disables CUAS (Cicero Unaware
-// Application Support) to emulate Windows Metro mode in terms of IME
-// functionality. This should be beneficial in QA process because on can test
-// IME functionality in Windows 8 desktop mode.
-BASE_EXPORT void SetForceToUseTSF();
-
// Allocates and returns the destination string via the LocalAlloc API after
// copying the src to it.
BASE_EXPORT wchar_t* LocalAllocAndCopyString(const string16& src);
diff --git a/chromium/base/win/object_watcher.cc b/chromium/base/win/object_watcher.cc
index 078f5b9fa1c..3bb1cd32c52 100644
--- a/chromium/base/win/object_watcher.cc
+++ b/chromium/base/win/object_watcher.cc
@@ -43,7 +43,7 @@ bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) {
if (!RegisterWaitForSingleObject(&wait_object_, object, DoneWaiting,
this, INFINITE, wait_flags)) {
- DLOG_GETLASTERROR(FATAL) << "RegisterWaitForSingleObject failed";
+ DPLOG(FATAL) << "RegisterWaitForSingleObject failed";
object_ = NULL;
wait_object_ = NULL;
return false;
@@ -65,7 +65,7 @@ bool ObjectWatcher::StopWatching() {
// Blocking call to cancel the wait. Any callbacks already in progress will
// finish before we return from this call.
if (!UnregisterWaitEx(wait_object_, INVALID_HANDLE_VALUE)) {
- DLOG_GETLASTERROR(FATAL) << "UnregisterWaitEx failed";
+ DPLOG(FATAL) << "UnregisterWaitEx failed";
return false;
}
diff --git a/chromium/base/win/registry.cc b/chromium/base/win/registry.cc
index 8bfe4329711..a6cb9ae89f7 100644
--- a/chromium/base/win/registry.cc
+++ b/chromium/base/win/registry.cc
@@ -10,8 +10,7 @@
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
-
-#pragma comment(lib, "shlwapi.lib") // for SHDeleteKey
+#include "base/win/windows_version.h"
namespace base {
namespace win {
@@ -30,23 +29,29 @@ inline DWORD to_wchar_size(DWORD byte_size) {
return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t);
}
+// Mask to pull WOW64 access flags out of REGSAM access.
+const REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
+
} // namespace
// RegKey ----------------------------------------------------------------------
RegKey::RegKey()
: key_(NULL),
- watch_event_(0) {
+ watch_event_(0),
+ wow64access_(0) {
}
RegKey::RegKey(HKEY key)
: key_(key),
- watch_event_(0) {
+ watch_event_(0),
+ wow64access_(0) {
}
RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
: key_(NULL),
- watch_event_(0) {
+ watch_event_(0),
+ wow64access_(0) {
if (rootkey) {
if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
Create(rootkey, subkey, access);
@@ -54,6 +59,7 @@ RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
Open(rootkey, subkey, access);
} else {
DCHECK(!subkey);
+ wow64access_ = access & kWow64AccessMask;
}
}
@@ -69,43 +75,77 @@ LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
DWORD* disposition, REGSAM access) {
DCHECK(rootkey && subkey && access && disposition);
- Close();
-
+ HKEY subhkey = NULL;
LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL,
- REG_OPTION_NON_VOLATILE, access, NULL, &key_,
+ REG_OPTION_NON_VOLATILE, access, NULL, &subhkey,
disposition);
+ if (result == ERROR_SUCCESS) {
+ Close();
+ key_ = subhkey;
+ wow64access_ = access & kWow64AccessMask;
+ }
+
return result;
}
LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
DCHECK(name && access);
+ // After the application has accessed an alternate registry view using one of
+ // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations
+ // (create, delete, or open) on child registry keys must explicitly use the
+ // same flag. Otherwise, there can be unexpected behavior.
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
+ if ((access & kWow64AccessMask) != wow64access_) {
+ NOTREACHED();
+ return ERROR_INVALID_PARAMETER;
+ }
HKEY subkey = NULL;
LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
access, NULL, &subkey, NULL);
- Close();
+ if (result == ERROR_SUCCESS) {
+ Close();
+ key_ = subkey;
+ wow64access_ = access & kWow64AccessMask;
+ }
- key_ = subkey;
return result;
}
LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
DCHECK(rootkey && subkey && access);
- Close();
+ HKEY subhkey = NULL;
+
+ LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &subhkey);
+ if (result == ERROR_SUCCESS) {
+ Close();
+ key_ = subhkey;
+ wow64access_ = access & kWow64AccessMask;
+ }
- LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_);
return result;
}
LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
DCHECK(relative_key_name && access);
+ // After the application has accessed an alternate registry view using one of
+ // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations
+ // (create, delete, or open) on child registry keys must explicitly use the
+ // same flag. Otherwise, there can be unexpected behavior.
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
+ if ((access & kWow64AccessMask) != wow64access_) {
+ NOTREACHED();
+ return ERROR_INVALID_PARAMETER;
+ }
HKEY subkey = NULL;
LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey);
// We have to close the current opened key before replacing it with the new
// one.
- Close();
-
- key_ = subkey;
+ if (result == ERROR_SUCCESS) {
+ Close();
+ key_ = subkey;
+ wow64access_ = access & kWow64AccessMask;
+ }
return result;
}
@@ -114,9 +154,11 @@ void RegKey::Close() {
if (key_) {
::RegCloseKey(key_);
key_ = NULL;
+ wow64access_ = 0;
}
}
+// TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400
void RegKey::Set(HKEY key) {
if (key_ != key) {
Close();
@@ -125,6 +167,7 @@ void RegKey::Set(HKEY key) {
}
HKEY RegKey::Take() {
+ DCHECK(wow64access_ == 0);
StopWatching();
HKEY key = key_;
key_ = NULL;
@@ -155,8 +198,43 @@ LONG RegKey::GetValueNameAt(int index, std::wstring* name) const {
LONG RegKey::DeleteKey(const wchar_t* name) {
DCHECK(key_);
DCHECK(name);
- LONG result = SHDeleteKey(key_, name);
- return result;
+ HKEY subkey = NULL;
+
+ // Verify the key exists before attempting delete to replicate previous
+ // behavior.
+ LONG result =
+ RegOpenKeyEx(key_, name, 0, READ_CONTROL | wow64access_, &subkey);
+ if (result != ERROR_SUCCESS)
+ return result;
+ RegCloseKey(subkey);
+
+ return RegDelRecurse(key_, std::wstring(name), wow64access_);
+}
+
+LONG RegKey::DeleteEmptyKey(const wchar_t* name) {
+ DCHECK(key_);
+ DCHECK(name);
+
+ HKEY target_key = NULL;
+ LONG result = RegOpenKeyEx(key_, name, 0, KEY_READ | wow64access_,
+ &target_key);
+
+ if (result != ERROR_SUCCESS)
+ return result;
+
+ DWORD count = 0;
+ result = RegQueryInfoKey(target_key, NULL, 0, NULL, NULL, NULL, NULL, &count,
+ NULL, NULL, NULL, NULL);
+
+ RegCloseKey(target_key);
+
+ if (result != ERROR_SUCCESS)
+ return result;
+
+ if (count == 0)
+ return RegDeleteKeyExWrapper(key_, name, wow64access_, 0);
+
+ return ERROR_DIR_NOT_EMPTY;
}
LONG RegKey::DeleteValue(const wchar_t* value_name) {
@@ -329,6 +407,83 @@ LONG RegKey::StopWatching() {
return result;
}
+// static
+LONG RegKey::RegDeleteKeyExWrapper(HKEY hKey,
+ const wchar_t* lpSubKey,
+ REGSAM samDesired,
+ DWORD Reserved) {
+ typedef LSTATUS(WINAPI* RegDeleteKeyExPtr)(HKEY, LPCWSTR, REGSAM, DWORD);
+
+ RegDeleteKeyExPtr reg_delete_key_ex_func =
+ reinterpret_cast<RegDeleteKeyExPtr>(
+ GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegDeleteKeyExW"));
+
+ if (reg_delete_key_ex_func)
+ return reg_delete_key_ex_func(hKey, lpSubKey, samDesired, Reserved);
+
+ // Windows XP does not support RegDeleteKeyEx, so fallback to RegDeleteKey.
+ return RegDeleteKey(hKey, lpSubKey);
+}
+
+// static
+LONG RegKey::RegDelRecurse(HKEY root_key,
+ const std::wstring& name,
+ REGSAM access) {
+ // First, see if the key can be deleted without having to recurse.
+ LONG result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0);
+ if (result == ERROR_SUCCESS)
+ return result;
+
+ HKEY target_key = NULL;
+ result = RegOpenKeyEx(
+ root_key, name.c_str(), 0, KEY_ENUMERATE_SUB_KEYS | access, &target_key);
+
+ if (result == ERROR_FILE_NOT_FOUND)
+ return ERROR_SUCCESS;
+ if (result != ERROR_SUCCESS)
+ return result;
+
+ std::wstring subkey_name(name);
+
+ // Check for an ending slash and add one if it is missing.
+ if (!name.empty() && subkey_name[name.length() - 1] != L'\\')
+ subkey_name += L"\\";
+
+ // Enumerate the keys
+ result = ERROR_SUCCESS;
+ const DWORD kMaxKeyNameLength = MAX_PATH;
+ const size_t base_key_length = subkey_name.length();
+ std::wstring key_name;
+ while (result == ERROR_SUCCESS) {
+ DWORD key_size = kMaxKeyNameLength;
+ result = RegEnumKeyEx(target_key,
+ 0,
+ WriteInto(&key_name, kMaxKeyNameLength),
+ &key_size,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ if (result != ERROR_SUCCESS)
+ break;
+
+ key_name.resize(key_size);
+ subkey_name.resize(base_key_length);
+ subkey_name += key_name;
+
+ if (RegDelRecurse(root_key, subkey_name, access) != ERROR_SUCCESS)
+ break;
+ }
+
+ RegCloseKey(target_key);
+
+ // Try again to delete the key.
+ result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0);
+
+ return result;
+}
+
// RegistryValueIterator ------------------------------------------------------
RegistryValueIterator::RegistryValueIterator(HKEY root_key,
diff --git a/chromium/base/win/registry.h b/chromium/base/win/registry.h
index f97f4f5a379..af1aee7dce9 100644
--- a/chromium/base/win/registry.h
+++ b/chromium/base/win/registry.h
@@ -53,11 +53,11 @@ class BASE_EXPORT RegKey {
// Transfers ownership away from this object.
HKEY Take();
- // Returns false if this key does not have the specified value, of if an error
+ // Returns false if this key does not have the specified value, or if an error
// occurrs while attempting to access it.
bool HasValue(const wchar_t* value_name) const;
- // Returns the number of values for this key, of 0 if the number cannot be
+ // Returns the number of values for this key, or 0 if the number cannot be
// determined.
DWORD GetValueCount() const;
@@ -71,6 +71,10 @@ class BASE_EXPORT RegKey {
// it.
LONG DeleteKey(const wchar_t* name);
+ // Deletes an empty subkey. If the subkey has subkeys or values then this
+ // will fail.
+ LONG DeleteEmptyKey(const wchar_t* name);
+
// Deletes a single value within the key.
LONG DeleteValue(const wchar_t* name);
@@ -132,8 +136,20 @@ class BASE_EXPORT RegKey {
HKEY Handle() const { return key_; }
private:
+ // Calls RegDeleteKeyEx on supported platforms, alternatively falls back to
+ // RegDeleteKey.
+ static LONG RegDeleteKeyExWrapper(HKEY hKey,
+ const wchar_t* lpSubKey,
+ REGSAM samDesired,
+ DWORD Reserved);
+
+ // Recursively deletes a key and all of its subkeys.
+ static LONG RegDelRecurse(HKEY root_key,
+ const std::wstring& name,
+ REGSAM access);
HKEY key_; // The registry key being iterated.
HANDLE watch_event_;
+ REGSAM wow64access_;
DISALLOW_COPY_AND_ASSIGN(RegKey);
};
diff --git a/chromium/base/win/registry_unittest.cc b/chromium/base/win/registry_unittest.cc
index 155402a351f..84074b38586 100644
--- a/chromium/base/win/registry_unittest.cc
+++ b/chromium/base/win/registry_unittest.cc
@@ -9,6 +9,7 @@
#include "base/compiler_specific.h"
#include "base/stl_util.h"
+#include "base/win/windows_version.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -16,31 +17,54 @@ namespace win {
namespace {
-const wchar_t kRootKey[] = L"Base_Registry_Unittest";
-
class RegistryTest : public testing::Test {
- public:
- RegistryTest() {}
-
protected:
+#if defined(_WIN64)
+ static const REGSAM kNativeViewMask = KEY_WOW64_64KEY;
+ static const REGSAM kRedirectedViewMask = KEY_WOW64_32KEY;
+#else
+ static const REGSAM kNativeViewMask = KEY_WOW64_32KEY;
+ static const REGSAM kRedirectedViewMask = KEY_WOW64_64KEY;
+#endif // _WIN64
+
+ RegistryTest() {}
virtual void SetUp() OVERRIDE {
// Create a temporary key.
RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
key.DeleteKey(kRootKey);
ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+ foo_software_key_ = L"Software\\";
+ foo_software_key_ += kRootKey;
+ foo_software_key_ += L"\\Foo";
}
virtual void TearDown() OVERRIDE {
// Clean up the temporary key.
RegKey key(HKEY_CURRENT_USER, L"", KEY_SET_VALUE);
ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+ ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
}
+ static bool IsRedirectorPresent() {
+#if defined(_WIN64)
+ return true;
+#else
+ return OSInfo::GetInstance()->wow64_status() == OSInfo::WOW64_ENABLED;
+#endif
+ }
+
+ const wchar_t* const kRootKey = L"Base_Registry_Unittest";
+ std::wstring foo_software_key_;
+
private:
DISALLOW_COPY_AND_ASSIGN(RegistryTest);
};
+// static
+const REGSAM RegistryTest::kNativeViewMask;
+const REGSAM RegistryTest::kRedirectedViewMask;
+
TEST_F(RegistryTest, ValueTest) {
RegKey key;
@@ -158,6 +182,173 @@ TEST_F(RegistryTest, TruncatedCharTest) {
EXPECT_FALSE(iterator.Valid());
}
+TEST_F(RegistryTest, RecursiveDelete) {
+ RegKey key;
+ // Create kRootKey->Foo
+ // \->Bar (TestValue)
+ // \->Foo (TestValue)
+ // \->Bar
+ // \->Foo
+ // \->Moo
+ // \->Foo
+ // and delete kRootKey->Foo
+ std::wstring foo_key(kRootKey);
+ foo_key += L"\\Foo";
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+ ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE));
+ ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData"));
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+ ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Moo", KEY_WRITE));
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+ ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE));
+ foo_key += L"\\Bar";
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+ foo_key += L"\\Foo";
+ ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE));
+ ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData"));
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
+
+ ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE));
+ ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"Bar"));
+ ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo"));
+ ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Bar\\Foo"));
+ ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Bar"));
+ ASSERT_EQ(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Foo"));
+
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+ ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE));
+ ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE));
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+ ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L""));
+ ASSERT_NE(ERROR_SUCCESS,
+ key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
+
+ ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE));
+ ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"Foo"));
+ ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"Foo"));
+ ASSERT_NE(ERROR_SUCCESS,
+ key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
+}
+
+// This test requires running as an Administrator as it tests redirected
+// registry writes to HKLM\Software
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa384253.aspx
+// TODO(wfh): flaky test on Vista. See http://crbug.com/377917
+TEST_F(RegistryTest, DISABLED_Wow64RedirectedFromNative) {
+ if (!IsRedirectorPresent())
+ return;
+
+ RegKey key;
+
+ // Test redirected key access from non-redirected.
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Create(HKEY_LOCAL_MACHINE,
+ foo_software_key_.c_str(),
+ KEY_WRITE | kRedirectedViewMask));
+ ASSERT_NE(ERROR_SUCCESS,
+ key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ));
+ ASSERT_NE(ERROR_SUCCESS,
+ key.Open(HKEY_LOCAL_MACHINE,
+ foo_software_key_.c_str(),
+ KEY_READ | kNativeViewMask));
+
+ // Open the non-redirected view of the parent and try to delete the test key.
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Open(HKEY_LOCAL_MACHINE, L"Software", KEY_SET_VALUE));
+ ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Open(HKEY_LOCAL_MACHINE,
+ L"Software",
+ KEY_SET_VALUE | kNativeViewMask));
+ ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+
+ // Open the redirected view and delete the key created above.
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Open(HKEY_LOCAL_MACHINE,
+ L"Software",
+ KEY_SET_VALUE | kRedirectedViewMask));
+ ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+}
+
+// Test for the issue found in http://crbug.com/384587 where OpenKey would call
+// Close() and reset wow64_access_ flag to 0 and cause a NOTREACHED to hit on a
+// subsequent OpenKey call.
+TEST_F(RegistryTest, SameWowFlags) {
+ RegKey key;
+
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Open(HKEY_LOCAL_MACHINE,
+ L"Software",
+ KEY_READ | KEY_WOW64_64KEY));
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.OpenKey(L"Microsoft",
+ KEY_READ | KEY_WOW64_64KEY));
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.OpenKey(L"Windows",
+ KEY_READ | KEY_WOW64_64KEY));
+}
+
+// TODO(wfh): flaky test on Vista. See http://crbug.com/377917
+TEST_F(RegistryTest, DISABLED_Wow64NativeFromRedirected) {
+ if (!IsRedirectorPresent())
+ return;
+ RegKey key;
+
+ // Test non-redirected key access from redirected.
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Create(HKEY_LOCAL_MACHINE,
+ foo_software_key_.c_str(),
+ KEY_WRITE | kNativeViewMask));
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ));
+ ASSERT_NE(ERROR_SUCCESS,
+ key.Open(HKEY_LOCAL_MACHINE,
+ foo_software_key_.c_str(),
+ KEY_READ | kRedirectedViewMask));
+
+ // Open the redirected view of the parent and try to delete the test key
+ // from the non-redirected view.
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Open(HKEY_LOCAL_MACHINE,
+ L"Software",
+ KEY_SET_VALUE | kRedirectedViewMask));
+ ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Open(HKEY_LOCAL_MACHINE,
+ L"Software",
+ KEY_SET_VALUE | kNativeViewMask));
+ ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+}
+
+TEST_F(RegistryTest, OpenSubKey) {
+ RegKey key;
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Open(HKEY_CURRENT_USER,
+ kRootKey,
+ KEY_READ | KEY_CREATE_SUB_KEY));
+
+ ASSERT_NE(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ));
+ ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"foo", KEY_READ));
+ ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+ ASSERT_EQ(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ));
+
+ std::wstring foo_key(kRootKey);
+ foo_key += L"\\Foo";
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
+
+ ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE));
+ ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"foo"));
+}
+
} // namespace
} // namespace win
diff --git a/chromium/base/win/scoped_com_initializer.h b/chromium/base/win/scoped_com_initializer.h
index 392c351cc7d..92228baa507 100644
--- a/chromium/base/win/scoped_com_initializer.h
+++ b/chromium/base/win/scoped_com_initializer.h
@@ -16,6 +16,11 @@ namespace win {
// Initializes COM in the constructor (STA or MTA), and uninitializes COM in the
// destructor.
+//
+// WARNING: This should only be used once per thread, ideally scoped to a
+// similar lifetime as the thread itself. You should not be using this in
+// random utility functions that make COM calls -- instead ensure these
+// functions are running on a COM-supporting thread!
class ScopedCOMInitializer {
public:
// Enum value provided to initialize the thread as an MTA instead of STA.
diff --git a/chromium/base/win/scoped_gdi_object.h b/chromium/base/win/scoped_gdi_object.h
index d44310a1598..57b013e2fba 100644
--- a/chromium/base/win/scoped_gdi_object.h
+++ b/chromium/base/win/scoped_gdi_object.h
@@ -60,7 +60,7 @@ class ScopedGDIObject {
// An explicit specialization for HICON because we have to call DestroyIcon()
// instead of DeleteObject() for HICON.
template<>
-void ScopedGDIObject<HICON>::Close() {
+void inline ScopedGDIObject<HICON>::Close() {
if (object_)
DestroyIcon(object_);
}
diff --git a/chromium/base/win/scoped_handle.h b/chromium/base/win/scoped_handle.h
index 0d038e010bd..a85e08d26e5 100644
--- a/chromium/base/win/scoped_handle.h
+++ b/chromium/base/win/scoped_handle.h
@@ -27,11 +27,9 @@ namespace win {
// Generic wrapper for raw handles that takes care of closing handles
// automatically. The class interface follows the style of
-// the ScopedStdioHandle class with a few additions:
+// the ScopedFILE class with one addition:
// - IsValid() method can tolerate multiple invalid handle values such as NULL
// and INVALID_HANDLE_VALUE (-1) for Win32 handles.
-// - Receive() method allows to receive a handle value from a function that
-// takes a raw handle pointer only.
template <class Traits, class Verifier>
class GenericScopedHandle {
MOVE_ONLY_TYPE_FOR_CPP_03(GenericScopedHandle, RValue)
@@ -168,7 +166,7 @@ class BASE_EXPORT VerifierTraits {
DISALLOW_IMPLICIT_CONSTRUCTORS(VerifierTraits);
};
-typedef GenericScopedHandle<HandleTraits, VerifierTraits> ScopedHandle;
+typedef GenericScopedHandle<HandleTraits, DummyVerifierTraits> ScopedHandle;
} // namespace win
} // namespace base
diff --git a/chromium/base/win/scoped_process_information_unittest.cc b/chromium/base/win/scoped_process_information_unittest.cc
index 550076ef9c6..0b720cb1a39 100644
--- a/chromium/base/win/scoped_process_information_unittest.cc
+++ b/chromium/base/win/scoped_process_information_unittest.cc
@@ -46,8 +46,7 @@ MULTIPROCESS_TEST_MAIN(ReturnNine) {
void ScopedProcessInformationTest::DoCreateProcess(
const std::string& main_id, PROCESS_INFORMATION* process_handle) {
- std::wstring cmd_line =
- this->MakeCmdLine(main_id, false).GetCommandLineString();
+ std::wstring cmd_line = MakeCmdLine(main_id).GetCommandLineString();
STARTUPINFO startup_info = {};
startup_info.cb = sizeof(startup_info);
diff --git a/chromium/base/win/shortcut.cc b/chromium/base/win/shortcut.cc
index 57a93dc6524..7dace5988d0 100644
--- a/chromium/base/win/shortcut.cc
+++ b/chromium/base/win/shortcut.cc
@@ -11,6 +11,7 @@
#include "base/file_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/win/scoped_comptr.h"
+#include "base/win/scoped_propvariant.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
@@ -172,52 +173,138 @@ bool CreateOrUpdateShortcutLink(const FilePath& shortcut_path,
return succeeded;
}
-bool ResolveShortcut(const FilePath& shortcut_path,
- FilePath* target_path,
- string16* args) {
+bool ResolveShortcutProperties(const FilePath& shortcut_path,
+ uint32 options,
+ ShortcutProperties* properties) {
+ DCHECK(options && properties);
base::ThreadRestrictions::AssertIOAllowed();
- HRESULT result;
+ if (options & ~ShortcutProperties::PROPERTIES_ALL)
+ NOTREACHED() << "Unhandled property is used.";
+
ScopedComPtr<IShellLink> i_shell_link;
// Get pointer to the IShellLink interface.
- result = i_shell_link.CreateInstance(CLSID_ShellLink, NULL,
- CLSCTX_INPROC_SERVER);
- if (FAILED(result))
+ if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL,
+ CLSCTX_INPROC_SERVER))) {
return false;
+ }
ScopedComPtr<IPersistFile> persist;
// Query IShellLink for the IPersistFile interface.
- result = persist.QueryFrom(i_shell_link);
- if (FAILED(result))
+ if (FAILED(persist.QueryFrom(i_shell_link)))
return false;
// Load the shell link.
- result = persist->Load(shortcut_path.value().c_str(), STGM_READ);
- if (FAILED(result))
+ if (FAILED(persist->Load(shortcut_path.value().c_str(), STGM_READ)))
return false;
- WCHAR temp[MAX_PATH];
- if (target_path) {
+ // Reset |properties|.
+ properties->options = 0;
+
+ wchar_t temp[MAX_PATH];
+ if (options & ShortcutProperties::PROPERTIES_TARGET) {
// Try to find the target of a shortcut.
- result = i_shell_link->Resolve(0, SLR_NO_UI | SLR_NOSEARCH);
- if (FAILED(result))
+ if (FAILED(i_shell_link->Resolve(0, SLR_NO_UI | SLR_NOSEARCH)))
return false;
+ if (FAILED(i_shell_link->GetPath(temp, MAX_PATH, NULL, SLGP_UNCPRIORITY)))
+ return false;
+ properties->set_target(FilePath(temp));
+ }
- result = i_shell_link->GetPath(temp, MAX_PATH, NULL, SLGP_UNCPRIORITY);
- if (FAILED(result))
+ if (options & ShortcutProperties::PROPERTIES_WORKING_DIR) {
+ if (FAILED(i_shell_link->GetWorkingDirectory(temp, MAX_PATH)))
return false;
+ properties->set_working_dir(FilePath(temp));
+ }
- *target_path = FilePath(temp);
+ if (options & ShortcutProperties::PROPERTIES_ARGUMENTS) {
+ if (FAILED(i_shell_link->GetArguments(temp, MAX_PATH)))
+ return false;
+ properties->set_arguments(temp);
}
- if (args) {
- result = i_shell_link->GetArguments(temp, MAX_PATH);
- if (FAILED(result))
+ if (options & ShortcutProperties::PROPERTIES_DESCRIPTION) {
+ // Note: description length constrained by MAX_PATH.
+ if (FAILED(i_shell_link->GetDescription(temp, MAX_PATH)))
return false;
+ properties->set_description(temp);
+ }
- *args = string16(temp);
+ if (options & ShortcutProperties::PROPERTIES_ICON) {
+ int temp_index;
+ if (FAILED(i_shell_link->GetIconLocation(temp, MAX_PATH, &temp_index)))
+ return false;
+ properties->set_icon(FilePath(temp), temp_index);
}
+
+ // Windows 7+ options, avoiding unnecessary work.
+ if ((options & ShortcutProperties::PROPERTIES_WIN7) &&
+ GetVersion() >= VERSION_WIN7) {
+ ScopedComPtr<IPropertyStore> property_store;
+ if (FAILED(property_store.QueryFrom(i_shell_link)))
+ return false;
+
+ if (options & ShortcutProperties::PROPERTIES_APP_ID) {
+ ScopedPropVariant pv_app_id;
+ if (property_store->GetValue(PKEY_AppUserModel_ID,
+ pv_app_id.Receive()) != S_OK) {
+ return false;
+ }
+ switch (pv_app_id.get().vt) {
+ case VT_EMPTY:
+ properties->set_app_id(L"");
+ break;
+ case VT_LPWSTR:
+ properties->set_app_id(pv_app_id.get().pwszVal);
+ break;
+ default:
+ NOTREACHED() << "Unexpected variant type: " << pv_app_id.get().vt;
+ return false;
+ }
+ }
+
+ if (options & ShortcutProperties::PROPERTIES_DUAL_MODE) {
+ ScopedPropVariant pv_dual_mode;
+ if (property_store->GetValue(PKEY_AppUserModel_IsDualMode,
+ pv_dual_mode.Receive()) != S_OK) {
+ return false;
+ }
+ switch (pv_dual_mode.get().vt) {
+ case VT_EMPTY:
+ properties->set_dual_mode(false);
+ break;
+ case VT_BOOL:
+ properties->set_dual_mode(pv_dual_mode.get().boolVal == VARIANT_TRUE);
+ break;
+ default:
+ NOTREACHED() << "Unexpected variant type: " << pv_dual_mode.get().vt;
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool ResolveShortcut(const FilePath& shortcut_path,
+ FilePath* target_path,
+ string16* args) {
+ uint32 options = 0;
+ if (target_path)
+ options |= ShortcutProperties::PROPERTIES_TARGET;
+ if (args)
+ options |= ShortcutProperties::PROPERTIES_ARGUMENTS;
+ DCHECK(options);
+
+ ShortcutProperties properties;
+ if (!ResolveShortcutProperties(shortcut_path, options, &properties))
+ return false;
+
+ if (target_path)
+ *target_path = properties.target;
+ if (args)
+ *args = properties.arguments;
return true;
}
@@ -237,7 +324,7 @@ bool TaskbarUnpinShortcutLink(const wchar_t* shortcut) {
base::ThreadRestrictions::AssertIOAllowed();
// "Unpin from taskbar" is only supported after Win7.
- if (base::win::GetVersion() < base::win::VERSION_WIN7)
+ if (GetVersion() < VERSION_WIN7)
return false;
int result = reinterpret_cast<int>(ShellExecute(NULL, L"taskbarunpin",
diff --git a/chromium/base/win/shortcut.h b/chromium/base/win/shortcut.h
index 0f5fb0f686b..13940ed52c4 100644
--- a/chromium/base/win/shortcut.h
+++ b/chromium/base/win/shortcut.h
@@ -31,13 +31,21 @@ enum ShortcutOperation {
// setting |options| as desired.
struct ShortcutProperties {
enum IndividualProperties {
- PROPERTIES_TARGET = 1 << 0,
- PROPERTIES_WORKING_DIR = 1 << 1,
- PROPERTIES_ARGUMENTS = 1 << 2,
- PROPERTIES_DESCRIPTION = 1 << 3,
- PROPERTIES_ICON = 1 << 4,
- PROPERTIES_APP_ID = 1 << 5,
- PROPERTIES_DUAL_MODE = 1 << 6,
+ PROPERTIES_TARGET = 1U << 0,
+ PROPERTIES_WORKING_DIR = 1U << 1,
+ PROPERTIES_ARGUMENTS = 1U << 2,
+ PROPERTIES_DESCRIPTION = 1U << 3,
+ PROPERTIES_ICON = 1U << 4,
+ PROPERTIES_APP_ID = 1U << 5,
+ PROPERTIES_DUAL_MODE = 1U << 6,
+ // Be sure to update the values below when adding a new property.
+ PROPERTIES_BASIC = PROPERTIES_TARGET |
+ PROPERTIES_WORKING_DIR |
+ PROPERTIES_ARGUMENTS |
+ PROPERTIES_DESCRIPTION |
+ PROPERTIES_ICON,
+ PROPERTIES_WIN7 = PROPERTIES_APP_ID | PROPERTIES_DUAL_MODE,
+ PROPERTIES_ALL = PROPERTIES_BASIC | PROPERTIES_WIN7
};
ShortcutProperties() : icon_index(-1), dual_mode(false), options(0U) {}
@@ -117,14 +125,25 @@ BASE_EXPORT bool CreateOrUpdateShortcutLink(
const ShortcutProperties& properties,
ShortcutOperation operation);
-// Resolve Windows shortcut (.LNK file)
-// This methods tries to resolve a shortcut .LNK file. The path of the shortcut
-// to resolve is in |shortcut_path|. If |target_path| is not NULL, the target
-// will be resolved and placed in |target_path|. If |args| is not NULL, the
-// arguments will be retrieved and placed in |args|. The function returns true
-// if all requested fields are found successfully.
-// Callers can safely use the same variable for both |shortcut_path| and
-// |target_path|.
+// Resolves Windows shortcut (.LNK file)
+// This methods tries to resolve selected properties of a shortcut .LNK file.
+// The path of the shortcut to resolve is in |shortcut_path|. |options| is a bit
+// field composed of ShortcutProperties::IndividualProperties, to specify which
+// properties to read. It should be non-0. The resulting data are read into
+// |properties|, which must not be NULL. The function returns true if all
+// requested properties are successfully read. Otherwise some reads have failed
+// and intermediate values written to |properties| should be ignored.
+BASE_EXPORT bool ResolveShortcutProperties(const FilePath& shortcut_path,
+ uint32 options,
+ ShortcutProperties* properties);
+
+// Resolves Windows shortcut (.LNK file).
+// This is a wrapper to ResolveShortcutProperties() to handle the common use
+// case of resolving target and arguments. |target_path| and |args| are
+// optional output variables that are ignored if NULL (but at least one must be
+// non-NULL). The function returns true if all requested fields are found
+// successfully. Callers can safely use the same variable for both
+// |shortcut_path| and |target_path|.
BASE_EXPORT bool ResolveShortcut(const FilePath& shortcut_path,
FilePath* target_path,
string16* args);
diff --git a/chromium/base/win/shortcut_unittest.cc b/chromium/base/win/shortcut_unittest.cc
index eaf152eb9dc..7a6f41dae92 100644
--- a/chromium/base/win/shortcut_unittest.cc
+++ b/chromium/base/win/shortcut_unittest.cc
@@ -12,6 +12,7 @@
#include "base/test/test_file_util.h"
#include "base/test/test_shortcut_win.h"
#include "base/win/scoped_com_initializer.h"
+#include "base/win/windows_version.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -33,8 +34,7 @@ class ShortcutTest : public testing::Test {
// Shortcut 1's properties
{
const FilePath target_file(temp_dir_.path().Append(L"Target 1.txt"));
- file_util::WriteFile(target_file, kFileContents,
- arraysize(kFileContents));
+ WriteFile(target_file, kFileContents, arraysize(kFileContents));
link_properties_.set_target(target_file);
link_properties_.set_working_dir(temp_dir_.path());
@@ -48,11 +48,10 @@ class ShortcutTest : public testing::Test {
// Shortcut 2's properties (all different from properties of shortcut 1).
{
const FilePath target_file_2(temp_dir_.path().Append(L"Target 2.txt"));
- file_util::WriteFile(target_file_2, kFileContents2,
- arraysize(kFileContents2));
+ WriteFile(target_file_2, kFileContents2, arraysize(kFileContents2));
FilePath icon_path_2;
- base::CreateTemporaryFileInDir(temp_dir_.path(), &icon_path_2);
+ CreateTemporaryFileInDir(temp_dir_.path(), &icon_path_2);
link_properties_2_.set_target(target_file_2);
link_properties_2_.set_working_dir(temp_dir_2_.path());
@@ -80,6 +79,56 @@ class ShortcutTest : public testing::Test {
} // namespace
+TEST_F(ShortcutTest, CreateAndResolveShortcutProperties) {
+ uint32 valid_properties = ShortcutProperties::PROPERTIES_BASIC;
+ if (GetVersion() >= VERSION_WIN7)
+ valid_properties |= ShortcutProperties::PROPERTIES_WIN7;
+
+ // Test all properties.
+ FilePath file_1(temp_dir_.path().Append(L"Link1.lnk"));
+ ASSERT_TRUE(CreateOrUpdateShortcutLink(
+ file_1, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+ ShortcutProperties properties_read_1;
+ ASSERT_TRUE(ResolveShortcutProperties(
+ file_1, ShortcutProperties::PROPERTIES_ALL, &properties_read_1));
+ EXPECT_EQ(valid_properties, properties_read_1.options);
+ ValidatePathsAreEqual(link_properties_.target, properties_read_1.target);
+ ValidatePathsAreEqual(link_properties_.working_dir,
+ properties_read_1.working_dir);
+ EXPECT_EQ(link_properties_.arguments, properties_read_1.arguments);
+ EXPECT_EQ(link_properties_.description, properties_read_1.description);
+ ValidatePathsAreEqual(link_properties_.icon, properties_read_1.icon);
+ EXPECT_EQ(link_properties_.icon_index, properties_read_1.icon_index);
+ if (GetVersion() >= VERSION_WIN7) {
+ EXPECT_EQ(link_properties_.app_id, properties_read_1.app_id);
+ EXPECT_EQ(link_properties_.dual_mode, properties_read_1.dual_mode);
+ }
+
+ // Test simple shortcut with no special properties set.
+ FilePath file_2(temp_dir_.path().Append(L"Link2.lnk"));
+ ShortcutProperties only_target_properties;
+ only_target_properties.set_target(link_properties_.target);
+ ASSERT_TRUE(CreateOrUpdateShortcutLink(
+ file_2, only_target_properties, SHORTCUT_CREATE_ALWAYS));
+
+ ShortcutProperties properties_read_2;
+ ASSERT_TRUE(ResolveShortcutProperties(
+ file_2, ShortcutProperties::PROPERTIES_ALL, &properties_read_2));
+ EXPECT_EQ(valid_properties, properties_read_2.options);
+ ValidatePathsAreEqual(only_target_properties.target,
+ properties_read_2.target);
+ ValidatePathsAreEqual(FilePath(), properties_read_2.working_dir);
+ EXPECT_EQ(L"", properties_read_2.arguments);
+ EXPECT_EQ(L"", properties_read_2.description);
+ ValidatePathsAreEqual(FilePath(), properties_read_2.icon);
+ EXPECT_EQ(0, properties_read_2.icon_index);
+ if (GetVersion() >= VERSION_WIN7) {
+ EXPECT_EQ(L"", properties_read_2.app_id);
+ EXPECT_FALSE(properties_read_2.dual_mode);
+ }
+}
+
TEST_F(ShortcutTest, CreateAndResolveShortcut) {
ShortcutProperties only_target_properties;
only_target_properties.set_target(link_properties_.target);
diff --git a/chromium/base/win/startup_information_unittest.cc b/chromium/base/win/startup_information_unittest.cc
index d637ebd68a1..43276c5ee34 100644
--- a/chromium/base/win/startup_information_unittest.cc
+++ b/chromium/base/win/startup_information_unittest.cc
@@ -62,7 +62,7 @@ TEST_F(StartupInformationTest, InheritStdOut) {
sizeof(events[0])));
std::wstring cmd_line =
- this->MakeCmdLine("FireInheritedEvents", false).GetCommandLineString();
+ MakeCmdLine("FireInheritedEvents").GetCommandLineString();
PROCESS_INFORMATION temp_process_info = {};
ASSERT_TRUE(::CreateProcess(NULL, const_cast<wchar_t*>(cmd_line.c_str()),
diff --git a/chromium/base/win/text_services_message_filter.cc b/chromium/base/win/text_services_message_filter.cc
deleted file mode 100644
index 7ce233d9fd4..00000000000
--- a/chromium/base/win/text_services_message_filter.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/win/text_services_message_filter.h"
-
-namespace base {
-namespace win {
-
-TextServicesMessageFilter::TextServicesMessageFilter()
- : client_id_(TF_CLIENTID_NULL),
- is_initialized_(false) {
-}
-
-TextServicesMessageFilter::~TextServicesMessageFilter() {
- if (is_initialized_)
- thread_mgr_->Deactivate();
-}
-
-bool TextServicesMessageFilter::Init() {
- if (FAILED(thread_mgr_.CreateInstance(CLSID_TF_ThreadMgr)))
- return false;
-
- if (FAILED(message_pump_.QueryFrom(thread_mgr_)))
- return false;
-
- if (FAILED(keystroke_mgr_.QueryFrom(thread_mgr_)))
- return false;
-
- if (FAILED(thread_mgr_->Activate(&client_id_)))
- return false;
-
- is_initialized_ = true;
- return is_initialized_;
-}
-
-// Wraps for ITfMessagePump::PeekMessage with win32 PeekMessage signature.
-// Obtains messages from application message queue.
-BOOL TextServicesMessageFilter::DoPeekMessage(MSG* msg,
- HWND window_handle,
- UINT msg_filter_min,
- UINT msg_filter_max,
- UINT remove_msg) {
- BOOL result = FALSE;
- if (FAILED(message_pump_->PeekMessage(msg, window_handle,
- msg_filter_min, msg_filter_max,
- remove_msg, &result))) {
- result = FALSE;
- }
-
- return result;
-}
-
-// Sends message to Text Service Manager.
-// The message will be used to input composition text.
-// Returns true if |message| was consumed by text service manager.
-bool TextServicesMessageFilter::ProcessMessage(const MSG& msg) {
- if (msg.message == WM_KEYDOWN) {
- BOOL eaten = FALSE;
- HRESULT hr = keystroke_mgr_->TestKeyDown(msg.wParam, msg.lParam, &eaten);
- if (FAILED(hr) && !eaten)
- return false;
- eaten = FALSE;
- hr = keystroke_mgr_->KeyDown(msg.wParam, msg.lParam, &eaten);
- return (SUCCEEDED(hr) && !!eaten);
- }
-
- if (msg.message == WM_KEYUP) {
- BOOL eaten = FALSE;
- HRESULT hr = keystroke_mgr_->TestKeyUp(msg.wParam, msg.lParam, &eaten);
- if (FAILED(hr) && !eaten)
- return false;
- eaten = FALSE;
- hr = keystroke_mgr_->KeyUp(msg.wParam, msg.lParam, &eaten);
- return (SUCCEEDED(hr) && !!eaten);
- }
-
- return false;
-}
-
-} // namespace win
-} // namespace base
diff --git a/chromium/base/win/text_services_message_filter.h b/chromium/base/win/text_services_message_filter.h
deleted file mode 100644
index 704c1da640b..00000000000
--- a/chromium/base/win/text_services_message_filter.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_WIN_TEXT_SERVICES_MESSAGE_FILTER_H_
-#define BASE_WIN_TEXT_SERVICES_MESSAGE_FILTER_H_
-
-#include <msctf.h>
-#include <Windows.h>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_pump_win.h"
-#include "base/win/metro.h"
-#include "base/win/scoped_comptr.h"
-
-namespace base {
-namespace win {
-
-// TextServicesMessageFilter extends MessageFilter with methods that are using
-// Text Services Framework COM component.
-class BASE_EXPORT TextServicesMessageFilter
- : public base::MessagePumpForUI::MessageFilter {
- public:
- TextServicesMessageFilter();
- virtual ~TextServicesMessageFilter();
- virtual BOOL DoPeekMessage(MSG* msg,
- HWND window_handle,
- UINT msg_filter_min,
- UINT msg_filter_max,
- UINT remove_msg) OVERRIDE;
- virtual bool ProcessMessage(const MSG& msg) OVERRIDE;
-
- bool Init();
-
- private:
- TfClientId client_id_;
- bool is_initialized_;
- base::win::ScopedComPtr<ITfThreadMgr> thread_mgr_;
- base::win::ScopedComPtr<ITfMessagePump> message_pump_;
- base::win::ScopedComPtr<ITfKeystrokeMgr> keystroke_mgr_;
-
- DISALLOW_COPY_AND_ASSIGN(TextServicesMessageFilter);
-};
-
-} // namespace win
-} // namespace base
-
-#endif // BASE_WIN_TEXT_SERVICES_MESSAGE_FILTER_H_
diff --git a/chromium/base/win/win_util.cc b/chromium/base/win/win_util.cc
index 7b85418a1ea..ee923522fc9 100644
--- a/chromium/base/win/win_util.cc
+++ b/chromium/base/win/win_util.cc
@@ -6,6 +6,7 @@
#include <aclapi.h>
#include <lm.h>
+#include <powrprof.h>
#include <shellapi.h>
#include <shlobj.h>
#include <shobjidl.h> // Must be before propkey.
@@ -221,14 +222,29 @@ void SetAbortBehaviorForCrashReporting() {
signal(SIGABRT, ForceCrashOnSigAbort);
}
-bool IsTouchEnabledDevice() {
- if (base::win::GetVersion() < base::win::VERSION_WIN7)
+bool IsTabletDevice() {
+ if (GetSystemMetrics(SM_MAXIMUMTOUCHES) == 0)
return false;
- const int kMultiTouch = NID_INTEGRATED_TOUCH | NID_MULTI_INPUT | NID_READY;
- int sm = GetSystemMetrics(SM_DIGITIZER);
- if ((sm & kMultiTouch) == kMultiTouch) {
- return true;
- }
+
+ base::win::Version version = base::win::GetVersion();
+ if (version == base::win::VERSION_XP)
+ return (GetSystemMetrics(SM_TABLETPC) != 0);
+
+ // If the device is docked, the user is treating the device as a PC.
+ if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0)
+ return false;
+
+ // PlatformRoleSlate was only added in Windows 8, but prior to Win8 it is
+ // still possible to check for a mobile power profile.
+ POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole();
+ bool mobile_power_profile = (role == PlatformRoleMobile);
+ bool slate_power_profile = false;
+ if (version >= base::win::VERSION_WIN8)
+ slate_power_profile = (role == PlatformRoleSlate);
+
+ if (mobile_power_profile || slate_power_profile)
+ return (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0);
+
return false;
}
@@ -329,41 +345,29 @@ bool DismissVirtualKeyboard() {
typedef HWND (*MetroRootWindow) ();
-// As of this writing, GetMonitorInfo function seem to return wrong values
-// for rcWork.left and rcWork.top in case of split screen situation inside
-// metro mode. In order to get required values we query for core window screen
-// coordinates.
-// TODO(shrikant): Remove detour code once GetMonitorInfo is fixed for 8.1.
-BOOL GetMonitorInfoWrapper(HMONITOR monitor, MONITORINFO* mi) {
- BOOL ret = ::GetMonitorInfo(monitor, mi);
-#if !defined(USE_ASH)
- if (base::win::IsMetroProcess() &&
- base::win::GetVersion() >= base::win::VERSION_WIN8_1) {
- static MetroRootWindow root_window = NULL;
- if (!root_window) {
- HMODULE metro = base::win::GetMetroModule();
- // There are apparently instances when current process is inside metro
- // environment but metro driver dll is not loaded.
- if (!metro) {
- return ret;
- }
- root_window = reinterpret_cast<MetroRootWindow>(
- ::GetProcAddress(metro, "GetRootWindow"));
- }
- ret = ::GetWindowRect(root_window(), &(mi->rcWork));
- }
-#endif
- return ret;
-}
+enum DomainEnrollementState {UNKNOWN = -1, NOT_ENROLLED, ENROLLED};
+static volatile long int g_domain_state = UNKNOWN;
bool IsEnrolledToDomain() {
- LPWSTR domain;
- NETSETUP_JOIN_STATUS join_status;
- if(::NetGetJoinInformation(NULL, &domain, &join_status) != NERR_Success)
- return false;
- ::NetApiBufferFree(domain);
+ // Doesn't make any sense to retry inside a user session because joining a
+ // domain will only kick in on a restart.
+ if (g_domain_state == UNKNOWN) {
+ LPWSTR domain;
+ NETSETUP_JOIN_STATUS join_status;
+ if(::NetGetJoinInformation(NULL, &domain, &join_status) != NERR_Success)
+ return false;
+ ::NetApiBufferFree(domain);
+ ::InterlockedCompareExchange(&g_domain_state,
+ join_status == ::NetSetupDomainName ?
+ ENROLLED : NOT_ENROLLED,
+ UNKNOWN);
+ }
+
+ return g_domain_state == ENROLLED;
+}
- return join_status == ::NetSetupDomainName;
+void SetDomainStateForTesting(bool state) {
+ g_domain_state = state ? ENROLLED : NOT_ENROLLED;
}
} // namespace win
diff --git a/chromium/base/win/win_util.h b/chromium/base/win/win_util.h
index eebb64ac8ef..573c4c72506 100644
--- a/chromium/base/win/win_util.h
+++ b/chromium/base/win/win_util.h
@@ -107,9 +107,10 @@ BASE_EXPORT bool ShouldCrashOnProcessDetach();
// process is aborted.
BASE_EXPORT void SetAbortBehaviorForCrashReporting();
-// A touch enabled device by this definition is something that has
-// integrated multi-touch ready to use and has Windows version > Windows7.
-BASE_EXPORT bool IsTouchEnabledDevice();
+// A tablet is a device that is touch enabled and also is being used
+// "like a tablet". This is used primarily for metrics in order to gain some
+// insight into how users use Chrome.
+BASE_EXPORT bool IsTabletDevice();
// Get the size of a struct up to and including the specified member.
// This is necessary to set compatible struct sizes for different versions
@@ -126,13 +127,13 @@ BASE_EXPORT bool DisplayVirtualKeyboard();
// above. Returns true on success.
BASE_EXPORT bool DismissVirtualKeyboard();
-// Returns monitor info after correcting rcWorkArea based on metro version.
-// see bug #247430 for more details.
-BASE_EXPORT BOOL GetMonitorInfoWrapper(HMONITOR monitor, MONITORINFO* mi);
-
// Returns true if the machine is enrolled to a domain.
BASE_EXPORT bool IsEnrolledToDomain();
+// Used by tests to mock any wanted state. Call with |state| set to true to
+// simulate being in a domain and false otherwise.
+BASE_EXPORT void SetDomainStateForTesting(bool state);
+
} // namespace win
} // namespace base