OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/host/plugin/daemon_controller.h" | 5 #include "remoting/host/plugin/daemon_controller.h" |
6 | 6 |
7 #include <objbase.h> | 7 #include <objbase.h> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" |
11 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
12 #include "base/file_path.h" | 13 #include "base/file_path.h" |
13 #include "base/file_util.h" | 14 #include "base/file_util.h" |
14 #include "base/json/json_reader.h" | 15 #include "base/json/json_reader.h" |
15 #include "base/json/json_writer.h" | 16 #include "base/json/json_writer.h" |
16 #include "base/logging.h" | 17 #include "base/logging.h" |
| 18 #include "base/string16.h" |
| 19 #include "base/stringize_macros.h" |
17 #include "base/threading/thread.h" | 20 #include "base/threading/thread.h" |
18 #include "base/utf_string_conversions.h" | 21 #include "base/utf_string_conversions.h" |
19 #include "base/values.h" | 22 #include "base/values.h" |
| 23 #include "base/win/scoped_bstr.h" |
| 24 #include "base/win/scoped_comptr.h" |
20 #include "remoting/base/scoped_sc_handle_win.h" | 25 #include "remoting/base/scoped_sc_handle_win.h" |
21 #include "remoting/host/branding.h" | 26 #include "remoting/host/branding.h" |
| 27 #include "remoting/host/plugin/daemon_installer_win.h" |
22 | 28 |
23 // MIDL-generated declarations and definitions. | 29 // MIDL-generated declarations and definitions. |
24 #include "remoting/host/elevated_controller.h" | 30 #include "remoting/host/elevated_controller.h" |
25 | 31 |
| 32 using base::win::ScopedBstr; |
| 33 using base::win::ScopedComPtr; |
| 34 |
26 namespace remoting { | 35 namespace remoting { |
27 | 36 |
28 namespace { | 37 namespace { |
29 | 38 |
30 // The COM elevation moniker for the elevated controller. | 39 // The COM elevation moniker for the elevated controller. |
31 const char kElevationMoniker[] = "Elevation:Administrator!new:" | 40 const char16 kDaemonControllerElevationMoniker[] = |
32 "{430a9403-8176-4733-afdc-0b325a8fda84}"; | 41 TO_L_STRING("Elevation:Administrator!new:") |
| 42 TO_L_STRING("ChromotingElevatedController.ElevatedController"); |
33 | 43 |
34 // Name of the Daemon Controller's worker thread. | 44 // Name of the Daemon Controller's worker thread. |
35 const char kDaemonControllerThreadName[] = "Daemon Controller thread"; | 45 const char kDaemonControllerThreadName[] = "Daemon Controller thread"; |
36 | 46 |
37 // A base::Thread implementation that initializes COM on the new thread. | 47 // A base::Thread implementation that initializes COM on the new thread. |
38 class ComThread : public base::Thread { | 48 class ComThread : public base::Thread { |
39 public: | 49 public: |
40 explicit ComThread(const char* name); | 50 explicit ComThread(const char* name); |
41 | 51 |
42 // Activates an elevated instance of the controller and returns the pointer | 52 // Activates an elevated instance of the controller and returns the pointer |
43 // to the control interface in |control_out|. This class keeps the ownership | 53 // to the control interface in |control_out|. This class keeps the ownership |
44 // of the pointer so the caller should not call call AddRef() or Release(). | 54 // of the pointer so the caller should not call call AddRef() or Release(). |
45 HRESULT ActivateElevatedController(IDaemonControl** control_out); | 55 HRESULT ActivateElevatedController(IDaemonControl** control_out); |
46 | 56 |
47 bool Start(); | 57 bool Start(); |
48 | 58 |
49 protected: | 59 protected: |
50 virtual void Init() OVERRIDE; | 60 virtual void Init() OVERRIDE; |
51 virtual void CleanUp() OVERRIDE; | 61 virtual void CleanUp() OVERRIDE; |
52 | 62 |
53 IDaemonControl* control_; | 63 ScopedComPtr<IDaemonControl> control_; |
54 | 64 |
55 DISALLOW_COPY_AND_ASSIGN(ComThread); | 65 DISALLOW_COPY_AND_ASSIGN(ComThread); |
56 }; | 66 }; |
57 | 67 |
58 class DaemonControllerWin : public remoting::DaemonController { | 68 class DaemonControllerWin : public remoting::DaemonController { |
59 public: | 69 public: |
60 DaemonControllerWin(); | 70 DaemonControllerWin(); |
61 virtual ~DaemonControllerWin(); | 71 virtual ~DaemonControllerWin(); |
62 | 72 |
63 virtual State GetState() OVERRIDE; | 73 virtual State GetState() OVERRIDE; |
64 virtual void GetConfig(const GetConfigCallback& callback) OVERRIDE; | 74 virtual void GetConfig(const GetConfigCallback& callback) OVERRIDE; |
65 virtual void SetConfigAndStart( | 75 virtual void SetConfigAndStart( |
66 scoped_ptr<base::DictionaryValue> config, | 76 scoped_ptr<base::DictionaryValue> config, |
67 const CompletionCallback& done_callback) OVERRIDE; | 77 const CompletionCallback& done_callback) OVERRIDE; |
68 virtual void UpdateConfig(scoped_ptr<base::DictionaryValue> config, | 78 virtual void UpdateConfig(scoped_ptr<base::DictionaryValue> config, |
69 const CompletionCallback& done_callback) OVERRIDE; | 79 const CompletionCallback& done_callback) OVERRIDE; |
70 virtual void Stop(const CompletionCallback& done_callback) OVERRIDE; | 80 virtual void Stop(const CompletionCallback& done_callback) OVERRIDE; |
71 | 81 |
72 private: | 82 private: |
73 // Converts a Windows service status code to a Daemon state. | 83 // Converts a Windows service status code to a Daemon state. |
74 static State ConvertToDaemonState(DWORD service_state); | 84 static State ConvertToDaemonState(DWORD service_state); |
75 | 85 |
76 // Converts HRESULT to the AsyncResult. | 86 // Converts HRESULT to the AsyncResult. |
77 static AsyncResult HResultToAsyncResult(HRESULT hr); | 87 static AsyncResult HResultToAsyncResult(HRESULT hr); |
78 | 88 |
| 89 // Procedes with the daemon configuration if the installation succeeded, |
| 90 // otherwise reports the error. |
| 91 void OnInstallationComplete(scoped_ptr<base::DictionaryValue> config, |
| 92 const CompletionCallback& done_callback, |
| 93 HRESULT result); |
| 94 |
79 // Opens the Chromoting service returning its handle in |service_out|. | 95 // Opens the Chromoting service returning its handle in |service_out|. |
80 DWORD OpenService(ScopedScHandle* service_out); | 96 DWORD OpenService(ScopedScHandle* service_out); |
81 | 97 |
82 // The functions that actually do the work. They should be called in | 98 // The functions that actually do the work. They should be called in |
83 // the context of |worker_thread_|; | 99 // the context of |worker_thread_|; |
84 void DoGetConfig(const GetConfigCallback& callback); | 100 void DoGetConfig(const GetConfigCallback& callback); |
| 101 void DoInstallAsNeededAndStart(scoped_ptr<base::DictionaryValue> config, |
| 102 const CompletionCallback& done_callback); |
85 void DoSetConfigAndStart(scoped_ptr<base::DictionaryValue> config, | 103 void DoSetConfigAndStart(scoped_ptr<base::DictionaryValue> config, |
86 const CompletionCallback& done_callback); | 104 const CompletionCallback& done_callback); |
87 void DoStop(const CompletionCallback& done_callback); | 105 void DoStop(const CompletionCallback& done_callback); |
88 | 106 |
89 // The worker thread used for servicing long running operations. | 107 // The worker thread used for servicing long running operations. |
90 ComThread worker_thread_; | 108 ComThread worker_thread_; |
91 | 109 |
| 110 scoped_ptr<DaemonInstallerWin> installer_; |
| 111 |
92 DISALLOW_COPY_AND_ASSIGN(DaemonControllerWin); | 112 DISALLOW_COPY_AND_ASSIGN(DaemonControllerWin); |
93 }; | 113 }; |
94 | 114 |
95 ComThread::ComThread(const char* name) : base::Thread(name), control_(NULL) { | 115 ComThread::ComThread(const char* name) : base::Thread(name), control_(NULL) { |
96 } | 116 } |
97 | 117 |
98 void ComThread::Init() { | 118 void ComThread::Init() { |
99 CoInitialize(NULL); | 119 CoInitialize(NULL); |
100 } | 120 } |
101 | 121 |
102 void ComThread::CleanUp() { | 122 void ComThread::CleanUp() { |
103 if (control_ != NULL) | 123 control_.Release(); |
104 control_->Release(); | |
105 CoUninitialize(); | 124 CoUninitialize(); |
106 } | 125 } |
107 | 126 |
108 HRESULT ComThread::ActivateElevatedController( | 127 HRESULT ComThread::ActivateElevatedController( |
109 IDaemonControl** control_out) { | 128 IDaemonControl** control_out) { |
110 // Chache the instance of Elevated Controller to prevent a UAC prompt on every | 129 // Chache the instance of Elevated Controller to prevent a UAC prompt on every |
111 // operation. | 130 // operation. |
112 if (control_ == NULL) { | 131 if (control_.get() == NULL) { |
113 BIND_OPTS3 bind_options; | 132 BIND_OPTS3 bind_options; |
114 memset(&bind_options, 0, sizeof(bind_options)); | 133 memset(&bind_options, 0, sizeof(bind_options)); |
115 bind_options.cbStruct = sizeof(bind_options); | 134 bind_options.cbStruct = sizeof(bind_options); |
116 bind_options.hwnd = NULL; | 135 bind_options.hwnd = NULL; |
117 bind_options.dwClassContext = CLSCTX_LOCAL_SERVER; | 136 bind_options.dwClassContext = CLSCTX_LOCAL_SERVER; |
118 | 137 |
119 HRESULT hr = ::CoGetObject(ASCIIToUTF16(kElevationMoniker).c_str(), | 138 HRESULT hr = ::CoGetObject( |
120 &bind_options, | 139 kDaemonControllerElevationMoniker, |
121 IID_IDaemonControl, | 140 &bind_options, |
122 reinterpret_cast<void**>(&control_)); | 141 IID_IDaemonControl, |
| 142 control_.ReceiveVoid()); |
123 if (FAILED(hr)) { | 143 if (FAILED(hr)) { |
124 LOG(ERROR) << "Failed to create the elevated controller (error: 0x" | |
125 << std::hex << hr << std::dec << ")."; | |
126 return hr; | 144 return hr; |
127 } | 145 } |
128 } | 146 } |
129 | 147 |
130 *control_out = control_; | 148 *control_out = control_.get(); |
131 return S_OK; | 149 return S_OK; |
132 } | 150 } |
133 | 151 |
134 bool ComThread::Start() { | 152 bool ComThread::Start() { |
135 // N.B. The single threaded COM apartment must be run on a UI message loop. | 153 // N.B. The single threaded COM apartment must be run on a UI message loop. |
136 base::Thread::Options thread_options(MessageLoop::TYPE_UI, 0); | 154 base::Thread::Options thread_options(MessageLoop::TYPE_UI, 0); |
137 return StartWithOptions(thread_options); | 155 return StartWithOptions(thread_options); |
138 } | 156 } |
139 | 157 |
140 DaemonControllerWin::DaemonControllerWin() | 158 DaemonControllerWin::DaemonControllerWin() |
(...skipping 20 matching lines...) Expand all Loading... |
161 return ConvertToDaemonState(status.dwCurrentState); | 179 return ConvertToDaemonState(status.dwCurrentState); |
162 } else { | 180 } else { |
163 LOG_GETLASTERROR(ERROR) | 181 LOG_GETLASTERROR(ERROR) |
164 << "Failed to query the state of the '" << kWindowsServiceName | 182 << "Failed to query the state of the '" << kWindowsServiceName |
165 << "' service"; | 183 << "' service"; |
166 return STATE_UNKNOWN; | 184 return STATE_UNKNOWN; |
167 } | 185 } |
168 break; | 186 break; |
169 } | 187 } |
170 case ERROR_SERVICE_DOES_NOT_EXIST: | 188 case ERROR_SERVICE_DOES_NOT_EXIST: |
171 return STATE_NOT_IMPLEMENTED; | 189 return STATE_NOT_INSTALLED; |
172 default: | 190 default: |
173 return STATE_UNKNOWN; | 191 return STATE_UNKNOWN; |
174 } | 192 } |
175 } | 193 } |
176 | 194 |
177 void DaemonControllerWin::GetConfig(const GetConfigCallback& callback) { | 195 void DaemonControllerWin::GetConfig(const GetConfigCallback& callback) { |
178 worker_thread_.message_loop_proxy()->PostTask( | 196 worker_thread_.message_loop_proxy()->PostTask( |
179 FROM_HERE, | 197 FROM_HERE, |
180 base::Bind(&DaemonControllerWin::DoGetConfig, | 198 base::Bind(&DaemonControllerWin::DoGetConfig, |
181 base::Unretained(this), callback)); | 199 base::Unretained(this), callback)); |
182 } | 200 } |
183 | 201 |
184 void DaemonControllerWin::SetConfigAndStart( | 202 void DaemonControllerWin::SetConfigAndStart( |
185 scoped_ptr<base::DictionaryValue> config, | 203 scoped_ptr<base::DictionaryValue> config, |
186 const CompletionCallback& done_callback) { | 204 const CompletionCallback& done_callback) { |
187 | 205 |
188 worker_thread_.message_loop_proxy()->PostTask( | 206 worker_thread_.message_loop_proxy()->PostTask( |
189 FROM_HERE, base::Bind( | 207 FROM_HERE, base::Bind( |
190 &DaemonControllerWin::DoSetConfigAndStart, base::Unretained(this), | 208 &DaemonControllerWin::DoInstallAsNeededAndStart, |
191 base::Passed(&config), done_callback)); | 209 base::Unretained(this), base::Passed(&config), done_callback)); |
192 } | 210 } |
193 | 211 |
194 void DaemonControllerWin::UpdateConfig( | 212 void DaemonControllerWin::UpdateConfig( |
195 scoped_ptr<base::DictionaryValue> config, | 213 scoped_ptr<base::DictionaryValue> config, |
196 const CompletionCallback& done_callback) { | 214 const CompletionCallback& done_callback) { |
197 NOTIMPLEMENTED(); | 215 NOTIMPLEMENTED(); |
198 done_callback.Run(RESULT_FAILED); | 216 done_callback.Run(RESULT_FAILED); |
199 } | 217 } |
200 | 218 |
201 void DaemonControllerWin::Stop(const CompletionCallback& done_callback) { | 219 void DaemonControllerWin::Stop(const CompletionCallback& done_callback) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 } | 252 } |
235 | 253 |
236 // static | 254 // static |
237 DaemonController::AsyncResult DaemonControllerWin::HResultToAsyncResult( | 255 DaemonController::AsyncResult DaemonControllerWin::HResultToAsyncResult( |
238 HRESULT hr) { | 256 HRESULT hr) { |
239 // TODO(sergeyu): Report other errors to the webapp once it knows | 257 // TODO(sergeyu): Report other errors to the webapp once it knows |
240 // how to handle them. | 258 // how to handle them. |
241 return FAILED(hr) ? RESULT_FAILED : RESULT_OK; | 259 return FAILED(hr) ? RESULT_FAILED : RESULT_OK; |
242 } | 260 } |
243 | 261 |
| 262 void DaemonControllerWin::OnInstallationComplete( |
| 263 scoped_ptr<base::DictionaryValue> config, |
| 264 const CompletionCallback& done_callback, |
| 265 HRESULT result) { |
| 266 DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 267 |
| 268 if (SUCCEEDED(result)) { |
| 269 DoSetConfigAndStart(config.Pass(), done_callback); |
| 270 } else { |
| 271 LOG(ERROR) << "Failed to install the Chromoting Host " |
| 272 << "(error: 0x" << std::hex << result << std::dec << ")."; |
| 273 done_callback.Run(HResultToAsyncResult(result)); |
| 274 } |
| 275 |
| 276 DCHECK(installer_.get() != NULL); |
| 277 installer_.reset(); |
| 278 } |
| 279 |
244 DWORD DaemonControllerWin::OpenService(ScopedScHandle* service_out) { | 280 DWORD DaemonControllerWin::OpenService(ScopedScHandle* service_out) { |
245 // Open the service and query its current state. | 281 // Open the service and query its current state. |
246 ScopedScHandle scmanager( | 282 ScopedScHandle scmanager( |
247 ::OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, | 283 ::OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, |
248 SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE)); | 284 SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE)); |
249 if (!scmanager.IsValid()) { | 285 if (!scmanager.IsValid()) { |
250 DWORD error = GetLastError(); | 286 DWORD error = GetLastError(); |
251 LOG_GETLASTERROR(ERROR) | 287 LOG_GETLASTERROR(ERROR) |
252 << "Failed to connect to the service control manager"; | 288 << "Failed to connect to the service control manager"; |
253 return error; | 289 return error; |
254 } | 290 } |
255 | 291 |
256 ScopedScHandle service( | 292 ScopedScHandle service( |
257 ::OpenServiceW(scmanager, UTF8ToUTF16(kWindowsServiceName).c_str(), | 293 ::OpenServiceW(scmanager, UTF8ToUTF16(kWindowsServiceName).c_str(), |
258 SERVICE_QUERY_STATUS)); | 294 SERVICE_QUERY_STATUS)); |
259 if (!service.IsValid()) { | 295 if (!service.IsValid()) { |
260 DWORD error = GetLastError(); | 296 DWORD error = GetLastError(); |
261 if (error != ERROR_SERVICE_DOES_NOT_EXIST) { | 297 if (error != ERROR_SERVICE_DOES_NOT_EXIST) { |
262 LOG_GETLASTERROR(ERROR) | 298 LOG_GETLASTERROR(ERROR) |
263 << "Failed to open to the '" << kWindowsServiceName << "' service"; | 299 << "Failed to open to the '" << kWindowsServiceName << "' service"; |
264 } | 300 } |
265 return error; | 301 return error; |
266 } | 302 } |
267 | 303 |
268 service_out->Set(service.Take()); | 304 service_out->Set(service.Take()); |
269 return ERROR_SUCCESS; | 305 return ERROR_SUCCESS; |
270 } | 306 } |
271 | 307 |
272 void DaemonControllerWin::DoGetConfig(const GetConfigCallback& callback) { | 308 void DaemonControllerWin::DoGetConfig(const GetConfigCallback& callback) { |
| 309 DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 310 |
273 IDaemonControl* control = NULL; | 311 IDaemonControl* control = NULL; |
274 HRESULT hr = worker_thread_.ActivateElevatedController(&control); | 312 HRESULT hr = worker_thread_.ActivateElevatedController(&control); |
275 if (FAILED(hr)) { | 313 if (FAILED(hr)) { |
276 callback.Run(scoped_ptr<base::DictionaryValue>()); | 314 callback.Run(scoped_ptr<base::DictionaryValue>()); |
277 return; | 315 return; |
278 } | 316 } |
279 | 317 |
280 // Get the host configuration. | 318 // Get the host configuration. |
281 BSTR host_config = NULL; | 319 ScopedBstr host_config; |
282 hr = control->GetConfig(&host_config); | 320 hr = control->GetConfig(host_config.Receive()); |
283 if (FAILED(hr)) { | 321 if (FAILED(hr)) { |
284 callback.Run(scoped_ptr<base::DictionaryValue>()); | 322 callback.Run(scoped_ptr<base::DictionaryValue>()); |
285 return; | 323 return; |
286 } | 324 } |
287 | 325 |
288 string16 file_content(static_cast<char16*>(host_config), | 326 string16 file_content(static_cast<BSTR>(host_config), host_config.Length()); |
289 ::SysStringLen(host_config)); | |
290 SysFreeString(host_config); | |
291 | 327 |
292 // Parse the string into a dictionary. | 328 // Parse the string into a dictionary. |
293 scoped_ptr<base::Value> config( | 329 scoped_ptr<base::Value> config( |
294 base::JSONReader::Read(UTF16ToUTF8(file_content), true)); | 330 base::JSONReader::Read(UTF16ToUTF8(file_content), true)); |
295 | 331 |
296 base::DictionaryValue* dictionary; | 332 base::DictionaryValue* dictionary; |
297 if (config.get() == NULL || !config->GetAsDictionary(&dictionary)) { | 333 if (config.get() == NULL || !config->GetAsDictionary(&dictionary)) { |
298 callback.Run(scoped_ptr<base::DictionaryValue>()); | 334 callback.Run(scoped_ptr<base::DictionaryValue>()); |
299 return; | 335 return; |
300 } | 336 } |
301 | 337 |
302 config.release(); | 338 config.release(); |
303 callback.Run(scoped_ptr<base::DictionaryValue>(dictionary)); | 339 callback.Run(scoped_ptr<base::DictionaryValue>(dictionary)); |
304 } | 340 } |
305 | 341 |
| 342 void DaemonControllerWin::DoInstallAsNeededAndStart( |
| 343 scoped_ptr<base::DictionaryValue> config, |
| 344 const CompletionCallback& done_callback) { |
| 345 DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 346 |
| 347 IDaemonControl* control = NULL; |
| 348 HRESULT hr = worker_thread_.ActivateElevatedController(&control); |
| 349 |
| 350 // Just configure and start the Daemon Controller if it is installed already. |
| 351 if (SUCCEEDED(hr)) { |
| 352 DoSetConfigAndStart(config.Pass(), done_callback); |
| 353 return; |
| 354 } |
| 355 |
| 356 // Otherwise, install it if it's COM registration entry is missing. |
| 357 if (hr == CO_E_CLASSSTRING) { |
| 358 scoped_ptr<DaemonInstallerWin> installer = DaemonInstallerWin::Create( |
| 359 base::Bind(&DaemonControllerWin::OnInstallationComplete, |
| 360 base::Unretained(this), |
| 361 base::Passed(&config), |
| 362 done_callback)); |
| 363 if (installer.get()) { |
| 364 DCHECK(!installer_.get()); |
| 365 installer_ = installer.Pass(); |
| 366 installer_->Install(); |
| 367 } |
| 368 } else { |
| 369 LOG(ERROR) << "Failed to initiate the Chromoting Host installation " |
| 370 << "(error: 0x" << std::hex << hr << std::dec << ")."; |
| 371 done_callback.Run(HResultToAsyncResult(hr)); |
| 372 } |
| 373 } |
| 374 |
306 void DaemonControllerWin::DoSetConfigAndStart( | 375 void DaemonControllerWin::DoSetConfigAndStart( |
307 scoped_ptr<base::DictionaryValue> config, | 376 scoped_ptr<base::DictionaryValue> config, |
308 const CompletionCallback& done_callback) { | 377 const CompletionCallback& done_callback) { |
| 378 DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 379 |
309 IDaemonControl* control = NULL; | 380 IDaemonControl* control = NULL; |
310 HRESULT hr = worker_thread_.ActivateElevatedController(&control); | 381 HRESULT hr = worker_thread_.ActivateElevatedController(&control); |
311 if (FAILED(hr)) { | 382 if (FAILED(hr)) { |
312 done_callback.Run(HResultToAsyncResult(hr)); | 383 done_callback.Run(HResultToAsyncResult(hr)); |
313 return; | 384 return; |
314 } | 385 } |
315 | 386 |
316 // Store the configuration. | 387 // Store the configuration. |
317 std::string file_content; | 388 std::string file_content; |
318 base::JSONWriter::Write(config.get(), &file_content); | 389 base::JSONWriter::Write(config.get(), &file_content); |
319 | 390 |
320 BSTR host_config = ::SysAllocString(UTF8ToUTF16(file_content).c_str()); | 391 ScopedBstr host_config(UTF8ToUTF16(file_content).c_str()); |
321 if (host_config == NULL) { | 392 if (host_config == NULL) { |
322 done_callback.Run(HResultToAsyncResult(E_OUTOFMEMORY)); | 393 done_callback.Run(HResultToAsyncResult(E_OUTOFMEMORY)); |
323 return; | 394 return; |
324 } | 395 } |
325 | 396 |
326 hr = control->SetConfig(host_config); | 397 hr = control->SetConfig(host_config); |
327 ::SysFreeString(host_config); | |
328 if (FAILED(hr)) { | 398 if (FAILED(hr)) { |
329 done_callback.Run(HResultToAsyncResult(hr)); | 399 done_callback.Run(HResultToAsyncResult(hr)); |
330 return; | 400 return; |
331 } | 401 } |
332 | 402 |
333 // Start daemon. | 403 // Start daemon. |
334 hr = control->StartDaemon(); | 404 hr = control->StartDaemon(); |
335 done_callback.Run(HResultToAsyncResult(hr)); | 405 done_callback.Run(HResultToAsyncResult(hr)); |
336 } | 406 } |
337 | 407 |
338 void DaemonControllerWin::DoStop(const CompletionCallback& done_callback) { | 408 void DaemonControllerWin::DoStop(const CompletionCallback& done_callback) { |
| 409 DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 410 |
339 IDaemonControl* control = NULL; | 411 IDaemonControl* control = NULL; |
340 HRESULT hr = worker_thread_.ActivateElevatedController(&control); | 412 HRESULT hr = worker_thread_.ActivateElevatedController(&control); |
341 if (FAILED(hr)) { | 413 if (FAILED(hr)) { |
342 done_callback.Run(HResultToAsyncResult(hr)); | 414 done_callback.Run(HResultToAsyncResult(hr)); |
343 return; | 415 return; |
344 } | 416 } |
345 | 417 |
346 hr = control->StopDaemon(); | 418 hr = control->StopDaemon(); |
347 done_callback.Run(HResultToAsyncResult(hr)); | 419 done_callback.Run(HResultToAsyncResult(hr)); |
348 } | 420 } |
349 | 421 |
350 } // namespace | 422 } // namespace |
351 | 423 |
352 scoped_ptr<DaemonController> remoting::DaemonController::Create() { | 424 scoped_ptr<DaemonController> remoting::DaemonController::Create() { |
353 return scoped_ptr<DaemonController>(new DaemonControllerWin()); | 425 return scoped_ptr<DaemonController>(new DaemonControllerWin()); |
354 } | 426 } |
355 | 427 |
356 } // namespace remoting | 428 } // namespace remoting |
OLD | NEW |