summaryrefslogtreecommitdiffstats
path: root/remoting/base
diff options
context:
space:
mode:
authorwez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-28 09:06:09 +0000
committerwez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-28 09:06:09 +0000
commit6d64642d4e1000f2d21f290aebee952cc61c6375 (patch)
treeb3323b629cfa9a646171118438dda49e789643d2 /remoting/base
parenteeaa7c2ae03465818725e7509ec192c0a6b1c279 (diff)
downloadchromium_src-6d64642d4e1000f2d21f290aebee952cc61c6375.zip
chromium_src-6d64642d4e1000f2d21f290aebee952cc61c6375.tar.gz
chromium_src-6d64642d4e1000f2d21f290aebee952cc61c6375.tar.bz2
Add COM initialization support to AutoThread.
This CL adds SetComInitType(), which can be used to configure an AutoThread for a single- or multi-threaded COM apartment before calling Start(), and a creator function providing equivalent capability. This is a re-land of crrev.com/11348087. BUG=145856 TBR=alexeypa Review URL: https://chromiumcodereview.appspot.com/11413193 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@169886 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.cc86
3 files changed, 169 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..25bdd03 100644
--- a/remoting/base/auto_thread_unittest.cc
+++ b/remoting/base/auto_thread_unittest.cc
@@ -3,10 +3,17 @@
// found in the LICENSE file.
#include "base/bind.h"
+#include "base/file_path.h"
#include "base/memory/ref_counted.h"
+#include "base/scoped_native_library.h"
#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 +29,30 @@ void PostSetFlagTask(
task_runner->PostTask(FROM_HERE, base::Bind(&SetFlagTask, success));
}
+#if defined(OS_WIN)
+void CheckComAptTypeTask(APTTYPE* apt_type_out, HRESULT* hresult) {
+ typedef HRESULT (WINAPI * CoGetApartmentTypeFunc)
+ (APTTYPE*, APTTYPEQUALIFIER*);
+
+ // CoGetApartmentType requires Windows 7 or above.
+ if (base::win::GetVersion() < base::win::VERSION_WIN7) {
+ *hresult = E_NOTIMPL;
+ return;
+ }
+
+ // Dynamic link to the API so the same test binary can run on older systems.
+ base::ScopedNativeLibrary com_library(FilePath(L"ole32.dll"));
+ ASSERT_TRUE(com_library.is_valid());
+ CoGetApartmentTypeFunc co_get_apartment_type =
+ static_cast<CoGetApartmentTypeFunc>(
+ com_library.GetFunctionPointer("CoGetApartmentType"));
+ ASSERT_TRUE(co_get_apartment_type != NULL);
+
+ APTTYPEQUALIFIER apt_type_qualifier;
+ *hresult = (*co_get_apartment_type)(apt_type_out, &apt_type_qualifier);
+}
+#endif
+
} // namespace
namespace remoting {
@@ -59,7 +90,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 +142,58 @@ TEST_F(AutoThreadTest, ThreadDependency) {
EXPECT_TRUE(success);
}
+#if defined(OS_WIN)
+TEST_F(AutoThreadTest, ThreadWithComMta) {
+ 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();
+
+ // CoGetApartmentType requires Windows 7 or above.
+ if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
+ EXPECT_EQ(S_OK, hresult);
+ EXPECT_EQ(APTTYPE_MTA, apt_type);
+ } else {
+ EXPECT_EQ(E_NOTIMPL, hresult);
+ }
+}
+
+TEST_F(AutoThreadTest, ThreadWithComSta) {
+ 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();
+
+ // CoGetApartmentType requires Windows 7 or above.
+ if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
+ 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);
+ } else {
+ EXPECT_EQ(E_NOTIMPL, hresult);
+ }
+}
+#endif // defined(OS_WIN)
+
} // namespace remoting