15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "stdafx.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "win8/metro_driver/file_picker.h"
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.storage.pickers.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
139ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/waitable_event.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/metro.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/scoped_comptr.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "win8/metro_driver/chrome_app_view.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "win8/metro_driver/winrt_utils.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace winstorage = ABI::Windows::Storage;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef winfoundtn::Collections::IVector<HSTRING> StringVectorItf;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(siggi): Complete this implementation and move it to a common place.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class StringVectorImpl : public mswr::RuntimeClass<StringVectorItf> {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~StringVectorImpl() {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::for_each(strings_.begin(), strings_.end(), ::WindowsDeleteString);
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HRESULT RuntimeClassInitialize(const std::vector<base::string16>& list) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < list.size(); ++i)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      strings_.push_back(MakeHString(list[i]));
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return S_OK;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IVector<HSTRING> implementation.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(GetAt)(unsigned index, HSTRING* item) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (index >= strings_.size())
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return E_INVALIDARG;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ::WindowsDuplicateString(strings_[index], item);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(get_Size)(unsigned *size) {
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (strings_.size() > UINT_MAX)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return E_UNEXPECTED;
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *size = static_cast<unsigned>(strings_.size());
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return S_OK;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(GetView)(winfoundtn::Collections::IVectorView<HSTRING> **view) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_NOTIMPL;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(IndexOf)(HSTRING value, unsigned *index, boolean *found) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_NOTIMPL;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // write methods
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(SetAt)(unsigned index, HSTRING item) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_NOTIMPL;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(InsertAt)(unsigned index, HSTRING item) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_NOTIMPL;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(RemoveAt)(unsigned index) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_NOTIMPL;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(Append)(HSTRING item) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_NOTIMPL;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(RemoveAtEnd)() {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_NOTIMPL;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(Clear)() {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_NOTIMPL;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<HSTRING> strings_;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class FilePickerSessionBase {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates a file picker for open_file_name.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit FilePickerSessionBase(OPENFILENAME* open_file_name);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Runs the picker, returns true on success.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Run();
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates, configures and starts a file picker.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the HRESULT returned is a failure code the file picker has not started,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so no callbacks should be expected.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT StartFilePicker() = 0;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The parameters to our picker.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OPENFILENAME* open_file_name_;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The event Run waits on.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::WaitableEvent event_;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // True iff a file picker has successfully finished.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success_;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initiate a file picker, must be called on the metro dispatcher's thread.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DoFilePicker();
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(FilePickerSessionBase);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class OpenFilePickerSession : public FilePickerSessionBase {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit OpenFilePickerSession(OPENFILENAME* open_file_name);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT StartFilePicker() OVERRIDE;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef winfoundtn::IAsyncOperation<winstorage::StorageFile*>
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SingleFileAsyncOp;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef winfoundtn::Collections::IVectorView<
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      winstorage::StorageFile*> StorageFileVectorCollection;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef winfoundtn::IAsyncOperation<StorageFileVectorCollection*>
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MultiFileAsyncOp;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called asynchronously when a single file picker is done.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT SinglePickerDone(SingleFileAsyncOp* async, AsyncStatus status);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called asynchronously when a multi file picker is done.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT MultiPickerDone(MultiFileAsyncOp* async, AsyncStatus status);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Composes a multi-file result string suitable for returning to a
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from a storage file collection.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static HRESULT ComposeMultiFileResult(StorageFileVectorCollection* files,
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        base::string16* result);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(OpenFilePickerSession);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SaveFilePickerSession : public FilePickerSessionBase {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit SaveFilePickerSession(OPENFILENAME* open_file_name);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT StartFilePicker() OVERRIDE;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef winfoundtn::IAsyncOperation<winstorage::StorageFile*>
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SaveFileAsyncOp;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called asynchronously when the save file picker is done.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT FilePickerDone(SaveFileAsyncOp* async, AsyncStatus status);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FilePickerSessionBase::FilePickerSessionBase(OPENFILENAME* open_file_name)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : open_file_name_(open_file_name),
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event_(true, false),
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      success_(false) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FilePickerSessionBase::Run() {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(globals.appview_msg_loop != NULL);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Post the picker request over to the metro thread.
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool posted = globals.appview_msg_loop->PostTask(FROM_HERE,
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&FilePickerSessionBase::DoFilePicker, base::Unretained(this)));
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!posted)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Wait for the file picker to complete.
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event_.Wait();
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return success_;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FilePickerSessionBase::DoFilePicker() {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The file picker will fail if spawned from a snapped application,
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so let's attempt to unsnap first if we're in that state.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = ChromeAppView::Unsnap();
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to unsnap for file picker, error 0x" << hr;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SUCCEEDED(hr))
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = StartFilePicker();
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to start file picker, error 0x"
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << std::hex << hr;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    event_.Signal();
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OpenFilePickerSession::OpenFilePickerSession(OPENFILENAME* open_file_name)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : FilePickerSessionBase(open_file_name) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT OpenFilePickerSession::SinglePickerDone(SingleFileAsyncOp* async,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                AsyncStatus status) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status == Completed) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mswr::ComPtr<winstorage::IStorageFile> file;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HRESULT hr = async->GetResults(file.GetAddressOf());
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (file) {
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mswr::ComPtr<winstorage::IStorageItem> storage_item;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (SUCCEEDED(hr))
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        hr = file.As(&storage_item);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mswrw::HString file_path;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (SUCCEEDED(hr))
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        hr = storage_item->get_Path(file_path.GetAddressOf());
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (SUCCEEDED(hr)) {
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        UINT32 path_len = 0;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const wchar_t* path_str =
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ::WindowsGetStringRawBuffer(file_path.Get(), &path_len);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the selected file name is longer than the supplied buffer,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // we return false as per GetOpenFileName documentation.
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (path_len < open_file_name_->nMaxFile) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::wcslcpy(open_file_name_->lpstrFile,
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        path_str,
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        open_file_name_->nMaxFile);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          success_ = true;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "NULL IStorageItem";
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event_.Signal();
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT OpenFilePickerSession::MultiPickerDone(MultiFileAsyncOp* async,
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 AsyncStatus status) {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status == Completed) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mswr::ComPtr<StorageFileVectorCollection> files;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HRESULT hr = async->GetResults(files.GetAddressOf());
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (files) {
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::string16 result;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (SUCCEEDED(hr))
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        hr = ComposeMultiFileResult(files.Get(), &result);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (SUCCEEDED(hr)) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (result.size() + 1 < open_file_name_->nMaxFile) {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Because the result has embedded nulls, we must memcpy.
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          memcpy(open_file_name_->lpstrFile,
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 result.c_str(),
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 (result.size() + 1) * sizeof(result[0]));
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          success_ = true;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "NULL StorageFileVectorCollection";
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event_.Signal();
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT OpenFilePickerSession::StartFilePicker() {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(globals.appview_msg_loop->BelongsToCurrentThread());
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(open_file_name_ != NULL);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswrw::HStringReference class_name(
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RuntimeClass_Windows_Storage_Pickers_FileOpenPicker);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the file picker.
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<winstorage::Pickers::IFileOpenPicker> picker;
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = ::Windows::Foundation::ActivateInstance(
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      class_name.Get(), picker.GetAddressOf());
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckHR(hr);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the file type filter
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<winfoundtn::Collections::IVector<HSTRING>> filter;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = picker->get_FileTypeFilter(filter.GetAddressOf());
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (open_file_name_->lpstrFilter == NULL) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = filter->Append(mswrw::HStringReference(L"*").Get());
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr))
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return hr;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The filter is a concatenation of zero terminated string pairs,
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // where each pair is {description, extension}. The concatenation ends
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // with a zero length string - e.g. a double zero terminator.
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* walk = open_file_name_->lpstrFilter;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (*walk != L'\0') {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Walk past the description.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      walk += wcslen(walk) + 1;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We should have an extension, but bail on malformed filters.
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (*walk == L'\0')
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // There can be a single extension, or a list of semicolon-separated ones.
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::vector<base::string16> extensions_win32_style;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_t extension_count = Tokenize(walk, L";", &extensions_win32_style);
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(extension_count, extensions_win32_style.size());
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Metro wants suffixes only, not patterns.
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mswrw::HString extension;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t i = 0; i < extensions_win32_style.size(); ++i) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (extensions_win32_style[i] == L"*.*") {
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // The wildcard filter is "*" for Metro. The string "*.*" produces
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // an "invalid parameter" error.
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          hr = extension.Set(L"*");
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Metro wants suffixes only, not patterns.
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::string16 ext =
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              base::FilePath(extensions_win32_style[i]).Extension();
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if ((ext.size() < 2) ||
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (ext.find_first_of(L"*?") != base::string16::npos)) {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            continue;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          hr = extension.Set(ext.c_str());
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (SUCCEEDED(hr))
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          hr = filter->Append(extension.Get());
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (FAILED(hr))
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return hr;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Walk past the extension.
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      walk += wcslen(walk) + 1;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Spin up a single or multi picker as appropriate.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (open_file_name_->Flags & OFN_ALLOWMULTISELECT) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mswr::ComPtr<MultiFileAsyncOp> completion;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = picker->PickMultipleFilesAsync(&completion);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr))
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return hr;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Create the callback method.
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    typedef winfoundtn::IAsyncOperationCompletedHandler<
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        StorageFileVectorCollection*> HandlerDoneType;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this, &OpenFilePickerSession::MultiPickerDone));
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(handler.Get() != NULL);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = completion->put_Completed(handler.Get());
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mswr::ComPtr<SingleFileAsyncOp> completion;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = picker->PickSingleFileAsync(&completion);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr))
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return hr;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Create the callback method.
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    typedef winfoundtn::IAsyncOperationCompletedHandler<
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        winstorage::StorageFile*> HandlerDoneType;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this, &OpenFilePickerSession::SinglePickerDone));
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(handler.Get() != NULL);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = completion->put_Completed(handler.Get());
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT OpenFilePickerSession::ComposeMultiFileResult(
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    StorageFileVectorCollection* files, base::string16* result) {
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(files != NULL);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(result != NULL);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Empty the output string.
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->clear();
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned int num_files = 0;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = files->get_Size(&num_files);
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we return an error on an empty collection.
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (num_files == 0) {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "Empty collection on input.";
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_UNEXPECTED;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This stores the base path that should be the parent of all the files.
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath base_path;
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iterate through the collection and append the file paths to the result.
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (unsigned int i = 0; i < num_files; ++i) {
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mswr::ComPtr<winstorage::IStorageFile> file;
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = files->GetAt(i, file.GetAddressOf());
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr))
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return hr;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mswr::ComPtr<winstorage::IStorageItem> storage_item;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = file.As(&storage_item);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr))
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return hr;
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mswrw::HString file_path_str;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = storage_item->get_Path(file_path_str.GetAddressOf());
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr))
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return hr;
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath file_path(MakeStdWString(file_path_str.Get()));
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (base_path.empty()) {
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(result->empty());
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base_path = file_path.DirName();
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Append the path, including the terminating zero.
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We do this only for the first file.
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result->append(base_path.value().c_str(), base_path.value().size() + 1);
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!result->empty());
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!base_path.empty());
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(base_path == file_path.DirName());
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Append the base name, including the terminating zero.
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath base_name = file_path.BaseName();
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->append(base_name.value().c_str(), base_name.value().size() + 1);
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!result->empty());
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SaveFilePickerSession::SaveFilePickerSession(OPENFILENAME* open_file_name)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : FilePickerSessionBase(open_file_name) {
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT SaveFilePickerSession::StartFilePicker() {
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(globals.appview_msg_loop->BelongsToCurrentThread());
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(open_file_name_ != NULL);
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswrw::HStringReference class_name(
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RuntimeClass_Windows_Storage_Pickers_FileSavePicker);
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the file picker.
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<winstorage::Pickers::IFileSavePicker> picker;
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = ::Windows::Foundation::ActivateInstance(
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      class_name.Get(), picker.GetAddressOf());
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckHR(hr);
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef winfoundtn::Collections::IMap<HSTRING, StringVectorItf*>
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      StringVectorMap;
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<StringVectorMap> choices;
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = picker->get_FileTypeChoices(choices.GetAddressOf());
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (open_file_name_->lpstrFilter) {
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The filter is a concatenation of zero terminated string pairs,
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // where each pair is {description, extension list}. The concatenation ends
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // with a zero length string - e.g. a double zero terminator.
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* walk = open_file_name_->lpstrFilter;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (*walk != L'\0') {
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mswrw::HString description;
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hr = description.Set(walk);
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (FAILED(hr))
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return hr;
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Walk past the description.
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      walk += wcslen(walk) + 1;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We should have an extension, but bail on malformed filters.
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (*walk == L'\0')
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // There can be a single extension, or a list of semicolon-separated ones.
4795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::vector<base::string16> extensions_win32_style;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_t extension_count = Tokenize(walk, L";", &extensions_win32_style);
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(extension_count, extensions_win32_style.size());
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Metro wants suffixes only, not patterns.  Also, metro does not support
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the all files ("*") pattern in the save picker.
4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::vector<base::string16> extensions;
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t i = 0; i < extensions_win32_style.size(); ++i) {
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::string16 ext =
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            base::FilePath(extensions_win32_style[i]).Extension();
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ((ext.size() < 2) ||
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            (ext.find_first_of(L"*?") != base::string16::npos))
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          continue;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        extensions.push_back(ext);
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!extensions.empty()) {
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Convert to a Metro collection class.
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mswr::ComPtr<StringVectorItf> list;
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        hr = mswr::MakeAndInitialize<StringVectorImpl>(
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            list.GetAddressOf(), extensions);
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (FAILED(hr))
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return hr;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Finally set the filter.
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        boolean replaced = FALSE;
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        hr = choices->Insert(description.Get(), list.Get(), &replaced);
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (FAILED(hr))
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return hr;
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK_EQ(FALSE, replaced);
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Walk past the extension(s).
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      walk += wcslen(walk) + 1;
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The save picker requires at least one choice.  Callers are strongly advised
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to provide sensible choices.  If none were given, fallback to .dat.
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 num_choices = 0;
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = choices->get_Size(&num_choices);
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (num_choices == 0) {
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mswrw::HString description;
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(grt): Get a properly translated string.  This can't be done from
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // within metro_driver.  Consider preprocessing the filter list in Chrome
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // land to ensure it has this entry if all others are patterns.  In that
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // case, this whole block of code can be removed.
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = description.Set(L"Data File");
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr))
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return hr;
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mswr::ComPtr<StringVectorItf> list;
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = mswr::MakeAndInitialize<StringVectorImpl>(
5355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        list.GetAddressOf(), std::vector<base::string16>(1, L".dat"));
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr))
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return hr;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    boolean replaced = FALSE;
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = choices->Insert(description.Get(), list.Get(), &replaced);
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr))
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return hr;
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(FALSE, replaced);
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (open_file_name_->lpstrFile != NULL) {
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = picker->put_SuggestedFileName(
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mswrw::HStringReference(
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const_cast<const wchar_t*>(open_file_name_->lpstrFile)).Get());
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FAILED(hr))
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return hr;
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<SaveFileAsyncOp> completion;
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = picker->PickSaveFileAsync(&completion);
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the callback method.
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef winfoundtn::IAsyncOperationCompletedHandler<
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      winstorage::StorageFile*> HandlerDoneType;
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this, &SaveFilePickerSession::FilePickerDone));
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(handler.Get() != NULL);
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = completion->put_Completed(handler.Get());
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT SaveFilePickerSession::FilePickerDone(SaveFileAsyncOp* async,
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              AsyncStatus status) {
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status == Completed) {
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mswr::ComPtr<winstorage::IStorageFile> file;
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HRESULT hr = async->GetResults(file.GetAddressOf());
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (file) {
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mswr::ComPtr<winstorage::IStorageItem> storage_item;
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (SUCCEEDED(hr))
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        hr = file.As(&storage_item);
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mswrw::HString file_path;
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (SUCCEEDED(hr))
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        hr = storage_item->get_Path(file_path.GetAddressOf());
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (SUCCEEDED(hr)) {
5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::string16 path_str = MakeStdWString(file_path.Get());
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the selected file name is longer than the supplied buffer,
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // we return false as per GetOpenFileName documentation.
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (path_str.size() < open_file_name_->nMaxFile) {
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::wcslcpy(open_file_name_->lpstrFile,
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        path_str.c_str(),
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        open_file_name_->nMaxFile);
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          success_ = true;
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "NULL IStorageItem";
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event_.Signal();
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL MetroGetOpenFileName(OPENFILENAME* open_file_name) {
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OpenFilePickerSession session(open_file_name);
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return session.Run();
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL MetroGetSaveFileName(OPENFILENAME* open_file_name) {
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveFilePickerSession session(open_file_name);
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return session.Run();
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
622