Index: remoting/host/plugin/daemon_controller_win.cc |
diff --git a/remoting/host/plugin/daemon_controller_win.cc b/remoting/host/plugin/daemon_controller_win.cc |
index 7fca35d897bc0d71ddf06a45f4a26fe67720dac7..88f34173558aa2ff2d491bcabd3ae36e14140c09 100644 |
--- a/remoting/host/plugin/daemon_controller_win.cc |
+++ b/remoting/host/plugin/daemon_controller_win.cc |
@@ -14,22 +14,29 @@ |
#include "base/json/json_reader.h" |
#include "base/json/json_writer.h" |
#include "base/logging.h" |
+#include "base/synchronization/lock.h" |
#include "base/threading/thread.h" |
#include "base/utf_string_conversions.h" |
#include "base/values.h" |
+#include "base/win/scoped_bstr.h" |
+#include "base/win/scoped_comptr.h" |
#include "remoting/base/scoped_sc_handle_win.h" |
#include "remoting/host/branding.h" |
+#include "remoting/host/plugin/daemon_installer_win.h" |
// MIDL-generated declarations and definitions. |
#include "remoting/host/elevated_controller.h" |
+using base::win::ScopedBstr; |
+using base::win::ScopedComPtr; |
+ |
namespace remoting { |
namespace { |
// The COM elevation moniker for the elevated controller. |
-const char kElevationMoniker[] = "Elevation:Administrator!new:" |
- "{430a9403-8176-4733-afdc-0b325a8fda84}"; |
+const char kDaemonControllerElevationMoniker[] = "Elevation:Administrator!new:" |
+ "ChromotingElevatedController.ElevatedController"; |
// Name of the Daemon Controller's worker thread. |
const char kDaemonControllerThreadName[] = "Daemon Controller thread"; |
@@ -50,7 +57,7 @@ class ComThread : public base::Thread { |
virtual void Init() OVERRIDE; |
virtual void CleanUp() OVERRIDE; |
- IDaemonControl* control_; |
+ ScopedComPtr<IDaemonControl> control_; |
DISALLOW_COPY_AND_ASSIGN(ComThread); |
}; |
@@ -76,12 +83,18 @@ class DaemonControllerWin : public remoting::DaemonController { |
// Converts HRESULT to the AsyncResult. |
static AsyncResult HResultToAsyncResult(HRESULT hr); |
+ // Procedes with the daemon configuration if the installation succeeded, |
+ // otherwise reports the error. |
+ void OnInstallationComplete(HRESULT result); |
+ |
// Opens the Chromoting service returning its handle in |service_out|. |
DWORD OpenService(ScopedScHandle* service_out); |
// The functions that actually do the work. They should be called in |
// the context of |worker_thread_|; |
void DoGetConfig(const GetConfigCallback& callback); |
+ void DoInstall(scoped_ptr<base::DictionaryValue> config, |
+ const CompletionCallback& done_callback); |
void DoSetConfigAndStart(scoped_ptr<base::DictionaryValue> config, |
const CompletionCallback& done_callback); |
void DoStop(const CompletionCallback& done_callback); |
@@ -89,6 +102,13 @@ class DaemonControllerWin : public remoting::DaemonController { |
// The worker thread used for servicing long running operations. |
ComThread worker_thread_; |
+ // The lock protecting the data members below. |
+ base::Lock lock_; |
+ |
+ scoped_ptr<base::DictionaryValue> config_; |
+ CompletionCallback done_callback_; |
+ scoped_ptr<DaemonInstallerWin> installer_; |
+ |
DISALLOW_COPY_AND_ASSIGN(DaemonControllerWin); |
}; |
@@ -100,8 +120,7 @@ void ComThread::Init() { |
} |
void ComThread::CleanUp() { |
- if (control_ != NULL) |
- control_->Release(); |
+ control_.Release(); |
CoUninitialize(); |
} |
@@ -109,25 +128,24 @@ HRESULT ComThread::ActivateElevatedController( |
IDaemonControl** control_out) { |
// Chache the instance of Elevated Controller to prevent a UAC prompt on every |
// operation. |
- if (control_ == NULL) { |
+ if (control_.get() == NULL) { |
BIND_OPTS3 bind_options; |
memset(&bind_options, 0, sizeof(bind_options)); |
bind_options.cbStruct = sizeof(bind_options); |
bind_options.hwnd = NULL; |
bind_options.dwClassContext = CLSCTX_LOCAL_SERVER; |
- HRESULT hr = ::CoGetObject(ASCIIToUTF16(kElevationMoniker).c_str(), |
- &bind_options, |
- IID_IDaemonControl, |
- reinterpret_cast<void**>(&control_)); |
+ HRESULT hr = ::CoGetObject( |
+ ASCIIToUTF16(kDaemonControllerElevationMoniker).c_str(), |
+ &bind_options, |
+ IID_IDaemonControl, |
+ control_.ReceiveVoid()); |
if (FAILED(hr)) { |
- LOG(ERROR) << "Failed to create the elevated controller (error: 0x" |
- << std::hex << hr << std::dec << ")."; |
return hr; |
} |
} |
- *control_out = control_; |
+ *control_out = control_.get(); |
return S_OK; |
} |
@@ -168,7 +186,7 @@ remoting::DaemonController::State DaemonControllerWin::GetState() { |
break; |
} |
case ERROR_SERVICE_DOES_NOT_EXIST: |
- return STATE_NOT_IMPLEMENTED; |
+ return STATE_NOT_INSTALLED; |
default: |
return STATE_UNKNOWN; |
} |
@@ -187,7 +205,7 @@ void DaemonControllerWin::SetConfigAndStart( |
worker_thread_.message_loop_proxy()->PostTask( |
FROM_HERE, base::Bind( |
- &DaemonControllerWin::DoSetConfigAndStart, base::Unretained(this), |
+ &DaemonControllerWin::DoInstall, base::Unretained(this), |
base::Passed(&config), done_callback)); |
} |
@@ -241,6 +259,26 @@ DaemonController::AsyncResult DaemonControllerWin::HResultToAsyncResult( |
return FAILED(hr) ? RESULT_FAILED : RESULT_OK; |
} |
+void DaemonControllerWin::OnInstallationComplete(HRESULT result) { |
+ scoped_ptr<base::DictionaryValue> config; |
+ CompletionCallback done_callback; |
+ |
+ { |
+ base::AutoLock lock(lock_); |
+ installer_.reset(); |
+ std::swap(done_callback, done_callback_); |
+ std::swap(config, config_); |
+ } |
+ |
+ if (SUCCEEDED(result)) { |
+ DoSetConfigAndStart(config.Pass(), done_callback); |
+ } else { |
+ LOG(ERROR) << "Failed to install the Chromoting Host " |
+ << "(error: 0x" << std::hex << result << std::dec << ")."; |
+ done_callback.Run(HResultToAsyncResult(result)); |
+ } |
+} |
+ |
DWORD DaemonControllerWin::OpenService(ScopedScHandle* service_out) { |
// Open the service and query its current state. |
ScopedScHandle scmanager( |
@@ -278,16 +316,14 @@ void DaemonControllerWin::DoGetConfig(const GetConfigCallback& callback) { |
} |
// Get the host configuration. |
- BSTR host_config = NULL; |
- hr = control->GetConfig(&host_config); |
+ ScopedBstr host_config; |
+ hr = control->GetConfig(host_config.Receive()); |
if (FAILED(hr)) { |
callback.Run(scoped_ptr<base::DictionaryValue>()); |
return; |
} |
- string16 file_content(static_cast<char16*>(host_config), |
- ::SysStringLen(host_config)); |
- SysFreeString(host_config); |
+ string16 file_content(static_cast<BSTR>(host_config), host_config.Length()); |
// Parse the string into a dictionary. |
scoped_ptr<base::Value> config( |
@@ -303,6 +339,41 @@ void DaemonControllerWin::DoGetConfig(const GetConfigCallback& callback) { |
callback.Run(scoped_ptr<base::DictionaryValue>(dictionary)); |
} |
+void DaemonControllerWin::DoInstall(scoped_ptr<base::DictionaryValue> config, |
+ const CompletionCallback& done_callback) { |
+ IDaemonControl* control = NULL; |
+ HRESULT hr = worker_thread_.ActivateElevatedController(&control); |
+ |
+ // Just configure and start the Daemon Controller if it is installed already. |
+ if (SUCCEEDED(hr)) { |
+ DoSetConfigAndStart(config.Pass(), done_callback); |
+ return; |
+ } |
+ |
+ // Otherwise, install it if it's COM registration entry is missing. |
+ if (hr == CO_E_CLASSSTRING) { |
+ base::AutoLock lock(lock_); |
+ DCHECK(!config_.get()); |
+ DCHECK(!installer_.get()); |
+ |
+ hr = DaemonInstallerWin::Create(&installer_); |
+ if (SUCCEEDED(hr)) { |
+ config_ = config.Pass(); |
+ done_callback_ = done_callback; |
+ } |
+ } |
+ |
+ // Run the installer or report the error if any. |
+ if (SUCCEEDED(hr)) { |
+ installer_->Install(base::Bind(&DaemonControllerWin::OnInstallationComplete, |
+ base::Unretained(this))); |
+ } else { |
+ LOG(ERROR) << "Failed to initiate the Chromoting Host installation " |
+ << "(error: 0x" << std::hex << hr << std::dec << ")."; |
+ done_callback.Run(HResultToAsyncResult(hr)); |
+ } |
+} |
+ |
void DaemonControllerWin::DoSetConfigAndStart( |
scoped_ptr<base::DictionaryValue> config, |
const CompletionCallback& done_callback) { |
@@ -317,14 +388,13 @@ void DaemonControllerWin::DoSetConfigAndStart( |
std::string file_content; |
base::JSONWriter::Write(config.get(), &file_content); |
- BSTR host_config = ::SysAllocString(UTF8ToUTF16(file_content).c_str()); |
+ ScopedBstr host_config(UTF8ToUTF16(file_content).c_str()); |
if (host_config == NULL) { |
done_callback.Run(HResultToAsyncResult(E_OUTOFMEMORY)); |
return; |
} |
hr = control->SetConfig(host_config); |
- ::SysFreeString(host_config); |
if (FAILED(hr)) { |
done_callback.Run(HResultToAsyncResult(hr)); |
return; |