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