diff options
author | wez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-27 07:04:23 +0000 |
---|---|---|
committer | wez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-27 07:04:23 +0000 |
commit | 260ea4588f809ee17befaf110ba7be1cb5709869 (patch) | |
tree | 08a93bd58dbc37a05e8fb01d3b97de94b4bdd450 /remoting/base | |
parent | b501d50a59dc5cb9863524cb545174e7e761099c (diff) | |
download | chromium_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.cc | 69 | ||||
-rw-r--r-- | remoting/base/auto_thread.h | 25 | ||||
-rw-r--r-- | remoting/base/auto_thread_unittest.cc | 65 |
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 |