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