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 "stdafx.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "win8/metro_driver/file_picker_ash.h" 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h" 109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/synchronization/waitable_event.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/metro.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/scoped_comptr.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/metro_viewer/metro_viewer_messages.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "win8/metro_driver/chrome_app_view_ash.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "win8/metro_driver/winrt_utils.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace winstorage = ABI::Windows::Storage; 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)typedef winfoundtn::Collections::IVector<HSTRING> StringVectorItf; 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(siggi): Complete this implementation and move it to a common place. 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class StringVectorImpl : public mswr::RuntimeClass<StringVectorItf> { 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ~StringVectorImpl() { 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::for_each(strings_.begin(), strings_.end(), ::WindowsDeleteString); 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT RuntimeClassInitialize(const std::vector<string16>& list) { 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < list.size(); ++i) 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) strings_.push_back(MakeHString(list[i])); 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return S_OK; 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // IVector<HSTRING> implementation. 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) STDMETHOD(GetAt)(unsigned index, HSTRING* item) { 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (index >= strings_.size()) 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return E_INVALIDARG; 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ::WindowsDuplicateString(strings_[index], item); 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) STDMETHOD(get_Size)(unsigned *size) { 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (strings_.size() > UINT_MAX) 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return E_UNEXPECTED; 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *size = static_cast<unsigned>(strings_.size()); 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return S_OK; 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) STDMETHOD(GetView)(winfoundtn::Collections::IVectorView<HSTRING> **view) { 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return E_NOTIMPL; 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) STDMETHOD(IndexOf)(HSTRING value, unsigned *index, boolean *found) { 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return E_NOTIMPL; 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // write methods 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) STDMETHOD(SetAt)(unsigned index, HSTRING item) { 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return E_NOTIMPL; 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) STDMETHOD(InsertAt)(unsigned index, HSTRING item) { 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return E_NOTIMPL; 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) STDMETHOD(RemoveAt)(unsigned index) { 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return E_NOTIMPL; 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) STDMETHOD(Append)(HSTRING item) { 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return E_NOTIMPL; 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) STDMETHOD(RemoveAtEnd)() { 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return E_NOTIMPL; 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) STDMETHOD(Clear)() { 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return E_NOTIMPL; 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<HSTRING> strings_; 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FilePickerSessionBase::FilePickerSessionBase(ChromeAppViewAsh* app_view, 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const string16& title, 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const string16& filter, 877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const base::FilePath& default_path) 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : app_view_(app_view), 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) title_(title), 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) filter_(filter), 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default_path_(default_path), 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) success_(false) { 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FilePickerSessionBase::Run() { 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!DoFilePicker()) 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return success_; 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FilePickerSessionBase::DoFilePicker() { 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The file picker will fail if spawned from a snapped application, 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // so let's attempt to unsnap first if we're in that state. 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT hr = ChromeAppViewAsh::Unsnap(); 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) { 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Failed to unsnap for file picker, error 0x" << hr; 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = StartFilePicker(); 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) { 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Failed to start file picker, error 0x" 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << std::hex << hr; 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1187dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochOpenFilePickerSession::OpenFilePickerSession( 1197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ChromeAppViewAsh* app_view, 1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const string16& title, 1217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const string16& filter, 1227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const base::FilePath& default_path, 1237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch bool allow_multi_select) 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : FilePickerSessionBase(app_view, title, filter, default_path), 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) allow_multi_select_(allow_multi_select) { 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT OpenFilePickerSession::SinglePickerDone(SingleFileAsyncOp* async, 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AsyncStatus status) { 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (status == Completed) { 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<winstorage::IStorageFile> file; 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT hr = async->GetResults(file.GetAddressOf()); 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (file) { 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<winstorage::IStorageItem> storage_item; 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (SUCCEEDED(hr)) 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = file.As(&storage_item); 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswrw::HString file_path; 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (SUCCEEDED(hr)) 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = storage_item->get_Path(file_path.GetAddressOf()); 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (SUCCEEDED(hr)) { 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UINT32 path_len = 0; 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const wchar_t* path_str = 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ::WindowsGetStringRawBuffer(file_path.Get(), &path_len); 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result_ = path_str; 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) success_ = true; 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "NULL IStorageItem"; 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Unexpected async status " << status; 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) app_view_->OnOpenFileCompleted(this, success_); 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return S_OK; 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT OpenFilePickerSession::MultiPickerDone(MultiFileAsyncOp* async, 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AsyncStatus status) { 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (status == Completed) { 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<StorageFileVectorCollection> files; 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT hr = async->GetResults(files.GetAddressOf()); 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (files) { 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16 result; 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (SUCCEEDED(hr)) 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = ComposeMultiFileResult(files.Get(), &result); 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (SUCCEEDED(hr)) { 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) success_ = true; 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The code below has been copied from the 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // SelectFileDialogImpl::RunOpenMultiFileDialog function in 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // select_file_dialog_win.cc. 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(ananta) 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Consolidate this into a common place. 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const wchar_t* selection = result.c_str(); 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<base::FilePath> files; 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (*selection) { // Empty string indicates end of list. 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) files.push_back(base::FilePath(selection)); 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Skip over filename and null-terminator. 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) selection += files.back().value().length() + 1; 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (files.empty()) { 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) success_ = false; 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (files.size() == 1) { 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // When there is one file, it contains the path and filename. 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) filenames_ = files; 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (files.size() > 1) { 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Otherwise, the first string is the path, and the remainder are 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // filenames. 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<base::FilePath>::iterator path = files.begin(); 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (std::vector<base::FilePath>::iterator file = path + 1; 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file != files.end(); ++file) { 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) filenames_.push_back(path->Append(*file)); 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "NULL StorageFileVectorCollection"; 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Unexpected async status " << status; 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) app_view_->OnOpenFileCompleted(this, success_); 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return S_OK; 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT OpenFilePickerSession::StartFilePicker() { 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswrw::HStringReference class_name( 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RuntimeClass_Windows_Storage_Pickers_FileOpenPicker); 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create the file picker. 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<winstorage::Pickers::IFileOpenPicker> picker; 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT hr = ::Windows::Foundation::ActivateInstance( 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) class_name.Get(), picker.GetAddressOf()); 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CheckHR(hr); 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Set the file type filter 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<winfoundtn::Collections::IVector<HSTRING>> filter; 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = picker->get_FileTypeFilter(filter.GetAddressOf()); 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (filter_.empty()) { 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = filter->Append(mswrw::HStringReference(L"*").Get()); 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The filter is a concatenation of zero terminated string pairs, 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // where each pair is {description, extension}. The concatenation ends 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // with a zero length string - e.g. a double zero terminator. 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const wchar_t* walk = filter_.c_str(); 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (*walk != L'\0') { 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Walk past the description. 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) walk += wcslen(walk) + 1; 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We should have an extension, but bail on malformed filters. 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (*walk == L'\0') 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // There can be a single extension, or a list of semicolon-separated ones. 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<string16> extensions_win32_style; 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t extension_count = Tokenize(walk, L";", &extensions_win32_style); 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(extension_count, extensions_win32_style.size()); 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Metro wants suffixes only, not patterns. 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswrw::HString extension; 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<string16> extensions; 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < extensions_win32_style.size(); ++i) { 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (extensions_win32_style[i] == L"*.*") { 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The wildcard filter is "*" for Metro. The string "*.*" produces 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // an "invalid parameter" error. 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = extension.Set(L"*"); 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Metro wants suffixes only, not patterns. 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16 ext = base::FilePath(extensions_win32_style[i]).Extension(); 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if ((ext.size() < 2) || 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (ext.find_first_of(L"*?") != string16::npos)) { 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = extension.Set(ext.c_str()); 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (SUCCEEDED(hr)) 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = filter->Append(extension.Get()); 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Walk past the extension. 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) walk += wcslen(walk) + 1; 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Spin up a single or multi picker as appropriate. 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (allow_multi_select_) { 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<MultiFileAsyncOp> completion; 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = picker->PickMultipleFilesAsync(&completion); 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create the callback method. 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) typedef winfoundtn::IAsyncOperationCompletedHandler< 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) StorageFileVectorCollection*> HandlerDoneType; 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>( 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, &OpenFilePickerSession::MultiPickerDone)); 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(handler.Get() != NULL); 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = completion->put_Completed(handler.Get()); 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<SingleFileAsyncOp> completion; 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = picker->PickSingleFileAsync(&completion); 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create the callback method. 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) typedef winfoundtn::IAsyncOperationCompletedHandler< 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) winstorage::StorageFile*> HandlerDoneType; 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>( 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, &OpenFilePickerSession::SinglePickerDone)); 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(handler.Get() != NULL); 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = completion->put_Completed(handler.Get()); 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT OpenFilePickerSession::ComposeMultiFileResult( 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) StorageFileVectorCollection* files, string16* result) { 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(files != NULL); 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(result != NULL); 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Empty the output string. 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result->clear(); 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unsigned int num_files = 0; 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT hr = files->get_Size(&num_files); 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Make sure we return an error on an empty collection. 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (num_files == 0) { 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DLOG(ERROR) << "Empty collection on input."; 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return E_UNEXPECTED; 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // This stores the base path that should be the parent of all the files. 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath base_path; 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Iterate through the collection and append the file paths to the result. 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (unsigned int i = 0; i < num_files; ++i) { 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<winstorage::IStorageFile> file; 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = files->GetAt(i, file.GetAddressOf()); 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<winstorage::IStorageItem> storage_item; 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = file.As(&storage_item); 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswrw::HString file_path_str; 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = storage_item->get_Path(file_path_str.GetAddressOf()); 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath file_path(MakeStdWString(file_path_str.Get())); 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (base_path.empty()) { 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(result->empty()); 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base_path = file_path.DirName(); 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Append the path, including the terminating zero. 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We do this only for the first file. 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result->append(base_path.value().c_str(), base_path.value().size() + 1); 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!result->empty()); 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!base_path.empty()); 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(base_path == file_path.DirName()); 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Append the base name, including the terminating zero. 3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath base_name = file_path.BaseName(); 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result->append(base_name.value().c_str(), base_name.value().size() + 1); 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!result->empty()); 3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return S_OK; 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SaveFilePickerSession::SaveFilePickerSession( 3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ChromeAppViewAsh* app_view, 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const MetroViewerHostMsg_SaveAsDialogParams& params) 3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : FilePickerSessionBase(app_view, 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) params.title, 3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) params.filter, 3807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch params.suggested_name), 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) filter_index_(params.filter_index) { 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int SaveFilePickerSession::filter_index() const { 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(ananta) 3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Add support for returning the correct filter index. This does not work in 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // regular Chrome metro on trunk as well. 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // BUG: https://code.google.com/p/chromium/issues/detail?id=172704 3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return filter_index_; 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT SaveFilePickerSession::StartFilePicker() { 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswrw::HStringReference class_name( 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RuntimeClass_Windows_Storage_Pickers_FileSavePicker); 3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create the file picker. 3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<winstorage::Pickers::IFileSavePicker> picker; 3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT hr = ::Windows::Foundation::ActivateInstance( 3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) class_name.Get(), picker.GetAddressOf()); 4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CheckHR(hr); 4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) typedef winfoundtn::Collections::IMap<HSTRING, StringVectorItf*> 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) StringVectorMap; 4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<StringVectorMap> choices; 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = picker->get_FileTypeChoices(choices.GetAddressOf()); 4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!filter_.empty()) { 4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The filter is a concatenation of zero terminated string pairs, 4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // where each pair is {description, extension list}. The concatenation ends 4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // with a zero length string - e.g. a double zero terminator. 4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const wchar_t* walk = filter_.c_str(); 4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (*walk != L'\0') { 4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswrw::HString description; 4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = description.Set(walk); 4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Walk past the description. 4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) walk += wcslen(walk) + 1; 4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We should have an extension, but bail on malformed filters. 4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (*walk == L'\0') 4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // There can be a single extension, or a list of semicolon-separated ones. 4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<string16> extensions_win32_style; 4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t extension_count = Tokenize(walk, L";", &extensions_win32_style); 4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(extension_count, extensions_win32_style.size()); 4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Metro wants suffixes only, not patterns. Also, metro does not support 4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the all files ("*") pattern in the save picker. 4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<string16> extensions; 4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < extensions_win32_style.size(); ++i) { 4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16 ext = base::FilePath(extensions_win32_style[i]).Extension(); 4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if ((ext.size() < 2) || 4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (ext.find_first_of(L"*?") != string16::npos)) 4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extensions.push_back(ext); 4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!extensions.empty()) { 4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Convert to a Metro collection class. 4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<StringVectorItf> list; 4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = mswr::MakeAndInitialize<StringVectorImpl>( 4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) list.GetAddressOf(), extensions); 4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Finally set the filter. 4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) boolean replaced = FALSE; 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = choices->Insert(description.Get(), list.Get(), &replaced); 4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(FALSE, replaced); 4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Walk past the extension(s). 4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) walk += wcslen(walk) + 1; 4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The save picker requires at least one choice. Callers are strongly advised 4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // to provide sensible choices. If none were given, fallback to .dat. 4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint32 num_choices = 0; 4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = choices->get_Size(&num_choices); 4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (num_choices == 0) { 4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswrw::HString description; 4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(grt): Get a properly translated string. This can't be done from 4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // within metro_driver. Consider preprocessing the filter list in Chrome 4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // land to ensure it has this entry if all others are patterns. In that 4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // case, this whole block of code can be removed. 4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = description.Set(L"Data File"); 4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<StringVectorItf> list; 4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = mswr::MakeAndInitialize<StringVectorImpl>( 4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) list.GetAddressOf(), std::vector<string16>(1, L".dat")); 4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) boolean replaced = FALSE; 4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = choices->Insert(description.Get(), list.Get(), &replaced); 4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(FALSE, replaced); 4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!default_path_.empty()) { 4957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch string16 file_part = default_path_.BaseName().value(); 4967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // If the suggested_name is a root directory, then don't set it as the 4977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // suggested name. 4987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (file_part.size() == 1 && file_part[0] == L'\\') 4997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch file_part.clear(); 5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = picker->put_SuggestedFileName( 5017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch mswrw::HStringReference(file_part.c_str()).Get()); 5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<SaveFileAsyncOp> completion; 5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = picker->PickSaveFileAsync(&completion); 5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create the callback method. 5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) typedef winfoundtn::IAsyncOperationCompletedHandler< 5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) winstorage::StorageFile*> HandlerDoneType; 5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>( 5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, &SaveFilePickerSession::FilePickerDone)); 5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(handler.Get() != NULL); 5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = completion->put_Completed(handler.Get()); 5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return hr; 5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT SaveFilePickerSession::FilePickerDone(SaveFileAsyncOp* async, 5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AsyncStatus status) { 5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (status == Completed) { 5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<winstorage::IStorageFile> file; 5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT hr = async->GetResults(file.GetAddressOf()); 5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (file) { 5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswr::ComPtr<winstorage::IStorageItem> storage_item; 5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (SUCCEEDED(hr)) 5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = file.As(&storage_item); 5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mswrw::HString file_path; 5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (SUCCEEDED(hr)) 5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = storage_item->get_Path(file_path.GetAddressOf()); 5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (SUCCEEDED(hr)) { 5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16 path_str = MakeStdWString(file_path.Get()); 5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result_ = path_str; 5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) success_ = true; 5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "NULL IStorageItem"; 5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Unexpected async status " << status; 5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) app_view_->OnSaveFileCompleted(this, success_); 5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return S_OK; 5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 552c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)FolderPickerSession::FolderPickerSession(ChromeAppViewAsh* app_view, 553c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const string16& title) 5547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch : FilePickerSessionBase(app_view, title, L"", base::FilePath()) {} 555c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 556c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)HRESULT FolderPickerSession::StartFilePicker() { 557c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mswrw::HStringReference class_name( 558c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) RuntimeClass_Windows_Storage_Pickers_FolderPicker); 559c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 560c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Create the folder picker. 561c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mswr::ComPtr<winstorage::Pickers::IFolderPicker> picker; 562c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) HRESULT hr = ::Windows::Foundation::ActivateInstance( 563c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) class_name.Get(), picker.GetAddressOf()); 564c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CheckHR(hr); 565c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 566c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Set the file type filter 567c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mswr::ComPtr<winfoundtn::Collections::IVector<HSTRING>> filter; 568c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) hr = picker->get_FileTypeFilter(filter.GetAddressOf()); 569c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (FAILED(hr)) 570c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return hr; 571c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 572c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) hr = filter->Append(mswrw::HStringReference(L"*").Get()); 573c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (FAILED(hr)) 574c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return hr; 575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 576c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mswr::ComPtr<FolderPickerAsyncOp> completion; 577c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) hr = picker->PickSingleFolderAsync(&completion); 578c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (FAILED(hr)) 579c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return hr; 580c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 581c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Create the callback method. 582c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) typedef winfoundtn::IAsyncOperationCompletedHandler< 583c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) winstorage::StorageFolder*> HandlerDoneType; 584c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>( 585c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) this, &FolderPickerSession::FolderPickerDone)); 586c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(handler.Get() != NULL); 587c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) hr = completion->put_Completed(handler.Get()); 588c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return hr; 589c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 590c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 591c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)HRESULT FolderPickerSession::FolderPickerDone(FolderPickerAsyncOp* async, 592c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AsyncStatus status) { 593c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (status == Completed) { 594c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mswr::ComPtr<winstorage::IStorageFolder> folder; 595c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) HRESULT hr = async->GetResults(folder.GetAddressOf()); 596c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 597c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (folder) { 598c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mswr::ComPtr<winstorage::IStorageItem> storage_item; 599c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (SUCCEEDED(hr)) 600c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) hr = folder.As(&storage_item); 601c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 602c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mswrw::HString file_path; 603c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (SUCCEEDED(hr)) 604c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) hr = storage_item->get_Path(file_path.GetAddressOf()); 605c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 606c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (SUCCEEDED(hr)) { 607c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) string16 path_str = MakeStdWString(file_path.Get()); 608c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) result_ = path_str; 609c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) success_ = true; 610c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 611c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 612c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LOG(ERROR) << "NULL IStorageItem"; 613c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 614c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 615c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LOG(ERROR) << "Unexpected async status " << status; 616c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 617c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) app_view_->OnFolderPickerCompleted(this, success_); 618c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return S_OK; 619c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 620c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 621