12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "win8/test/open_with_dialog_controller.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <shlobj.h> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/callback.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_ptr.h" 139ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/run_loop.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/thread_task_runner_handle.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread_checker.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/windows_version.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "win8/test/open_with_dialog_async.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "win8/test/ui_automation_client.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace win8 { 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kControllerTimeoutSeconds = 5; 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t kShellFlyoutClassName[] = L"Shell_Flyout"; 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// A callback invoked with the OpenWithDialogController's results. Said results 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// are copied to |result_out| and |choices_out| and then |closure| is invoked. 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This function is in support of OpenWithDialogController::RunSynchronously. 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OnMakeDefaultComplete( 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Closure& closure, 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT* result_out, 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<base::string16>* choices_out, 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT hr, 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<base::string16> choices) { 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *result_out = hr; 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *choices_out = choices; 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) closure.Run(); 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Lives on the main thread and is owned by a controller. May outlive the 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// controller (see Orphan). 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class OpenWithDialogController::Context { 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Context(); 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ~Context(); 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::WeakPtr<Context> AsWeakPtr(); 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void Orphan(); 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void Begin(HWND parent_window, 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::string16& url_protocol, 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::string16& program_name, 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const OpenWithDialogController::SetDefaultCallback& callback); 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) enum State { 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The Context has been constructed. 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CONTEXT_INITIALIZED, 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The UI automation event handler is ready. 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CONTEXT_AUTOMATION_READY, 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The automation results came back before the call to SHOpenWithDialog. 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CONTEXT_WAITING_FOR_DIALOG, 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The call to SHOpenWithDialog returned before automation results. 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CONTEXT_WAITING_FOR_RESULTS, 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CONTEXT_FINISHED, 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }; 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Invokes the client's callback and destroys this instance. 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void NotifyClientAndDie(); 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void OnTimeout(); 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void OnInitialized(HRESULT result); 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void OnAutomationResult(HRESULT result, std::vector<base::string16> choices); 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void OnOpenWithComplete(HRESULT result); 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::ThreadChecker thread_checker_; 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) State state_; 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) internal::UIAutomationClient automation_client_; 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HWND parent_window_; 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 file_name_; 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 file_type_class_; 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int open_as_info_flags_; 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OpenWithDialogController::SetDefaultCallback callback_; 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT open_with_result_; 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT automation_result_; 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<base::string16> automation_choices_; 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::WeakPtrFactory<Context> weak_ptr_factory_; 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(Context); 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OpenWithDialogController::Context::Context() 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : state_(CONTEXT_INITIALIZED), 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parent_window_(), 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) open_as_info_flags_(), 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) open_with_result_(E_FAIL), 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) automation_result_(E_FAIL), 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) weak_ptr_factory_(this) {} 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OpenWithDialogController::Context::~Context() { 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::WeakPtr<OpenWithDialogController::Context> 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OpenWithDialogController::Context::AsWeakPtr() { 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return weak_ptr_factory_.GetWeakPtr(); 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OpenWithDialogController::Context::Orphan() { 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The controller is being destroyed. Its client is no longer interested in 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // having the interaction continue. 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DLOG_IF(WARNING, (state_ == CONTEXT_AUTOMATION_READY || 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_ == CONTEXT_WAITING_FOR_DIALOG)) 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << "Abandoning the OpenWithDialog."; 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete this; 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OpenWithDialogController::Context::Begin( 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HWND parent_window, 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::string16& url_protocol, 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::string16& program_name, 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const OpenWithDialogController::SetDefaultCallback& callback) { 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parent_window_ = parent_window; 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_name_ = url_protocol; 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_type_class_.clear(); 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) open_as_info_flags_ = (OAIF_URL_PROTOCOL | OAIF_FORCE_REGISTRATION | 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OAIF_REGISTER_EXT); 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_ = callback; 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Post a delayed callback to abort the operation if it takes too long. 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&OpenWithDialogController::Context::OnTimeout, AsWeakPtr()), 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::TimeDelta::FromSeconds(kControllerTimeoutSeconds)); 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) automation_client_.Begin( 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kShellFlyoutClassName, 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) program_name, 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&OpenWithDialogController::Context::OnInitialized, 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AsWeakPtr()), 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&OpenWithDialogController::Context::OnAutomationResult, 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AsWeakPtr())); 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OpenWithDialogController::Context::NotifyClientAndDie() { 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(state_, CONTEXT_FINISHED); 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DLOG_IF(WARNING, SUCCEEDED(automation_result_) && FAILED(open_with_result_)) 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << "Automation succeeded, yet SHOpenWithDialog failed."; 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Ignore any future callbacks (such as the timeout) or calls to Orphan. 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) weak_ptr_factory_.InvalidateWeakPtrs(); 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_.Run(automation_result_, automation_choices_); 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete this; 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OpenWithDialogController::Context::OnTimeout() { 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // This is a LOG rather than a DLOG since it represents something that needs 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // to be investigated and fixed. 170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch LOG(ERROR) << __FUNCTION__ << " state: " << state_; 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_ = CONTEXT_FINISHED; 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NotifyClientAndDie(); 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OpenWithDialogController::Context::OnInitialized(HRESULT result) { 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(state_, CONTEXT_INITIALIZED); 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(result)) { 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) automation_result_ = result; 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_ = CONTEXT_FINISHED; 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NotifyClientAndDie(); 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_ = CONTEXT_AUTOMATION_READY; 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OpenWithDialogAsync( 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parent_window_, file_name_, file_type_class_, open_as_info_flags_, 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&OpenWithDialogController::Context::OnOpenWithComplete, 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OpenWithDialogController::Context::OnAutomationResult( 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT result, 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<base::string16> choices) { 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(automation_result_, E_FAIL); 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) automation_result_ = result; 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) automation_choices_ = choices; 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (state_) { 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case CONTEXT_AUTOMATION_READY: 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The results of automation are in and we're waiting for 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // SHOpenWithDialog to return. 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_ = CONTEXT_WAITING_FOR_DIALOG; 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case CONTEXT_WAITING_FOR_RESULTS: 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_ = CONTEXT_FINISHED; 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NotifyClientAndDie(); 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED() << state_; 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OpenWithDialogController::Context::OnOpenWithComplete(HRESULT result) { 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(open_with_result_, E_FAIL); 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) open_with_result_ = result; 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (state_) { 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case CONTEXT_AUTOMATION_READY: 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The interaction completed and we're waiting for the results from the 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // automation side to come in. 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_ = CONTEXT_WAITING_FOR_RESULTS; 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case CONTEXT_WAITING_FOR_DIALOG: 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // All results are in. Invoke the caller's callback. 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_ = CONTEXT_FINISHED; 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NotifyClientAndDie(); 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED() << state_; 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OpenWithDialogController::OpenWithDialogController() {} 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)OpenWithDialogController::~OpenWithDialogController() { 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Orphan the context if this instance is being destroyed before the context 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // finishes its work. 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (context_) 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) context_->Orphan(); 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OpenWithDialogController::Begin( 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HWND parent_window, 2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::string16& url_protocol, 2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::string16& program, 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const SetDefaultCallback& callback) { 250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK_EQ(context_.get(), static_cast<Context*>(NULL)); 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (base::win::GetVersion() < base::win::VERSION_WIN8) { 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED() << "Windows 8 is required."; 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The callback may not properly handle being run from Begin, so post a task 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // to this thread's task runner to call it. 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::ThreadTaskRunnerHandle::Get()->PostTask( 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(callback, E_FAIL, std::vector<base::string16>())); 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) context_ = (new Context())->AsWeakPtr(); 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) context_->Begin(parent_window, url_protocol, program, callback); 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT OpenWithDialogController::RunSynchronously( 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HWND parent_window, 2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::string16& protocol, 2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::string16& program, 2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<base::string16>* choices) { 270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK_EQ(base::MessageLoop::current(), 271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) static_cast<base::MessageLoop*>(NULL)); 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (base::win::GetVersion() < base::win::VERSION_WIN8) { 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED() << "Windows 8 is required."; 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return E_FAIL; 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT result = S_OK; 278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::MessageLoop message_loop; 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::RunLoop run_loop; 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message_loop.PostTask( 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&OpenWithDialogController::Begin, base::Unretained(this), 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parent_window, protocol, program, 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Bind(&OnMakeDefaultComplete, run_loop.QuitClosure(), 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &result, choices))); 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) run_loop.Run(); 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return result; 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace win8 293