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)typedef winfoundtn::Collections::IVector<HSTRING> StringVectorItf;
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(siggi): Complete this implementation and move it to a common place.
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class StringVectorImpl : public mswr::RuntimeClass<StringVectorItf> {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ~StringVectorImpl() {
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::for_each(strings_.begin(), strings_.end(), ::WindowsDeleteString);
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HRESULT RuntimeClassInitialize(const std::vector<base::string16>& list) {
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < list.size(); ++i)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      strings_.push_back(MakeHString(list[i]));
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return S_OK;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // IVector<HSTRING> implementation.
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STDMETHOD(GetAt)(unsigned index, HSTRING* item) {
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (index >= strings_.size())
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return E_INVALIDARG;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ::WindowsDuplicateString(strings_[index], item);
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STDMETHOD(get_Size)(unsigned *size) {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (strings_.size() > UINT_MAX)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return E_UNEXPECTED;
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *size = static_cast<unsigned>(strings_.size());
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return S_OK;
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STDMETHOD(GetView)(winfoundtn::Collections::IVectorView<HSTRING> **view) {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return E_NOTIMPL;
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STDMETHOD(IndexOf)(HSTRING value, unsigned *index, boolean *found) {
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return E_NOTIMPL;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // write methods
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STDMETHOD(SetAt)(unsigned index, HSTRING item) {
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return E_NOTIMPL;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STDMETHOD(InsertAt)(unsigned index, HSTRING item) {
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return E_NOTIMPL;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STDMETHOD(RemoveAt)(unsigned index) {
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return E_NOTIMPL;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STDMETHOD(Append)(HSTRING item) {
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return E_NOTIMPL;
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STDMETHOD(RemoveAtEnd)() {
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return E_NOTIMPL;
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STDMETHOD(Clear)() {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return E_NOTIMPL;
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<HSTRING> strings_;
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FilePickerSessionBase::FilePickerSessionBase(ChromeAppViewAsh* app_view,
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                             const base::string16& title,
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                             const base::string16& filter,
867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                             const base::FilePath& default_path)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : app_view_(app_view),
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      title_(title),
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      filter_(filter),
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default_path_(default_path),
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      success_(false) {
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FilePickerSessionBase::Run() {
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!DoFilePicker())
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return success_;
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FilePickerSessionBase::DoFilePicker() {
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The file picker will fail if spawned from a snapped application,
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // so let's attempt to unsnap first if we're in that state.
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT hr = ChromeAppViewAsh::Unsnap();
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr)) {
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to unsnap for file picker, error 0x" << hr;
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = StartFilePicker();
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr)) {
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to start file picker, error 0x"
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << std::hex << hr;
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1177dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochOpenFilePickerSession::OpenFilePickerSession(
1187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ChromeAppViewAsh* app_view,
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& title,
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& filter,
1217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const base::FilePath& default_path,
1227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    bool allow_multi_select)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : FilePickerSessionBase(app_view, title, filter, default_path),
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      allow_multi_select_(allow_multi_select) {
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT OpenFilePickerSession::SinglePickerDone(SingleFileAsyncOp* async,
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                AsyncStatus status) {
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (status == Completed) {
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mswr::ComPtr<winstorage::IStorageFile> file;
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    HRESULT hr = async->GetResults(file.GetAddressOf());
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (file) {
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      mswr::ComPtr<winstorage::IStorageItem> storage_item;
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (SUCCEEDED(hr))
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        hr = file.As(&storage_item);
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      mswrw::HString file_path;
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (SUCCEEDED(hr))
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        hr = storage_item->get_Path(file_path.GetAddressOf());
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (SUCCEEDED(hr)) {
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        UINT32 path_len = 0;
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        const wchar_t* path_str =
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ::WindowsGetStringRawBuffer(file_path.Get(), &path_len);
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        result_ = path_str;
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        success_ = true;
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(ERROR) << "NULL IStorageItem";
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  app_view_->OnOpenFileCompleted(this, success_);
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return S_OK;
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT OpenFilePickerSession::MultiPickerDone(MultiFileAsyncOp* async,
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               AsyncStatus status) {
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (status == Completed) {
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mswr::ComPtr<StorageFileVectorCollection> files;
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    HRESULT hr = async->GetResults(files.GetAddressOf());
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (files) {
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::string16 result;
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (SUCCEEDED(hr))
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        hr = ComposeMultiFileResult(files.Get(), &result);
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (SUCCEEDED(hr)) {
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        success_ = true;
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // The code below has been copied from the
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // SelectFileDialogImpl::RunOpenMultiFileDialog function in
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // select_file_dialog_win.cc.
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // TODO(ananta)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // Consolidate this into a common place.
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        const wchar_t* selection = result.c_str();
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::vector<base::FilePath> files;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        while (*selection) {  // Empty string indicates end of list.
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          files.push_back(base::FilePath(selection));
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // Skip over filename and null-terminator.
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          selection += files.back().value().length() + 1;
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (files.empty()) {
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          success_ = false;
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        } else if (files.size() == 1) {
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // When there is one file, it contains the path and filename.
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          filenames_ = files;
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        } else if (files.size() > 1) {
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // Otherwise, the first string is the path, and the remainder are
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // filenames.
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          std::vector<base::FilePath>::iterator path = files.begin();
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          for (std::vector<base::FilePath>::iterator file = path + 1;
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               file != files.end(); ++file) {
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            filenames_.push_back(path->Append(*file));
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          }
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(ERROR) << "NULL StorageFileVectorCollection";
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
2053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  app_view_->OnOpenFileCompleted(this, success_);
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return S_OK;
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT OpenFilePickerSession::StartFilePicker() {
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  mswrw::HStringReference class_name(
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RuntimeClass_Windows_Storage_Pickers_FileOpenPicker);
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the file picker.
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  mswr::ComPtr<winstorage::Pickers::IFileOpenPicker> picker;
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT hr = ::Windows::Foundation::ActivateInstance(
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      class_name.Get(), picker.GetAddressOf());
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckHR(hr);
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Set the file type filter
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  mswr::ComPtr<winfoundtn::Collections::IVector<HSTRING>> filter;
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = picker->get_FileTypeFilter(filter.GetAddressOf());
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr))
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (filter_.empty()) {
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    hr = filter->Append(mswrw::HStringReference(L"*").Get());
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (FAILED(hr))
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return hr;
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The filter is a concatenation of zero terminated string pairs,
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // where each pair is {description, extension}. The concatenation ends
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // with a zero length string - e.g. a double zero terminator.
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const wchar_t* walk = filter_.c_str();
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    while (*walk != L'\0') {
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Walk past the description.
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      walk += wcslen(walk) + 1;
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // We should have an extension, but bail on malformed filters.
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (*walk == L'\0')
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // There can be a single extension, or a list of semicolon-separated ones.
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::vector<base::string16> extensions_win32_style;
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      size_t extension_count = Tokenize(walk, L";", &extensions_win32_style);
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK_EQ(extension_count, extensions_win32_style.size());
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Metro wants suffixes only, not patterns.
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      mswrw::HString extension;
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (size_t i = 0; i < extensions_win32_style.size(); ++i) {
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (extensions_win32_style[i] == L"*.*") {
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // The wildcard filter is "*" for Metro. The string "*.*" produces
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // an "invalid parameter" error.
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          hr = extension.Set(L"*");
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        } else {
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // Metro wants suffixes only, not patterns.
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::string16 ext =
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              base::FilePath(extensions_win32_style[i]).Extension();
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          if ((ext.size() < 2) ||
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (ext.find_first_of(L"*?") != base::string16::npos)) {
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            continue;
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          }
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          hr = extension.Set(ext.c_str());
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (SUCCEEDED(hr))
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          hr = filter->Append(extension.Get());
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (FAILED(hr))
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          return hr;
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Walk past the extension.
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      walk += wcslen(walk) + 1;
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Spin up a single or multi picker as appropriate.
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (allow_multi_select_) {
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mswr::ComPtr<MultiFileAsyncOp> completion;
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    hr = picker->PickMultipleFilesAsync(&completion);
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (FAILED(hr))
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return hr;
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Create the callback method.
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    typedef winfoundtn::IAsyncOperationCompletedHandler<
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        StorageFileVectorCollection*> HandlerDoneType;
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        this, &OpenFilePickerSession::MultiPickerDone));
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(handler.Get() != NULL);
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    hr = completion->put_Completed(handler.Get());
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mswr::ComPtr<SingleFileAsyncOp> completion;
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    hr = picker->PickSingleFileAsync(&completion);
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (FAILED(hr))
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return hr;
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Create the callback method.
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    typedef winfoundtn::IAsyncOperationCompletedHandler<
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        winstorage::StorageFile*> HandlerDoneType;
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        this, &OpenFilePickerSession::SinglePickerDone));
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(handler.Get() != NULL);
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    hr = completion->put_Completed(handler.Get());
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT OpenFilePickerSession::ComposeMultiFileResult(
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    StorageFileVectorCollection* files, base::string16* result) {
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(files != NULL);
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(result != NULL);
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Empty the output string.
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->clear();
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned int num_files = 0;
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT hr = files->get_Size(&num_files);
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr))
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Make sure we return an error on an empty collection.
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (num_files == 0) {
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DLOG(ERROR) << "Empty collection on input.";
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return E_UNEXPECTED;
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This stores the base path that should be the parent of all the files.
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath base_path;
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Iterate through the collection and append the file paths to the result.
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (unsigned int i = 0; i < num_files; ++i) {
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mswr::ComPtr<winstorage::IStorageFile> file;
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    hr = files->GetAt(i, file.GetAddressOf());
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (FAILED(hr))
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return hr;
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mswr::ComPtr<winstorage::IStorageItem> storage_item;
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    hr = file.As(&storage_item);
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (FAILED(hr))
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return hr;
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mswrw::HString file_path_str;
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    hr = storage_item->get_Path(file_path_str.GetAddressOf());
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (FAILED(hr))
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return hr;
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath file_path(MakeStdWString(file_path_str.Get()));
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (base_path.empty()) {
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK(result->empty());
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base_path = file_path.DirName();
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Append the path, including the terminating zero.
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // We do this only for the first file.
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      result->append(base_path.value().c_str(), base_path.value().size() + 1);
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(!result->empty());
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(!base_path.empty());
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(base_path == file_path.DirName());
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Append the base name, including the terminating zero.
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath base_name = file_path.BaseName();
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result->append(base_name.value().c_str(), base_name.value().size() + 1);
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!result->empty());
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return S_OK;
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SaveFilePickerSession::SaveFilePickerSession(
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ChromeAppViewAsh* app_view,
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const MetroViewerHostMsg_SaveAsDialogParams& params)
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : FilePickerSessionBase(app_view,
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            params.title,
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            params.filter,
3797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            params.suggested_name),
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      filter_index_(params.filter_index) {
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int SaveFilePickerSession::filter_index() const {
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(ananta)
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Add support for returning the correct filter index. This does not work in
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // regular Chrome metro on trunk as well.
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // BUG: https://code.google.com/p/chromium/issues/detail?id=172704
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return filter_index_;
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT SaveFilePickerSession::StartFilePicker() {
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  mswrw::HStringReference class_name(
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RuntimeClass_Windows_Storage_Pickers_FileSavePicker);
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the file picker.
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  mswr::ComPtr<winstorage::Pickers::IFileSavePicker> picker;
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT hr = ::Windows::Foundation::ActivateInstance(
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      class_name.Get(), picker.GetAddressOf());
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckHR(hr);
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef winfoundtn::Collections::IMap<HSTRING, StringVectorItf*>
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      StringVectorMap;
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  mswr::ComPtr<StringVectorMap> choices;
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = picker->get_FileTypeChoices(choices.GetAddressOf());
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr))
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!filter_.empty()) {
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The filter is a concatenation of zero terminated string pairs,
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // where each pair is {description, extension list}. The concatenation ends
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // with a zero length string - e.g. a double zero terminator.
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const wchar_t* walk = filter_.c_str();
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    while (*walk != L'\0') {
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      mswrw::HString description;
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      hr = description.Set(walk);
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (FAILED(hr))
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return hr;
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Walk past the description.
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      walk += wcslen(walk) + 1;
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // We should have an extension, but bail on malformed filters.
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (*walk == L'\0')
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // There can be a single extension, or a list of semicolon-separated ones.
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::vector<base::string16> extensions_win32_style;
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      size_t extension_count = Tokenize(walk, L";", &extensions_win32_style);
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK_EQ(extension_count, extensions_win32_style.size());
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Metro wants suffixes only, not patterns.  Also, metro does not support
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // the all files ("*") pattern in the save picker.
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::vector<base::string16> extensions;
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (size_t i = 0; i < extensions_win32_style.size(); ++i) {
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::string16 ext =
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            base::FilePath(extensions_win32_style[i]).Extension();
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if ((ext.size() < 2) ||
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            (ext.find_first_of(L"*?") != base::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>(
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        list.GetAddressOf(), std::vector<base::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()) {
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::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)) {
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::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 {
5463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "Unexpected async status " << static_cast<int>(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,
5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         const base::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)) {
6075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::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 {
6153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "Unexpected async status " << static_cast<int>(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