summaryrefslogtreecommitdiffstats
path: root/remoting/base
diff options
context:
space:
mode:
authorwez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-27 07:04:23 +0000
committerwez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-27 07:04:23 +0000
commit260ea4588f809ee17befaf110ba7be1cb5709869 (patch)
tree08a93bd58dbc37a05e8fb01d3b97de94b4bdd450 /remoting/base
parentb501d50a59dc5cb9863524cb545174e7e761099c (diff)
downloadchromium_src-260ea4588f809ee17befaf110ba7be1cb5709869.zip
chromium_src-260ea4588f809ee17befaf110ba7be1cb5709869.tar.gz
chromium_src-260ea4588f809ee17befaf110ba7be1cb5709869.tar.bz2
Add AutoThread types for Windows that initialize COM.
This CL adds AutoThread types that create a UI MessageLoop on the thread and initialize COM for single- or multi-threaded used. BUG=145856 Review URL: https://chromiumcodereview.appspot.com/11348087 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@169595 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/base')
-rw-r--r--remoting/base/auto_thread.cc69
-rw-r--r--remoting/base/auto_thread.h25
-rw-r--r--remoting/base/auto_thread_unittest.cc65
3 files changed, 148 insertions, 11 deletions
diff --git a/remoting/base/auto_thread.cc b/remoting/base/auto_thread.cc
index 324ccc3..9f51378 100644
--- a/remoting/base/auto_thread.cc
+++ b/remoting/base/auto_thread.cc
@@ -12,11 +12,34 @@
#include "base/synchronization/waitable_event.h"
#include "remoting/base/auto_thread_task_runner.h"
+#if defined(OS_WIN)
+#include "base/win/scoped_com_initializer.h"
+#endif
+
namespace remoting {
+namespace {
+
+#if defined(OS_WIN)
+scoped_ptr<base::win::ScopedCOMInitializer> CreateComInitializer(
+ AutoThread::ComInitType type) {
+ scoped_ptr<base::win::ScopedCOMInitializer> initializer;
+ if (type == AutoThread::COM_INIT_MTA) {
+ initializer.reset(new base::win::ScopedCOMInitializer(
+ base::win::ScopedCOMInitializer::kMTA));
+ } else if (type == AutoThread::COM_INIT_STA) {
+ initializer.reset(new base::win::ScopedCOMInitializer());
+ }
+ return initializer.Pass();
+}
+#endif
+
+}
+
// Used to pass data to ThreadMain. This structure is allocated on the stack
// from within StartWithType.
struct AutoThread::StartupData {
+ // Fields describing the desired thread behaviour.
MessageLoop::Type loop_type;
// Used to receive the AutoThreadTaskRunner for the thread.
@@ -37,12 +60,9 @@ scoped_refptr<AutoThreadTaskRunner> AutoThread::CreateWithType(
MessageLoop::Type type) {
AutoThread* thread = new AutoThread(name, joiner);
scoped_refptr<AutoThreadTaskRunner> task_runner = thread->StartWithType(type);
- if (task_runner.get()) {
- return task_runner;
- } else {
+ if (!task_runner)
delete thread;
- return NULL;
- }
+ return task_runner;
}
// static
@@ -51,8 +71,28 @@ scoped_refptr<AutoThreadTaskRunner> AutoThread::Create(
return CreateWithType(name, joiner, MessageLoop::TYPE_DEFAULT);
}
+#if defined(OS_WIN)
+// static
+scoped_refptr<AutoThreadTaskRunner> AutoThread::CreateWithLoopAndComInitTypes(
+ const char* name,
+ scoped_refptr<AutoThreadTaskRunner> joiner,
+ MessageLoop::Type loop_type,
+ ComInitType com_init_type) {
+ AutoThread* thread = new AutoThread(name, joiner);
+ thread->SetComInitType(com_init_type);
+ scoped_refptr<AutoThreadTaskRunner> task_runner =
+ thread->StartWithType(loop_type);
+ if (!task_runner)
+ delete thread;
+ return task_runner;
+}
+#endif
+
AutoThread::AutoThread(const char* name)
: startup_data_(NULL),
+#if defined(OS_WIN)
+ com_init_type_(COM_INIT_NONE),
+#endif
thread_(0),
name_(name),
was_quit_properly_(false) {
@@ -60,6 +100,9 @@ AutoThread::AutoThread(const char* name)
AutoThread::AutoThread(const char* name, AutoThreadTaskRunner* joiner)
: startup_data_(NULL),
+#if defined(OS_WIN)
+ com_init_type_(COM_INIT_NONE),
+#endif
thread_(0),
name_(name),
was_quit_properly_(false),
@@ -78,6 +121,9 @@ AutoThread::~AutoThread() {
scoped_refptr<AutoThreadTaskRunner>
AutoThread::StartWithType(MessageLoop::Type type) {
DCHECK(!thread_);
+#if defined(OS_WIN)
+ DCHECK(com_init_type_ != COM_INIT_STA || type == MessageLoop::TYPE_UI);
+#endif
StartupData startup_data(type);
startup_data_ = &startup_data;
@@ -103,9 +149,12 @@ AutoThread::StartWithType(MessageLoop::Type type) {
return startup_data.task_runner;
}
-scoped_refptr<AutoThreadTaskRunner> AutoThread::Start() {
- return StartWithType(MessageLoop::TYPE_DEFAULT);
+#if defined(OS_WIN)
+void AutoThread::SetComInitType(ComInitType com_init_type) {
+ DCHECK_EQ(com_init_type_, COM_INIT_NONE);
+ com_init_type_ = com_init_type;
}
+#endif
void AutoThread::QuitThread(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
@@ -150,6 +199,12 @@ void AutoThread::ThreadMain() {
// startup_data_ can't be touched anymore since the starting thread is now
// unlocked.
+#if defined(OS_WIN)
+ // Initialize COM on the thread, if requested.
+ scoped_ptr<base::win::ScopedCOMInitializer> com_initializer(
+ CreateComInitializer(com_init_type_));
+#endif
+
message_loop.Run();
// Assert that MessageLoop::Quit was called by AutoThread::QuitThread.
diff --git a/remoting/base/auto_thread.h b/remoting/base/auto_thread.h
index 4a34976..6242839 100644
--- a/remoting/base/auto_thread.h
+++ b/remoting/base/auto_thread.h
@@ -40,13 +40,24 @@ class AutoThread : base::PlatformThread::Delegate {
const char* name,
scoped_refptr<AutoThreadTaskRunner> joiner);
+#if defined(OS_WIN)
+ // Create an AutoThread initialized for COM. |com_init_type| specifies the
+ // type of COM apartment to initialize.
+ enum ComInitType { COM_INIT_NONE, COM_INIT_STA, COM_INIT_MTA };
+ static scoped_refptr<AutoThreadTaskRunner> CreateWithLoopAndComInitTypes(
+ const char* name,
+ scoped_refptr<AutoThreadTaskRunner> joiner,
+ MessageLoop::Type loop_type,
+ ComInitType com_init_type);
+#endif
+
// Construct the AutoThread. |name| identifies the thread for debugging.
explicit AutoThread(const char* name);
// Waits for the thread to exit, and then destroys it.
virtual ~AutoThread();
- // Starts a the thread, running the specified type of MessageLoop. Returns
+ // Starts the thread, running the specified type of MessageLoop. Returns
// an AutoThreadTaskRunner through which tasks may be posted to the thread
// if successful, or NULL on failure.
//
@@ -58,8 +69,11 @@ class AutoThread : base::PlatformThread::Delegate {
// thread will exit when no references to the TaskRunner remain.
scoped_refptr<AutoThreadTaskRunner> StartWithType(MessageLoop::Type type);
- // Shorthand for StartWithType(MessageLoop::TYPE_DEFAULT).
- scoped_refptr<AutoThreadTaskRunner> Start();
+#if defined(OS_WIN)
+ // Configures the thread to initialize the specified COM apartment type.
+ // SetComInitType() must be called before Start().
+ void SetComInitType(ComInitType com_init_type);
+#endif
private:
AutoThread(const char* name, AutoThreadTaskRunner* joiner);
@@ -74,6 +88,11 @@ class AutoThread : base::PlatformThread::Delegate {
struct StartupData;
StartupData* startup_data_;
+#if defined(OS_WIN)
+ // Specifies which kind of COM apartment to initialize, if any.
+ ComInitType com_init_type_;
+#endif
+
// The thread's handle.
base::PlatformThreadHandle thread_;
diff --git a/remoting/base/auto_thread_unittest.cc b/remoting/base/auto_thread_unittest.cc
index 65f4aa5..35dd3a5 100644
--- a/remoting/base/auto_thread_unittest.cc
+++ b/remoting/base/auto_thread_unittest.cc
@@ -7,6 +7,11 @@
#include "remoting/base/auto_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_WIN)
+#include <objbase.h>
+#include "base/win/windows_version.h"
+#endif
+
namespace {
const char kThreadName[] = "Test thread";
@@ -22,6 +27,13 @@ void PostSetFlagTask(
task_runner->PostTask(FROM_HERE, base::Bind(&SetFlagTask, success));
}
+#if defined(OS_WIN)
+void CheckComAptTypeTask(APTTYPE* apt_type_out, HRESULT* hresult) {
+ APTTYPEQUALIFIER apt_type_qualifier;
+ *hresult = CoGetApartmentType(apt_type_out, &apt_type_qualifier);
+}
+#endif
+
} // namespace
namespace remoting {
@@ -59,7 +71,6 @@ class AutoThreadTest : public testing::Test {
message_loop_.PostTask(FROM_HERE, MessageLoop::QuitClosure());
}
-
MessageLoop message_loop_;
bool message_loop_quit_correctly_;
scoped_refptr<AutoThreadTaskRunner> main_task_runner_;
@@ -112,4 +123,56 @@ TEST_F(AutoThreadTest, ThreadDependency) {
EXPECT_TRUE(success);
}
+#if defined(OS_WIN)
+TEST_F(AutoThreadTest, ThreadWithComMta) {
+ // CoGetApartmentType requires Windows 7 or above.
+ if (base::win::GetVersion() < base::win::VERSION_WIN7)
+ return;
+
+ scoped_refptr<base::TaskRunner> task_runner =
+ AutoThread::CreateWithLoopAndComInitTypes(
+ kThreadName, main_task_runner_, MessageLoop::TYPE_DEFAULT,
+ AutoThread::COM_INIT_MTA);
+ EXPECT_TRUE(task_runner.get());
+
+ // Post a task to query the COM apartment type.
+ HRESULT hresult = E_FAIL;
+ APTTYPE apt_type = APTTYPE_NA;
+ task_runner->PostTask(FROM_HERE,
+ base::Bind(&CheckComAptTypeTask, &apt_type, &hresult));
+
+ task_runner = NULL;
+ RunMessageLoop();
+
+ EXPECT_EQ(S_OK, hresult);
+ EXPECT_EQ(APTTYPE_MTA, apt_type);
+}
+
+TEST_F(AutoThreadTest, ThreadWithComSta) {
+ // CoGetApartmentType requires Windows 7 or above.
+ if (base::win::GetVersion() < base::win::VERSION_WIN7)
+ return;
+
+ scoped_refptr<base::TaskRunner> task_runner =
+ AutoThread::CreateWithLoopAndComInitTypes(
+ kThreadName, main_task_runner_, MessageLoop::TYPE_UI,
+ AutoThread::COM_INIT_STA);
+ EXPECT_TRUE(task_runner.get());
+
+ // Post a task to query the COM apartment type.
+ HRESULT hresult = E_FAIL;
+ APTTYPE apt_type = APTTYPE_NA;
+ task_runner->PostTask(FROM_HERE,
+ base::Bind(&CheckComAptTypeTask, &apt_type, &hresult));
+
+ task_runner = NULL;
+ RunMessageLoop();
+
+ EXPECT_EQ(S_OK, hresult);
+ // Whether the thread is the "main" STA apartment depends upon previous
+ // COM activity in this test process, so allow both types here.
+ EXPECT_TRUE(apt_type == APTTYPE_MAINSTA || apt_type == APTTYPE_STA);
+}
+#endif // defined(OS_WIN)
+
} // namespace remoting