| Index: win8/metro_driver/file_picker_ash.cc
|
| diff --git a/win8/metro_driver/file_picker_ash.cc b/win8/metro_driver/file_picker_ash.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..31e699d0ed11909a4145493e1acfb5bc793c0ddf
|
| --- /dev/null
|
| +++ b/win8/metro_driver/file_picker_ash.cc
|
| @@ -0,0 +1,619 @@
|
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include <stddef.h>
|
| +#include <stdint.h>
|
| +
|
| +#include "stdafx.h"
|
| +#include "win8/metro_driver/file_picker_ash.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/logging.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/strings/string_split.h"
|
| +#include "base/strings/string_util.h"
|
| +#include "base/synchronization/waitable_event.h"
|
| +#include "base/win/scoped_comptr.h"
|
| +#include "ui/metro_viewer/metro_viewer_messages.h"
|
| +#include "win8/metro_driver/chrome_app_view_ash.h"
|
| +#include "win8/metro_driver/winrt_utils.h"
|
| +
|
| +namespace {
|
| +
|
| +typedef winfoundtn::Collections::IVector<HSTRING> StringVectorItf;
|
| +
|
| +// TODO(siggi): Complete this implementation and move it to a common place.
|
| +class StringVectorImpl : public mswr::RuntimeClass<StringVectorItf> {
|
| + public:
|
| + ~StringVectorImpl() override {
|
| + std::for_each(strings_.begin(), strings_.end(), ::WindowsDeleteString);
|
| + }
|
| +
|
| + HRESULT RuntimeClassInitialize(const std::vector<base::string16>& list) {
|
| + for (size_t i = 0; i < list.size(); ++i)
|
| + strings_.push_back(MakeHString(list[i]));
|
| +
|
| + return S_OK;
|
| + }
|
| +
|
| + // IVector<HSTRING> implementation.
|
| + STDMETHOD(GetAt)(unsigned index, HSTRING* item) override {
|
| + if (index >= strings_.size())
|
| + return E_INVALIDARG;
|
| +
|
| + return ::WindowsDuplicateString(strings_[index], item);
|
| + }
|
| + STDMETHOD(get_Size)(unsigned* size) override {
|
| + if (strings_.size() > UINT_MAX)
|
| + return E_UNEXPECTED;
|
| + *size = static_cast<unsigned>(strings_.size());
|
| + return S_OK;
|
| + }
|
| + STDMETHOD(GetView)(
|
| + winfoundtn::Collections::IVectorView<HSTRING>** view) override {
|
| + return E_NOTIMPL;
|
| + }
|
| + STDMETHOD(IndexOf)(HSTRING value, unsigned* index, boolean* found) override {
|
| + return E_NOTIMPL;
|
| + }
|
| +
|
| + // write methods
|
| + STDMETHOD(SetAt)(unsigned index, HSTRING item) override { return E_NOTIMPL; }
|
| + STDMETHOD(InsertAt)(unsigned index, HSTRING item) override {
|
| + return E_NOTIMPL;
|
| + }
|
| + STDMETHOD(RemoveAt)(unsigned index) override { return E_NOTIMPL; }
|
| + STDMETHOD(Append)(HSTRING item) override { return E_NOTIMPL; }
|
| + STDMETHOD(RemoveAtEnd)() override { return E_NOTIMPL; }
|
| + STDMETHOD(Clear)() override { return E_NOTIMPL; }
|
| +
|
| + private:
|
| + std::vector<HSTRING> strings_;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +FilePickerSessionBase::~FilePickerSessionBase() {
|
| +}
|
| +
|
| +bool FilePickerSessionBase::Run() {
|
| + if (!DoFilePicker())
|
| + return false;
|
| + return success_;
|
| +}
|
| +
|
| +FilePickerSessionBase::FilePickerSessionBase(ChromeAppViewAsh* app_view,
|
| + const base::string16& title,
|
| + const base::string16& filter,
|
| + const base::FilePath& default_path)
|
| + : success_(false),
|
| + title_(title),
|
| + filter_(filter),
|
| + default_path_(default_path),
|
| + app_view_(app_view) {
|
| +}
|
| +
|
| +bool FilePickerSessionBase::DoFilePicker() {
|
| + // The file picker will fail if spawned from a snapped application,
|
| + // so let's attempt to unsnap first if we're in that state.
|
| + HRESULT hr = ChromeAppViewAsh::Unsnap();
|
| + if (FAILED(hr)) {
|
| + LOG(ERROR) << "Failed to unsnap for file picker, error 0x" << hr;
|
| + return false;
|
| + }
|
| + hr = StartFilePicker();
|
| + if (FAILED(hr)) {
|
| + LOG(ERROR) << "Failed to start file picker, error 0x"
|
| + << std::hex << hr;
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +OpenFilePickerSession::OpenFilePickerSession(
|
| + ChromeAppViewAsh* app_view,
|
| + const base::string16& title,
|
| + const base::string16& filter,
|
| + const base::FilePath& default_path,
|
| + bool allow_multi_select)
|
| + : FilePickerSessionBase(app_view, title, filter, default_path),
|
| + allow_multi_select_(allow_multi_select) {
|
| +}
|
| +
|
| +OpenFilePickerSession::~OpenFilePickerSession() {
|
| +}
|
| +
|
| +HRESULT OpenFilePickerSession::SinglePickerDone(SingleFileAsyncOp* async,
|
| + AsyncStatus status) {
|
| + if (status == Completed) {
|
| + mswr::ComPtr<winstorage::IStorageFile> file;
|
| + HRESULT hr = async->GetResults(file.GetAddressOf());
|
| +
|
| + if (file) {
|
| + mswr::ComPtr<winstorage::IStorageItem> storage_item;
|
| + if (SUCCEEDED(hr))
|
| + hr = file.As(&storage_item);
|
| +
|
| + mswrw::HString file_path;
|
| + if (SUCCEEDED(hr))
|
| + hr = storage_item->get_Path(file_path.GetAddressOf());
|
| +
|
| + if (SUCCEEDED(hr)) {
|
| + UINT32 path_len = 0;
|
| + const wchar_t* path_str =
|
| + ::WindowsGetStringRawBuffer(file_path.Get(), &path_len);
|
| +
|
| + result_ = path_str;
|
| + success_ = true;
|
| + }
|
| + } else {
|
| + LOG(ERROR) << "NULL IStorageItem";
|
| + }
|
| + } else {
|
| + LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
|
| + }
|
| + app_view_->OnOpenFileCompleted(this, success_);
|
| + return S_OK;
|
| +}
|
| +
|
| +HRESULT OpenFilePickerSession::MultiPickerDone(MultiFileAsyncOp* async,
|
| + AsyncStatus status) {
|
| + if (status == Completed) {
|
| + mswr::ComPtr<StorageFileVectorCollection> files;
|
| + HRESULT hr = async->GetResults(files.GetAddressOf());
|
| +
|
| + if (files) {
|
| + base::string16 result;
|
| + if (SUCCEEDED(hr))
|
| + hr = ComposeMultiFileResult(files.Get(), &result);
|
| +
|
| + if (SUCCEEDED(hr)) {
|
| + success_ = true;
|
| + // The code below has been copied from the
|
| + // SelectFileDialogImpl::RunOpenMultiFileDialog function in
|
| + // select_file_dialog_win.cc.
|
| + // TODO(ananta)
|
| + // Consolidate this into a common place.
|
| + const wchar_t* selection = result.c_str();
|
| + std::vector<base::FilePath> files;
|
| +
|
| + while (*selection) { // Empty string indicates end of list.
|
| + files.push_back(base::FilePath(selection));
|
| + // Skip over filename and null-terminator.
|
| + selection += files.back().value().length() + 1;
|
| + }
|
| + if (files.empty()) {
|
| + success_ = false;
|
| + } else if (files.size() == 1) {
|
| + // When there is one file, it contains the path and filename.
|
| + filenames_ = files;
|
| + } else if (files.size() > 1) {
|
| + // Otherwise, the first string is the path, and the remainder are
|
| + // filenames.
|
| + std::vector<base::FilePath>::iterator path = files.begin();
|
| + for (std::vector<base::FilePath>::iterator file = path + 1;
|
| + file != files.end(); ++file) {
|
| + filenames_.push_back(path->Append(*file));
|
| + }
|
| + }
|
| + }
|
| + } else {
|
| + LOG(ERROR) << "NULL StorageFileVectorCollection";
|
| + }
|
| + } else {
|
| + LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
|
| + }
|
| + app_view_->OnOpenFileCompleted(this, success_);
|
| + return S_OK;
|
| +}
|
| +
|
| +HRESULT OpenFilePickerSession::StartFilePicker() {
|
| + mswrw::HStringReference class_name(
|
| + RuntimeClass_Windows_Storage_Pickers_FileOpenPicker);
|
| +
|
| + // Create the file picker.
|
| + mswr::ComPtr<winstorage::Pickers::IFileOpenPicker> picker;
|
| + HRESULT hr = ::Windows::Foundation::ActivateInstance(
|
| + class_name.Get(), picker.GetAddressOf());
|
| + CheckHR(hr);
|
| +
|
| + // Set the file type filter
|
| + mswr::ComPtr<winfoundtn::Collections::IVector<HSTRING>> filter;
|
| + hr = picker->get_FileTypeFilter(filter.GetAddressOf());
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + if (filter_.empty()) {
|
| + hr = filter->Append(mswrw::HStringReference(L"*").Get());
|
| + if (FAILED(hr))
|
| + return hr;
|
| + } else {
|
| + // The filter is a concatenation of zero terminated string pairs,
|
| + // where each pair is {description, extension}. The concatenation ends
|
| + // with a zero length string - e.g. a double zero terminator.
|
| + const wchar_t* walk = filter_.c_str();
|
| + while (*walk != L'\0') {
|
| + // Walk past the description.
|
| + walk += wcslen(walk) + 1;
|
| +
|
| + // We should have an extension, but bail on malformed filters.
|
| + if (*walk == L'\0')
|
| + break;
|
| +
|
| + // There can be a single extension, or a list of semicolon-separated ones.
|
| + std::vector<base::string16> extensions_win32_style = base::SplitString(
|
| + walk, L";", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
| +
|
| + // Metro wants suffixes only, not patterns.
|
| + mswrw::HString extension;
|
| + for (size_t i = 0; i < extensions_win32_style.size(); ++i) {
|
| + if (extensions_win32_style[i] == L"*.*") {
|
| + // The wildcard filter is "*" for Metro. The string "*.*" produces
|
| + // an "invalid parameter" error.
|
| + hr = extension.Set(L"*");
|
| + } else {
|
| + // Metro wants suffixes only, not patterns.
|
| + base::string16 ext =
|
| + base::FilePath(extensions_win32_style[i]).Extension();
|
| + if ((ext.size() < 2) ||
|
| + (ext.find_first_of(L"*?") != base::string16::npos)) {
|
| + continue;
|
| + }
|
| + hr = extension.Set(ext.c_str());
|
| + }
|
| + if (SUCCEEDED(hr))
|
| + hr = filter->Append(extension.Get());
|
| + if (FAILED(hr))
|
| + return hr;
|
| + }
|
| +
|
| + // Walk past the extension.
|
| + walk += wcslen(walk) + 1;
|
| + }
|
| + }
|
| +
|
| + // Spin up a single or multi picker as appropriate.
|
| + if (allow_multi_select_) {
|
| + mswr::ComPtr<MultiFileAsyncOp> completion;
|
| + hr = picker->PickMultipleFilesAsync(&completion);
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + // Create the callback method.
|
| + typedef winfoundtn::IAsyncOperationCompletedHandler<
|
| + StorageFileVectorCollection*> HandlerDoneType;
|
| + mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
|
| + this, &OpenFilePickerSession::MultiPickerDone));
|
| + DCHECK(handler.Get() != NULL);
|
| + hr = completion->put_Completed(handler.Get());
|
| +
|
| + return hr;
|
| + } else {
|
| + mswr::ComPtr<SingleFileAsyncOp> completion;
|
| + hr = picker->PickSingleFileAsync(&completion);
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + // Create the callback method.
|
| + typedef winfoundtn::IAsyncOperationCompletedHandler<
|
| + winstorage::StorageFile*> HandlerDoneType;
|
| + mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
|
| + this, &OpenFilePickerSession::SinglePickerDone));
|
| + DCHECK(handler.Get() != NULL);
|
| + hr = completion->put_Completed(handler.Get());
|
| +
|
| + return hr;
|
| + }
|
| +}
|
| +
|
| +HRESULT OpenFilePickerSession::ComposeMultiFileResult(
|
| + StorageFileVectorCollection* files, base::string16* result) {
|
| + DCHECK(files != NULL);
|
| + DCHECK(result != NULL);
|
| +
|
| + // Empty the output string.
|
| + result->clear();
|
| +
|
| + unsigned int num_files = 0;
|
| + HRESULT hr = files->get_Size(&num_files);
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + // Make sure we return an error on an empty collection.
|
| + if (num_files == 0) {
|
| + DLOG(ERROR) << "Empty collection on input.";
|
| + return E_UNEXPECTED;
|
| + }
|
| +
|
| + // This stores the base path that should be the parent of all the files.
|
| + base::FilePath base_path;
|
| +
|
| + // Iterate through the collection and append the file paths to the result.
|
| + for (unsigned int i = 0; i < num_files; ++i) {
|
| + mswr::ComPtr<winstorage::IStorageFile> file;
|
| + hr = files->GetAt(i, file.GetAddressOf());
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + mswr::ComPtr<winstorage::IStorageItem> storage_item;
|
| + hr = file.As(&storage_item);
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + mswrw::HString file_path_str;
|
| + hr = storage_item->get_Path(file_path_str.GetAddressOf());
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + base::FilePath file_path(MakeStdWString(file_path_str.Get()));
|
| + if (base_path.empty()) {
|
| + DCHECK(result->empty());
|
| + base_path = file_path.DirName();
|
| +
|
| + // Append the path, including the terminating zero.
|
| + // We do this only for the first file.
|
| + result->append(base_path.value().c_str(), base_path.value().size() + 1);
|
| + }
|
| + DCHECK(!result->empty());
|
| + DCHECK(!base_path.empty());
|
| + DCHECK(base_path == file_path.DirName());
|
| +
|
| + // Append the base name, including the terminating zero.
|
| + base::FilePath base_name = file_path.BaseName();
|
| + result->append(base_name.value().c_str(), base_name.value().size() + 1);
|
| + }
|
| +
|
| + DCHECK(!result->empty());
|
| +
|
| + return S_OK;
|
| +}
|
| +
|
| +SaveFilePickerSession::SaveFilePickerSession(
|
| + ChromeAppViewAsh* app_view,
|
| + const MetroViewerHostMsg_SaveAsDialogParams& params)
|
| + : FilePickerSessionBase(app_view,
|
| + params.title,
|
| + params.filter,
|
| + params.suggested_name),
|
| + filter_index_(params.filter_index) {
|
| +}
|
| +
|
| +int SaveFilePickerSession::filter_index() const {
|
| + // TODO(ananta)
|
| + // Add support for returning the correct filter index. This does not work in
|
| + // regular Chrome metro on trunk as well.
|
| + // BUG: https://code.google.com/p/chromium/issues/detail?id=172704
|
| + return filter_index_;
|
| +}
|
| +
|
| +HRESULT SaveFilePickerSession::StartFilePicker() {
|
| + mswrw::HStringReference class_name(
|
| + RuntimeClass_Windows_Storage_Pickers_FileSavePicker);
|
| +
|
| + // Create the file picker.
|
| + mswr::ComPtr<winstorage::Pickers::IFileSavePicker> picker;
|
| + HRESULT hr = ::Windows::Foundation::ActivateInstance(
|
| + class_name.Get(), picker.GetAddressOf());
|
| + CheckHR(hr);
|
| +
|
| + typedef winfoundtn::Collections::IMap<HSTRING, StringVectorItf*>
|
| + StringVectorMap;
|
| + mswr::ComPtr<StringVectorMap> choices;
|
| + hr = picker->get_FileTypeChoices(choices.GetAddressOf());
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + if (!filter_.empty()) {
|
| + // The filter is a concatenation of zero terminated string pairs,
|
| + // where each pair is {description, extension list}. The concatenation ends
|
| + // with a zero length string - e.g. a double zero terminator.
|
| + const wchar_t* walk = filter_.c_str();
|
| + while (*walk != L'\0') {
|
| + mswrw::HString description;
|
| + hr = description.Set(walk);
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + // Walk past the description.
|
| + walk += wcslen(walk) + 1;
|
| +
|
| + // We should have an extension, but bail on malformed filters.
|
| + if (*walk == L'\0')
|
| + break;
|
| +
|
| + // There can be a single extension, or a list of semicolon-separated ones.
|
| + std::vector<base::string16> extensions_win32_style = base::SplitString(
|
| + walk, L";", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
| +
|
| + // Metro wants suffixes only, not patterns. Also, metro does not support
|
| + // the all files ("*") pattern in the save picker.
|
| + std::vector<base::string16> extensions;
|
| + for (size_t i = 0; i < extensions_win32_style.size(); ++i) {
|
| + base::string16 ext =
|
| + base::FilePath(extensions_win32_style[i]).Extension();
|
| + if ((ext.size() < 2) ||
|
| + (ext.find_first_of(L"*?") != base::string16::npos))
|
| + continue;
|
| + extensions.push_back(ext);
|
| + }
|
| +
|
| + if (!extensions.empty()) {
|
| + // Convert to a Metro collection class.
|
| + mswr::ComPtr<StringVectorItf> list;
|
| + hr = mswr::MakeAndInitialize<StringVectorImpl>(
|
| + list.GetAddressOf(), extensions);
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + // Finally set the filter.
|
| + boolean replaced = FALSE;
|
| + hr = choices->Insert(description.Get(), list.Get(), &replaced);
|
| + if (FAILED(hr))
|
| + return hr;
|
| + DCHECK_EQ(FALSE, replaced);
|
| + }
|
| +
|
| + // Walk past the extension(s).
|
| + walk += wcslen(walk) + 1;
|
| + }
|
| + }
|
| +
|
| + // The save picker requires at least one choice. Callers are strongly advised
|
| + // to provide sensible choices. If none were given, fallback to .dat.
|
| + uint32_t num_choices = 0;
|
| + hr = choices->get_Size(&num_choices);
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + if (num_choices == 0) {
|
| + mswrw::HString description;
|
| + // TODO(grt): Get a properly translated string. This can't be done from
|
| + // within metro_driver. Consider preprocessing the filter list in Chrome
|
| + // land to ensure it has this entry if all others are patterns. In that
|
| + // case, this whole block of code can be removed.
|
| + hr = description.Set(L"Data File");
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + mswr::ComPtr<StringVectorItf> list;
|
| + hr = mswr::MakeAndInitialize<StringVectorImpl>(
|
| + list.GetAddressOf(), std::vector<base::string16>(1, L".dat"));
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + boolean replaced = FALSE;
|
| + hr = choices->Insert(description.Get(), list.Get(), &replaced);
|
| + if (FAILED(hr))
|
| + return hr;
|
| + DCHECK_EQ(FALSE, replaced);
|
| + }
|
| +
|
| + if (!default_path_.empty()) {
|
| + base::string16 file_part = default_path_.BaseName().value();
|
| + // If the suggested_name is a root directory, then don't set it as the
|
| + // suggested name.
|
| + if (file_part.size() == 1 && file_part[0] == L'\\')
|
| + file_part.clear();
|
| + hr = picker->put_SuggestedFileName(
|
| + mswrw::HStringReference(file_part.c_str()).Get());
|
| + if (FAILED(hr))
|
| + return hr;
|
| + }
|
| +
|
| + mswr::ComPtr<SaveFileAsyncOp> completion;
|
| + hr = picker->PickSaveFileAsync(&completion);
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + // Create the callback method.
|
| + typedef winfoundtn::IAsyncOperationCompletedHandler<
|
| + winstorage::StorageFile*> HandlerDoneType;
|
| + mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
|
| + this, &SaveFilePickerSession::FilePickerDone));
|
| + DCHECK(handler.Get() != NULL);
|
| + hr = completion->put_Completed(handler.Get());
|
| +
|
| + return hr;
|
| +}
|
| +
|
| +HRESULT SaveFilePickerSession::FilePickerDone(SaveFileAsyncOp* async,
|
| + AsyncStatus status) {
|
| + if (status == Completed) {
|
| + mswr::ComPtr<winstorage::IStorageFile> file;
|
| + HRESULT hr = async->GetResults(file.GetAddressOf());
|
| +
|
| + if (file) {
|
| + mswr::ComPtr<winstorage::IStorageItem> storage_item;
|
| + if (SUCCEEDED(hr))
|
| + hr = file.As(&storage_item);
|
| +
|
| + mswrw::HString file_path;
|
| + if (SUCCEEDED(hr))
|
| + hr = storage_item->get_Path(file_path.GetAddressOf());
|
| +
|
| + if (SUCCEEDED(hr)) {
|
| + base::string16 path_str = MakeStdWString(file_path.Get());
|
| + result_ = path_str;
|
| + success_ = true;
|
| + }
|
| + } else {
|
| + LOG(ERROR) << "NULL IStorageItem";
|
| + }
|
| + } else {
|
| + LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
|
| + }
|
| + app_view_->OnSaveFileCompleted(this, success_);
|
| + return S_OK;
|
| +}
|
| +
|
| +FolderPickerSession::FolderPickerSession(ChromeAppViewAsh* app_view,
|
| + const base::string16& title)
|
| + : FilePickerSessionBase(app_view, title, L"", base::FilePath()) {
|
| +}
|
| +
|
| +HRESULT FolderPickerSession::StartFilePicker() {
|
| + mswrw::HStringReference class_name(
|
| + RuntimeClass_Windows_Storage_Pickers_FolderPicker);
|
| +
|
| + // Create the folder picker.
|
| + mswr::ComPtr<winstorage::Pickers::IFolderPicker> picker;
|
| + HRESULT hr = ::Windows::Foundation::ActivateInstance(
|
| + class_name.Get(), picker.GetAddressOf());
|
| + CheckHR(hr);
|
| +
|
| + // Set the file type filter
|
| + mswr::ComPtr<winfoundtn::Collections::IVector<HSTRING>> filter;
|
| + hr = picker->get_FileTypeFilter(filter.GetAddressOf());
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + hr = filter->Append(mswrw::HStringReference(L"*").Get());
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + mswr::ComPtr<FolderPickerAsyncOp> completion;
|
| + hr = picker->PickSingleFolderAsync(&completion);
|
| + if (FAILED(hr))
|
| + return hr;
|
| +
|
| + // Create the callback method.
|
| + typedef winfoundtn::IAsyncOperationCompletedHandler<
|
| + winstorage::StorageFolder*> HandlerDoneType;
|
| + mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
|
| + this, &FolderPickerSession::FolderPickerDone));
|
| + DCHECK(handler.Get() != NULL);
|
| + hr = completion->put_Completed(handler.Get());
|
| + return hr;
|
| +}
|
| +
|
| +HRESULT FolderPickerSession::FolderPickerDone(FolderPickerAsyncOp* async,
|
| + AsyncStatus status) {
|
| + if (status == Completed) {
|
| + mswr::ComPtr<winstorage::IStorageFolder> folder;
|
| + HRESULT hr = async->GetResults(folder.GetAddressOf());
|
| +
|
| + if (folder) {
|
| + mswr::ComPtr<winstorage::IStorageItem> storage_item;
|
| + if (SUCCEEDED(hr))
|
| + hr = folder.As(&storage_item);
|
| +
|
| + mswrw::HString file_path;
|
| + if (SUCCEEDED(hr))
|
| + hr = storage_item->get_Path(file_path.GetAddressOf());
|
| +
|
| + if (SUCCEEDED(hr)) {
|
| + base::string16 path_str = MakeStdWString(file_path.Get());
|
| + result_ = path_str;
|
| + success_ = true;
|
| + }
|
| + } else {
|
| + LOG(ERROR) << "NULL IStorageItem";
|
| + }
|
| + } else {
|
| + LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
|
| + }
|
| + app_view_->OnFolderPickerCompleted(this, success_);
|
| + return S_OK;
|
| +}
|
| +
|
|
|