From 52e09741034fed7ca09d8aa436a058c6170d1583 Mon Sep 17 00:00:00 2001 From: DinahK-2SO <116714259+DinahK-2SO@users.noreply.github.com> Date: Tue, 30 Sep 2025 02:17:04 +0800 Subject: [PATCH 1/4] new functionalities --- ...TerminalVelocityFeatures-StoragePickers2.h | 32 ++++ ...rminalVelocityFeatures-StoragePickers2.xml | 20 +++ dev/Interop/StoragePickers/FileOpenPicker.cpp | 37 ++++- dev/Interop/StoragePickers/FileOpenPicker.h | 16 +- dev/Interop/StoragePickers/FileSavePicker.cpp | 21 ++- dev/Interop/StoragePickers/FileSavePicker.h | 4 + .../StoragePickers/FileTypeChoicesMap.cpp | 8 +- .../StoragePickers/FileTypeChoicesMap.h | 4 +- .../StoragePickers/FileTypeFilterVector.cpp | 2 +- dev/Interop/StoragePickers/FolderPicker.cpp | 27 +++- dev/Interop/StoragePickers/FolderPicker.h | 8 + .../Microsoft.Windows.Storage.Pickers.idl | 22 ++- dev/Interop/StoragePickers/PickerCommon.cpp | 137 ++++++++++++++++-- dev/Interop/StoragePickers/PickerCommon.h | 15 +- .../StoragePickersTests/PickerCommonTests.cpp | 65 ++++++++- .../StoragePickersTests.cpp | 20 +++ 16 files changed, 396 insertions(+), 42 deletions(-) create mode 100644 dev/Common/TerminalVelocityFeatures-StoragePickers2.h create mode 100644 dev/Common/TerminalVelocityFeatures-StoragePickers2.xml diff --git a/dev/Common/TerminalVelocityFeatures-StoragePickers2.h b/dev/Common/TerminalVelocityFeatures-StoragePickers2.h new file mode 100644 index 0000000000..e44c4cfaa5 --- /dev/null +++ b/dev/Common/TerminalVelocityFeatures-StoragePickers2.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +// THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT IT + +// INPUT FILE: dev\Common\TerminalVelocityFeatures-StoragePickers2.xml +// OPTIONS: -Channel Experimental -Language C++ -Namespace Microsoft.Windows.Storage.Pickers -Path dev\Common\TerminalVelocityFeatures-StoragePickers2.xml -Output dev\Common\TerminalVelocityFeatures-StoragePickers2.h + +#if defined(__midlrt) +namespace features +{ + feature_name Feature_StoragePickers2 = { DisabledByDefault, FALSE }; +} +#endif // defined(__midlrt) + +// Feature constants +#define WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_STORAGE_PICKERS_FEATURE_STORAGEPICKERS2_ENABLED 1 + +#if defined(__cplusplus) + +namespace Microsoft::Windows::Storage::Pickers +{ + +__pragma(detect_mismatch("ODR_violation_WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_STORAGE_PICKERS_FEATURE_STORAGEPICKERS2_ENABLED_mismatch", "AlwaysEnabled")) +struct Feature_StoragePickers2 +{ + static constexpr bool IsEnabled() { return WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_STORAGE_PICKERS_FEATURE_STORAGEPICKERS2_ENABLED == 1; } +}; + +} // namespace Microsoft.Windows.Storage.Pickers + +#endif // defined(__cplusplus) diff --git a/dev/Common/TerminalVelocityFeatures-StoragePickers2.xml b/dev/Common/TerminalVelocityFeatures-StoragePickers2.xml new file mode 100644 index 0000000000..b878a8128f --- /dev/null +++ b/dev/Common/TerminalVelocityFeatures-StoragePickers2.xml @@ -0,0 +1,20 @@ + + + + + + + + + + Feature_StoragePickers2 + New functionalities in StoragePickers for the WindowsAppRuntime: SuggestedDefaultFolder, FileTypeChoices + AlwaysEnabled + + Preview + Stable + + + diff --git a/dev/Interop/StoragePickers/FileOpenPicker.cpp b/dev/Interop/StoragePickers/FileOpenPicker.cpp index 775e6411ab..3a8c108261 100644 --- a/dev/Interop/StoragePickers/FileOpenPicker.cpp +++ b/dev/Interop/StoragePickers/FileOpenPicker.cpp @@ -49,17 +49,46 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation PickerCommon::ValidateStringNoEmbeddedNulls(value); m_commitButtonText = value; } - winrt::Windows::Foundation::Collections::IVector FileOpenPicker::FileTypeFilter() + winrt::Windows::Foundation::Collections::IMap> FileOpenPicker::FileTypeChoices() + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + return m_fileTypeChoices; + } + winrt::Windows::Foundation::Collections::IVector FileOpenPicker::FileTypeFilter() { return m_fileTypeFilter; } + winrt::hstring FileOpenPicker::SuggestedFolder() + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + return m_suggestedFolder; + } + void FileOpenPicker::SuggestedFolder(winrt::hstring const& value) + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + PickerCommon::ValidateFolderPath(value, "SuggestedFolder"); + m_suggestedFolder = value; + } + winrt::hstring FileOpenPicker::SuggestedStartFolder() + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + return m_suggestedStartFolder; + } + void FileOpenPicker::SuggestedStartFolder(winrt::hstring const& value) + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + PickerCommon::ValidateFolderPath(value, "SuggestedStartFolder"); + m_suggestedStartFolder = value; + } void FileOpenPicker::CaptureParameters(PickerCommon::PickerParameters& parameters) { parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); parameters.CommitButtonText = m_commitButtonText; - parameters.PickerLocationId = m_suggestedStartLocation; - parameters.CaptureFilterSpec(m_fileTypeFilter.GetView()); + parameters.SuggestedFolder = m_suggestedFolder; + parameters.SuggestedStartLocation = m_suggestedStartLocation; + parameters.SuggestedStartFolder = m_suggestedStartFolder; + parameters.CaptureFilterSpecData(m_fileTypeFilter.GetView(), m_fileTypeChoices.GetView()); } winrt::Windows::Foundation::IAsyncOperation FileOpenPicker::PickSingleFileAsync() @@ -87,7 +116,6 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation auto dialog = create_instance(CLSID_FileOpenDialog, CLSCTX_INPROC_SERVER); parameters.ConfigureDialog(dialog); - check_hresult(dialog->SetFileTypeIndex(parameters.FileTypeFilterPara.size())); { auto hr = dialog->Show(parameters.HWnd); @@ -142,7 +170,6 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation auto dialog = create_instance(CLSID_FileOpenDialog, CLSCTX_INPROC_SERVER); parameters.ConfigureDialog(dialog); - check_hresult(dialog->SetFileTypeIndex(parameters.FileTypeFilterPara.size())); FILEOPENDIALOGOPTIONS dialogOptions; check_hresult(dialog->GetOptions(&dialogOptions)); diff --git a/dev/Interop/StoragePickers/FileOpenPicker.h b/dev/Interop/StoragePickers/FileOpenPicker.h index 47353b6310..c8beadf316 100644 --- a/dev/Interop/StoragePickers/FileOpenPicker.h +++ b/dev/Interop/StoragePickers/FileOpenPicker.h @@ -6,6 +6,7 @@ #include "PickerCommon.h" #include "StoragePickersTelemetryHelper.h" #include +#include "FileTypeChoicesMap.h" #include "FileTypeFilterVector.h" namespace winrt::Microsoft::Windows::Storage::Pickers::implementation @@ -23,7 +24,14 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation winrt::hstring CommitButtonText(); void CommitButtonText(winrt::hstring const& value); - winrt::Windows::Foundation::Collections::IVector FileTypeFilter(); + winrt::Windows::Foundation::Collections::IVector FileTypeFilter(); + winrt::Windows::Foundation::Collections::IMap> FileTypeChoices(); + + winrt::hstring SuggestedFolder(); + void SuggestedFolder(winrt::hstring const& value); + + winrt::hstring SuggestedStartFolder(); + void SuggestedStartFolder(winrt::hstring const& value); winrt::Windows::Foundation::IAsyncOperation PickSingleFileAsync(); winrt::Windows::Foundation::IAsyncOperation> PickMultipleFilesAsync(); @@ -34,7 +42,11 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation PickerLocationId m_suggestedStartLocation{ PickerLocationId::Unspecified }; winrt::hstring m_commitButtonText{}; - winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ make() }; + winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ make() }; + winrt::Windows::Foundation::Collections::IMap> m_fileTypeChoices{ make(false) }; + + winrt::hstring m_suggestedFolder{}; + winrt::hstring m_suggestedStartFolder{}; StoragePickersTelemetryHelper m_telemetryHelper{}; diff --git a/dev/Interop/StoragePickers/FileSavePicker.cpp b/dev/Interop/StoragePickers/FileSavePicker.cpp index aa1f091b53..6fcb3e2eb0 100644 --- a/dev/Interop/StoragePickers/FileSavePicker.cpp +++ b/dev/Interop/StoragePickers/FileSavePicker.cpp @@ -63,10 +63,22 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation } void FileSavePicker::SuggestedFolder(hstring const& value) { - PickerCommon::ValidateSuggestedFolder(value); + PickerCommon::ValidateFolderPath(value, "SuggestedFolder"); m_suggestedFolder = value; } + hstring FileSavePicker::SuggestedStartFolder() + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + return m_suggestedStartFolder; + } + void FileSavePicker::SuggestedStartFolder(hstring const& value) + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + PickerCommon::ValidateFolderPath(value, "SuggestedStartFolder"); + m_suggestedStartFolder = value; + } + hstring FileSavePicker::SuggestedFileName() { return m_suggestedFileName; @@ -82,10 +94,13 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation { parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); parameters.CommitButtonText = m_commitButtonText; - parameters.PickerLocationId = m_suggestedStartLocation; parameters.SuggestedFileName = m_suggestedFileName; parameters.SuggestedFolder = m_suggestedFolder; - parameters.CaptureFilterSpec(m_fileTypeChoices.GetView()); + parameters.SuggestedStartLocation = m_suggestedStartLocation; + parameters.SuggestedStartFolder = m_suggestedStartFolder; + parameters.CaptureFilterSpecData( + winrt::Windows::Foundation::Collections::IVectorView{}, + m_fileTypeChoices.GetView()); } winrt::Windows::Foundation::IAsyncOperation FileSavePicker::PickSaveFileAsync() diff --git a/dev/Interop/StoragePickers/FileSavePicker.h b/dev/Interop/StoragePickers/FileSavePicker.h index 59a3eb977a..849c819819 100644 --- a/dev/Interop/StoragePickers/FileSavePicker.h +++ b/dev/Interop/StoragePickers/FileSavePicker.h @@ -29,6 +29,9 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation hstring SuggestedFolder(); void SuggestedFolder(hstring const& value); + hstring SuggestedStartFolder(); + void SuggestedStartFolder(hstring const& value); + hstring SuggestedFileName(); void SuggestedFileName(hstring const& value); @@ -41,6 +44,7 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation winrt::Windows::Foundation::Collections::IMap> m_fileTypeChoices{ make() }; hstring m_defaultFileExtension{}; hstring m_suggestedFolder{}; + hstring m_suggestedStartFolder{}; hstring m_suggestedFileName{}; StoragePickersTelemetryHelper m_telemetryHelper{}; diff --git a/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp b/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp index 3f04a4a373..5ca48d2beb 100644 --- a/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp +++ b/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp @@ -7,12 +7,18 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation { - FileTypeChoicesMap::FileTypeChoicesMap() + FileTypeChoicesMap::FileTypeChoicesMap(bool forSavePicker) + : ForSavePicker(forSavePicker) { } bool FileTypeChoicesMap::Insert(hstring const& key, winrt::Windows::Foundation::Collections::IVector const& value) { + if (!ForSavePicker) + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + } + // Create a new FileTypeFilterVector and copy all values from the input vector auto validatingVector = make(); diff --git a/dev/Interop/StoragePickers/FileTypeChoicesMap.h b/dev/Interop/StoragePickers/FileTypeChoicesMap.h index 0f1e2a1a87..794c5e20c3 100644 --- a/dev/Interop/StoragePickers/FileTypeChoicesMap.h +++ b/dev/Interop/StoragePickers/FileTypeChoicesMap.h @@ -11,7 +11,9 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation winrt::Windows::Foundation::Collections::IMap>, winrt::Windows::Foundation::Collections::IIterable>>> { - FileTypeChoicesMap(); + FileTypeChoicesMap(bool forSavePicker = true); + + bool ForSavePicker{ forSavePicker }; // IMap> winrt::Windows::Foundation::Collections::IVector Lookup(hstring const& key) const; diff --git a/dev/Interop/StoragePickers/FileTypeFilterVector.cpp b/dev/Interop/StoragePickers/FileTypeFilterVector.cpp index 5fe3d8bad5..67bb664ff9 100644 --- a/dev/Interop/StoragePickers/FileTypeFilterVector.cpp +++ b/dev/Interop/StoragePickers/FileTypeFilterVector.cpp @@ -7,7 +7,7 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation { - FileTypeFilterVector::FileTypeFilterVector() + FileTypeFilterVector::FileTypeFilterVector(bool forSavePicker) { } diff --git a/dev/Interop/StoragePickers/FolderPicker.cpp b/dev/Interop/StoragePickers/FolderPicker.cpp index c95a581607..aeaea4a90a 100644 --- a/dev/Interop/StoragePickers/FolderPicker.cpp +++ b/dev/Interop/StoragePickers/FolderPicker.cpp @@ -47,15 +47,38 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation PickerCommon::ValidateStringNoEmbeddedNulls(value); m_commitButtonText = value; } + hstring FolderPicker::SuggestedFolder() + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + return m_suggestedFolder; + } + void FolderPicker::SuggestedFolder(hstring const& value) + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + PickerCommon::ValidateFolderPath(value, "SuggestedFolder"); + m_suggestedFolder = value; + } + hstring FolderPicker::SuggestedStartFolder() + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + return m_suggestedStartFolder; + } + void FolderPicker::SuggestedStartFolder(hstring const& value) + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + PickerCommon::ValidateFolderPath(value, "SuggestedStartFolder"); + m_suggestedStartFolder = value; + } void FolderPicker::CaptureParameters(PickerCommon::PickerParameters& parameters) { parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); parameters.CommitButtonText = m_commitButtonText; - parameters.PickerLocationId = m_suggestedStartLocation; + parameters.SuggestedFolder = m_suggestedFolder; + parameters.SuggestedStartLocation = m_suggestedStartLocation; + parameters.SuggestedStartFolder = m_suggestedStartFolder; } - winrt::Windows::Foundation::IAsyncOperation FolderPicker::PickSingleFolderAsync() { // TODO: remove get strong reference when telementry is safe stop diff --git a/dev/Interop/StoragePickers/FolderPicker.h b/dev/Interop/StoragePickers/FolderPicker.h index f5e8f88136..49e7c4b1f7 100644 --- a/dev/Interop/StoragePickers/FolderPicker.h +++ b/dev/Interop/StoragePickers/FolderPicker.h @@ -21,6 +21,12 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation hstring CommitButtonText(); void CommitButtonText(hstring const& value); + hstring SuggestedFolder(); + void SuggestedFolder(hstring const& value); + + hstring SuggestedStartFolder(); + void SuggestedStartFolder(hstring const& value); + winrt::Windows::Foundation::IAsyncOperation PickSingleFolderAsync(); private: @@ -29,6 +35,8 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation PickerViewMode m_viewMode{ PickerViewMode::List }; PickerLocationId m_suggestedStartLocation{ PickerLocationId::Unspecified }; hstring m_commitButtonText{}; + hstring m_suggestedFolder{}; + hstring m_suggestedStartFolder{}; StoragePickersTelemetryHelper m_telemetryHelper{}; void CaptureParameters(PickerCommon::PickerParameters& parameters); diff --git a/dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl b/dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl index 895fb2c621..e70b9d7954 100644 --- a/dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl +++ b/dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl @@ -1,9 +1,11 @@ // Copyright (c) Microsoft Corporation and Contributors. // Licensed under the MIT License. +#include + namespace Microsoft.Windows.Storage.Pickers { - [contractversion(1.8)] + [contractversion(2.0)] apicontract StoragePickersContract {}; [contract(StoragePickersContract, 1.8)] @@ -41,8 +43,17 @@ namespace Microsoft.Windows.Storage.Pickers Microsoft.Windows.Storage.Pickers.PickerViewMode ViewMode; Microsoft.Windows.Storage.Pickers.PickerLocationId SuggestedStartLocation; String CommitButtonText; + Windows.Foundation.Collections.IMap > FileTypeChoices{ get; }; Windows.Foundation.Collections.IVector FileTypeFilter{ get; }; + [contract(StoragePickersContract, 2.0)] + [feature(Feature_StoragePickers2)] + String SuggestedFolder; + + [contract(StoragePickersContract, 2.0)] + [feature(Feature_StoragePickers2)] + String SuggestedStartFolder; + [remote_sync] Windows.Foundation.IAsyncOperation PickSingleFileAsync(); [remote_sync] Windows.Foundation.IAsyncOperation > PickMultipleFilesAsync(); } @@ -59,6 +70,10 @@ namespace Microsoft.Windows.Storage.Pickers String SuggestedFileName; String SuggestedFolder; + [contract(StoragePickersContract, 2.0)] + [feature(Feature_StoragePickers2)] + String SuggestedStartFolder; + [remote_sync] Windows.Foundation.IAsyncOperation PickSaveFileAsync(); } @@ -76,6 +91,11 @@ namespace Microsoft.Windows.Storage.Pickers Microsoft.Windows.Storage.Pickers.PickerViewMode ViewMode; Microsoft.Windows.Storage.Pickers.PickerLocationId SuggestedStartLocation; String CommitButtonText; + String SuggestedFolder; + + [contract(StoragePickersContract, 2.0)] + [feature(Feature_StoragePickers2)] + String SuggestedStartFolder; [remote_sync] Windows.Foundation.IAsyncOperation PickSingleFolderAsync(); } diff --git a/dev/Interop/StoragePickers/PickerCommon.cpp b/dev/Interop/StoragePickers/PickerCommon.cpp index dec7a50d3a..e90558e1f8 100644 --- a/dev/Interop/StoragePickers/PickerCommon.cpp +++ b/dev/Interop/StoragePickers/PickerCommon.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include namespace { @@ -224,7 +226,7 @@ namespace PickerCommon { ValidateStringNoEmbeddedNulls(suggestedFileName); } - void ValidateSuggestedFolder(winrt::hstring const& path) + void ValidateFolderPath(winrt::hstring const& path, std::string const& propertyName) { if (path.empty()) { @@ -234,16 +236,77 @@ namespace PickerCommon { ValidateStringNoEmbeddedNulls(path); - auto pathObj = std::filesystem::path(path.c_str()); + std::wstring pathString{ path }; + auto pathObj = std::filesystem::path(pathString); if (!pathObj.is_absolute()) { - throw std::invalid_argument("SuggestedFolder"); + throw std::invalid_argument(propertyName); } - wil::unique_cotaskmem_ptr pidl(SHSimpleIDListFromPath(path.c_str())); - if (!pidl) + constexpr std::wstring_view invalidCharacters{ L"<>\"|?*" }; + + bool hasExtendedPrefix = false; + size_t startIndex = 0; + if (pathString.size() >= 4 && pathString[0] == L'\\' && pathString[1] == L'\\' && + (pathString[2] == L'?' || pathString[2] == L'.') && pathString[3] == L'\\') + { + hasExtendedPrefix = true; + startIndex = 4; // Skip the extended path prefix + } + + auto isDriveSpecifier = [&](size_t index) + { + if (!hasExtendedPrefix) + { + return index == 1 && std::iswalpha(pathString[0]); + } + + return (index == 5 && std::iswalpha(pathString[4])); + }; + + for (size_t i = startIndex; i < pathString.size(); ++i) + { + wchar_t currentChar = pathString[i]; + + if (currentChar == L':') + { + if (isDriveSpecifier(i)) + { + continue; + } + } + + if (invalidCharacters.find(currentChar) != std::wstring_view::npos) + { + throw std::invalid_argument(propertyName); + } + } + + constexpr size_t MaxComponentLength = 255; + bool isFirstComponent = true; + for (auto const& component : pathObj) { - throw std::invalid_argument("SuggestedFolder"); + auto nativeComponent = component.native(); + if (nativeComponent.empty()) + { + continue; + } + + if (isFirstComponent) + { + isFirstComponent = false; + continue; // Skip root name (e.g., "C:" or "\\server\share") + } + + if (nativeComponent == L"\\" || nativeComponent == L"/") + { + continue; // Skip root directory separators + } + + if (nativeComponent.size() > MaxComponentLength) + { + throw std::invalid_argument(propertyName); + } } } @@ -278,6 +341,28 @@ namespace PickerCommon { return result; } + void PickerParameters::CaptureFilterSpecData( + winrt::Windows::Foundation::Collections::IVectorView fileTypeFilterView, + winrt::Windows::Foundation::Collections::IMapView> fileTypeChoicesView) + { + // The FileTypeChoices takes precedence over FileTypeFilter if both are provided. + if (fileTypeChoicesView && fileTypeChoicesView.Size() > 0) + { + CaptureFilterSpec(fileTypeChoicesView); + return; + } + + if (fileTypeFilterView && fileTypeFilterView.Size() > 0) + { + CaptureFilterSpec(fileTypeFilterView); + return; + } + + // Even if no filters provided, we still need to set filter to All Files *.* + auto emptyFilters = winrt::single_threaded_vector(); + CaptureFilterSpec(emptyFilters.GetView()); + } + /// /// Capture and processing pickers filter inputs and convert them into Common Item Dialog's accepting type, for FileOpenPicker /// @@ -330,6 +415,8 @@ namespace PickerCommon { { FileTypeFilterPara.push_back({ FileTypeFilterData.at(i * 2).c_str(), FileTypeFilterData.at(i * 2 + 1).c_str() }); } + + FocusLastFilter = true; } /// @@ -372,15 +459,41 @@ namespace PickerCommon { check_hresult(dialog->SetOkButtonLabel(CommitButtonText.c_str())); } - auto defaultFolder = GetKnownFolderFromId(PickerLocationId); - if (defaultFolder != nullptr) + winrt::com_ptr defaultFolder{}; + + // The SuggestedStartFolder takes precedence over SuggestedStartLocation if both are provided. + if (!IsHStringNullOrEmpty(SuggestedStartFolder)) + { + defaultFolder = TryParseFolderItem(SuggestedStartFolder); + } + + if (!defaultFolder) + { + defaultFolder = GetKnownFolderFromId(SuggestedStartLocation); + } + + if (defaultFolder) { check_hresult(dialog->SetDefaultFolder(defaultFolder.get())); } + // SuggestedFolder takes precedence over SuggestedStartFolder/SuggestedStartLocation if both are provided. + if (!IsHStringNullOrEmpty(SuggestedFolder)) + { + if (auto folderItem = TryParseFolderItem(SuggestedFolder)) + { + check_hresult(dialog->SetFolder(folderItem.get())); + } + } + if (FileTypeFilterPara.size() > 0) { check_hresult(dialog->SetFileTypes((UINT)FileTypeFilterPara.size(), FileTypeFilterPara.data())); + + if (FocusLastFilter) + { + check_hresult(dialog->SetFileTypeIndex(FileTypeFilterPara.size())); + } } } @@ -395,13 +508,5 @@ namespace PickerCommon { check_hresult(dialog->SetFileName(SuggestedFileName.c_str())); } - if (!PickerCommon::IsHStringNullOrEmpty(SuggestedFolder)) - { - winrt::com_ptr folderItem = TryParseFolderItem(SuggestedFolder); - if (folderItem) - { - check_hresult(dialog->SetFolder(folderItem.get())); - } - } } } diff --git a/dev/Interop/StoragePickers/PickerCommon.h b/dev/Interop/StoragePickers/PickerCommon.h index 124a9eb261..f9e419bc38 100644 --- a/dev/Interop/StoragePickers/PickerCommon.h +++ b/dev/Interop/StoragePickers/PickerCommon.h @@ -26,26 +26,33 @@ namespace PickerCommon { void ValidateSuggestedStartLocation(winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId const& value); void ValidateSingleFileTypeFilterElement(winrt::hstring const& filter); void ValidateSuggestedFileName(winrt::hstring const& suggestedFileName); - void ValidateSuggestedFolder(winrt::hstring const& path); + void ValidateFolderPath(winrt::hstring const& path, std::string const& argumentName); struct PickerParameters { HWND HWnd{}; winrt::hstring CommitButtonText; - winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId PickerLocationId; + winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId SuggestedStartLocation; std::vector FileTypeFilterData{}; std::vector FileTypeFilterPara{}; + bool FocusLastFilter{ false }; winrt::hstring AllFilesText{ L"All Files" }; // initialize to All Files as a default value, will be updated by localization winrt::hstring SuggestedFileName; winrt::hstring SuggestedFolder; + winrt::hstring SuggestedStartFolder; winrt::hstring FormatExtensionWithWildcard(winrt::hstring extension); winrt::hstring JoinExtensions(winrt::Windows::Foundation::Collections::IVectorView extensions); - void CaptureFilterSpec(winrt::Windows::Foundation::Collections::IVectorView filters); - void CaptureFilterSpec(winrt::Windows::Foundation::Collections::IMapView> filters); + void CaptureFilterSpecData( + winrt::Windows::Foundation::Collections::IVectorView fileTypeFilterView, + winrt::Windows::Foundation::Collections::IMapView> fileTypeChoicesView); void ConfigureDialog(winrt::com_ptr dialog); void ConfigureFileSaveDialog(winrt::com_ptr dialog); + + private: + void CaptureFilterSpec(winrt::Windows::Foundation::Collections::IVectorView filters); + void CaptureFilterSpec(winrt::Windows::Foundation::Collections::IMapView> filters); }; } diff --git a/test/StoragePickersTests/PickerCommonTests.cpp b/test/StoragePickersTests/PickerCommonTests.cpp index 29c870c7f8..555eec06a1 100644 --- a/test/StoragePickersTests/PickerCommonTests.cpp +++ b/test/StoragePickersTests/PickerCommonTests.cpp @@ -99,6 +99,7 @@ namespace Test::PickerCommonTests // Act. auto dialog = winrt::create_instance(CLSID_FileSaveDialog, CLSCTX_INPROC_SERVER); + parameters.ConfigureDialog(dialog.as()); parameters.ConfigureFileSaveDialog(dialog); // Assert. @@ -130,6 +131,7 @@ namespace Test::PickerCommonTests // Act. auto dialog = winrt::create_instance(CLSID_FileSaveDialog, CLSCTX_INPROC_SERVER); + parameters.ConfigureDialog(dialog.as()); parameters.ConfigureFileSaveDialog(dialog); // Assert. @@ -150,7 +152,7 @@ namespace Test::PickerCommonTests // Act. PickerParameters parameters{}; - parameters.CaptureFilterSpec(picker.FileTypeFilter().GetView()); + parameters.CaptureFilterSpecData(picker.FileTypeFilter().GetView(), nullptr); // Assert. VERIFY_ARE_EQUAL(parameters.FileTypeFilterPara.size(), 3); @@ -176,7 +178,7 @@ namespace Test::PickerCommonTests // Act. PickerParameters parameters{}; - parameters.CaptureFilterSpec(picker.FileTypeFilter().GetView()); + parameters.CaptureFilterSpecData(picker.FileTypeFilter().GetView(), nullptr); // Assert. VERIFY_ARE_EQUAL(parameters.FileTypeFilterPara.size(), 1); @@ -196,7 +198,7 @@ namespace Test::PickerCommonTests // Act. PickerParameters parameters{}; - parameters.CaptureFilterSpec(picker.FileTypeFilter().GetView()); + parameters.CaptureFilterSpecData(picker.FileTypeFilter().GetView(), nullptr); // Assert. VERIFY_ARE_EQUAL(parameters.FileTypeFilterPara.size(), 1); @@ -206,6 +208,34 @@ namespace Test::PickerCommonTests L"*"); } + TEST_METHOD(VerifyFilters_FileOpenPickerWhenFileTypeChoicesDefinedExpectMatchingSpec) + { + // Arrange. + winrt::Microsoft::UI::WindowId windowId{}; + winrt::Microsoft::Windows::Storage::Pickers::FileOpenPicker picker(windowId); + + picker.FileTypeChoices().Insert( + L"Documents", winrt::single_threaded_vector({ L".txt", L".doc", L".docx" })); + picker.FileTypeChoices().Insert( + L"Pictures", winrt::single_threaded_vector({ L".png", L".jpg", L".jpeg", L".bmp" })); + + // Act. + PickerParameters parameters{}; + parameters.CaptureFilterSpecData( + winrt::Windows::Foundation::Collections::IVectorView{}, + picker.FileTypeChoices().GetView()); + + // Assert. + VERIFY_ARE_EQUAL(parameters.FileTypeFilterPara.size(), 2); + + VERIFY_ARE_EQUAL( + std::wstring(parameters.FileTypeFilterPara[0].pszSpec), + L"*.txt;*.doc;*.docx"); + VERIFY_ARE_EQUAL( + std::wstring(parameters.FileTypeFilterPara[1].pszSpec), + L"*.png;*.jpg;*.jpeg;*.bmp"); + } + TEST_METHOD(VerifyFilters_FileSavePickerWhenFileTypeChoicesDefinedExpectMatchingSpec) { // Arrange. @@ -219,7 +249,9 @@ namespace Test::PickerCommonTests // Act. PickerParameters parameters{}; - parameters.CaptureFilterSpec(picker.FileTypeChoices().GetView()); + parameters.CaptureFilterSpecData( + winrt::Windows::Foundation::Collections::IVectorView{}, + picker.FileTypeChoices().GetView()); // Assert. VERIFY_ARE_EQUAL(parameters.FileTypeFilterPara.size(), 2); @@ -242,7 +274,9 @@ namespace Test::PickerCommonTests // Act. PickerParameters parameters{}; - parameters.CaptureFilterSpec(picker.FileTypeChoices().GetView()); + parameters.CaptureFilterSpecData( + winrt::Windows::Foundation::Collections::IVectorView{}, + picker.FileTypeChoices().GetView()); // Assert. VERIFY_ARE_EQUAL(parameters.FileTypeFilterPara.size(), 1); @@ -250,6 +284,9 @@ namespace Test::PickerCommonTests VERIFY_ARE_EQUAL( std::wstring(parameters.FileTypeFilterPara[0].pszSpec), L"*"); + VERIFY_ARE_EQUAL( + std::wstring(parameters.FileTypeFilterPara[0].pszName), + L"All Files"); } TEST_METHOD(VerifyFilters_FileSavePickerWhenAsteriskFileTypeChoicesDefinedExpectAsteriskSpec) @@ -265,7 +302,9 @@ namespace Test::PickerCommonTests // Act. PickerParameters parameters{}; - parameters.CaptureFilterSpec(picker.FileTypeChoices().GetView()); + parameters.CaptureFilterSpecData( + winrt::Windows::Foundation::Collections::IVectorView{}, + picker.FileTypeChoices().GetView()); // Assert. VERIFY_ARE_EQUAL(parameters.FileTypeFilterPara.size(), 1); @@ -628,6 +667,9 @@ namespace Test::PickerCommonTests { picker.SuggestedFolder(suggestedFolder); VERIFY_ARE_EQUAL(picker.SuggestedFolder(), suggestedFolder); + + picker.SuggestedStartFolder(suggestedFolder); + VERIFY_ARE_EQUAL(picker.SuggestedStartFolder(), suggestedFolder); } else { @@ -641,6 +683,17 @@ namespace Test::PickerCommonTests { // Expected exception for invalid suggested folder } + + try + { + picker.SuggestedStartFolder(suggestedFolder); + std::wstring errorMessage = L"Expected exception for invalid suggested start folder: " + std::wstring(suggestedFolder); + VERIFY_FAIL(errorMessage.c_str()); + } + catch (...) + { + // Expected exception for invalid suggested start folder + } } } } diff --git a/test/StoragePickersTests/StoragePickersTests.cpp b/test/StoragePickersTests/StoragePickersTests.cpp index 5c63b5a2d2..97721e7c2a 100644 --- a/test/StoragePickersTests/StoragePickersTests.cpp +++ b/test/StoragePickersTests/StoragePickersTests.cpp @@ -153,6 +153,17 @@ namespace Test::StoragePickersTests picker.FileTypeFilter().Append(L"*"); VERIFY_ARE_EQUAL(picker.FileTypeFilter().GetAt(0), L"*"); + + auto openPickerChoices = winrt::single_threaded_vector(); + openPickerChoices.Append(L".txt"); + picker.FileTypeChoices().Insert(L"Documents", openPickerChoices); + VERIFY_ARE_EQUAL(picker.FileTypeChoices().Lookup(L"Documents").GetAt(0), L".txt"); + + picker.SuggestedFolder(L"C:\\temp_fileopenpicker_ut_temp"); + VERIFY_ARE_EQUAL(picker.SuggestedFolder(), L"C:\\temp_fileopenpicker_ut_temp"); + + picker.SuggestedStartFolder(L"C:\\temp_fileopenpicker_ut_start"); + VERIFY_ARE_EQUAL(picker.SuggestedStartFolder(), L"C:\\temp_fileopenpicker_ut_start"); } TEST_METHOD(VerifyFileSavePickerOptionsAreReadCorrectly) @@ -174,6 +185,9 @@ namespace Test::StoragePickersTests filters.Append(L"*"); picker.FileTypeChoices().Insert(L"All Files", filters); VERIFY_ARE_EQUAL(picker.FileTypeChoices().Lookup(L"All Files").GetAt(0), L"*"); + + picker.SuggestedStartFolder(L"C:\\temp_filesavepicker_start"); + VERIFY_ARE_EQUAL(picker.SuggestedStartFolder(), L"C:\\temp_filesavepicker_start"); } TEST_METHOD(VerifyFolderPickerOptionsAreReadCorrectly) @@ -193,6 +207,12 @@ namespace Test::StoragePickersTests picker.CommitButtonText(L"commit"); VERIFY_ARE_EQUAL(picker.CommitButtonText(), L"commit"); + + picker.SuggestedFolder(L"C:\\temp_folderpicker_ut_temp"); + VERIFY_ARE_EQUAL(picker.SuggestedFolder(), L"C:\\temp_folderpicker_ut_temp"); + + picker.SuggestedStartFolder(L"C:\\temp_folderpicker_ut_start"); + VERIFY_ARE_EQUAL(picker.SuggestedStartFolder(), L"C:\\temp_folderpicker_ut_start"); } }; From 1534dd9a451f9fef25d3e1eda9e238521e46e58f Mon Sep 17 00:00:00 2001 From: DinahK-2SO <116714259+DinahK-2SO@users.noreply.github.com> Date: Thu, 2 Oct 2025 10:48:36 +0800 Subject: [PATCH 2/4] fix errors --- .../StoragePickers/FileTypeFilterVector.cpp | 2 +- dev/Interop/StoragePickers/PickerCommon.cpp | 70 ++----------------- 2 files changed, 6 insertions(+), 66 deletions(-) diff --git a/dev/Interop/StoragePickers/FileTypeFilterVector.cpp b/dev/Interop/StoragePickers/FileTypeFilterVector.cpp index 67bb664ff9..5fe3d8bad5 100644 --- a/dev/Interop/StoragePickers/FileTypeFilterVector.cpp +++ b/dev/Interop/StoragePickers/FileTypeFilterVector.cpp @@ -7,7 +7,7 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation { - FileTypeFilterVector::FileTypeFilterVector(bool forSavePicker) + FileTypeFilterVector::FileTypeFilterVector() { } diff --git a/dev/Interop/StoragePickers/PickerCommon.cpp b/dev/Interop/StoragePickers/PickerCommon.cpp index e90558e1f8..d5c003cc77 100644 --- a/dev/Interop/StoragePickers/PickerCommon.cpp +++ b/dev/Interop/StoragePickers/PickerCommon.cpp @@ -236,77 +236,17 @@ namespace PickerCommon { ValidateStringNoEmbeddedNulls(path); - std::wstring pathString{ path }; - auto pathObj = std::filesystem::path(pathString); + auto pathObj = std::filesystem::path(path.c_str()); if (!pathObj.is_absolute()) { throw std::invalid_argument(propertyName); } - constexpr std::wstring_view invalidCharacters{ L"<>\"|?*" }; - - bool hasExtendedPrefix = false; - size_t startIndex = 0; - if (pathString.size() >= 4 && pathString[0] == L'\\' && pathString[1] == L'\\' && - (pathString[2] == L'?' || pathString[2] == L'.') && pathString[3] == L'\\') - { - hasExtendedPrefix = true; - startIndex = 4; // Skip the extended path prefix - } - - auto isDriveSpecifier = [&](size_t index) - { - if (!hasExtendedPrefix) - { - return index == 1 && std::iswalpha(pathString[0]); - } - - return (index == 5 && std::iswalpha(pathString[4])); - }; - - for (size_t i = startIndex; i < pathString.size(); ++i) - { - wchar_t currentChar = pathString[i]; - - if (currentChar == L':') - { - if (isDriveSpecifier(i)) - { - continue; - } - } - - if (invalidCharacters.find(currentChar) != std::wstring_view::npos) - { - throw std::invalid_argument(propertyName); - } - } - - constexpr size_t MaxComponentLength = 255; - bool isFirstComponent = true; - for (auto const& component : pathObj) + // The method SHSimpleIDListFromPath does syntax check on the path string. + wil::unique_cotaskmem_ptr pidl(SHSimpleIDListFromPath(path.c_str())); + if (!pidl) { - auto nativeComponent = component.native(); - if (nativeComponent.empty()) - { - continue; - } - - if (isFirstComponent) - { - isFirstComponent = false; - continue; // Skip root name (e.g., "C:" or "\\server\share") - } - - if (nativeComponent == L"\\" || nativeComponent == L"/") - { - continue; // Skip root directory separators - } - - if (nativeComponent.size() > MaxComponentLength) - { - throw std::invalid_argument(propertyName); - } + throw std::invalid_argument(propertyName); } } From 3f0a1dd8e1d9d6975448cfd19e188b03910bc81f Mon Sep 17 00:00:00 2001 From: DinahK-2SO <116714259+DinahK-2SO@users.noreply.github.com> Date: Thu, 2 Oct 2025 11:50:34 +0800 Subject: [PATCH 3/4] ForFeature_StoragePickers2 --- dev/Interop/StoragePickers/FileOpenPicker.h | 9 ++++++++- dev/Interop/StoragePickers/FileTypeChoicesMap.cpp | 5 ++--- dev/Interop/StoragePickers/FileTypeChoicesMap.h | 4 ++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/dev/Interop/StoragePickers/FileOpenPicker.h b/dev/Interop/StoragePickers/FileOpenPicker.h index c8beadf316..03319b8f4d 100644 --- a/dev/Interop/StoragePickers/FileOpenPicker.h +++ b/dev/Interop/StoragePickers/FileOpenPicker.h @@ -43,7 +43,14 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation winrt::hstring m_commitButtonText{}; winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ make() }; - winrt::Windows::Foundation::Collections::IMap> m_fileTypeChoices{ make(false) }; + winrt::Windows::Foundation::Collections::IMap> m_fileTypeChoices{ + []() + { + auto map = make(); + map.ForFeature_StoragePickers2 = true; + return map.as>>(); + }() + }; winrt::hstring m_suggestedFolder{}; winrt::hstring m_suggestedStartFolder{}; diff --git a/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp b/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp index 5ca48d2beb..c2f23b319f 100644 --- a/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp +++ b/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp @@ -7,14 +7,13 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation { - FileTypeChoicesMap::FileTypeChoicesMap(bool forSavePicker) - : ForSavePicker(forSavePicker) + FileTypeChoicesMap::FileTypeChoicesMap() { } bool FileTypeChoicesMap::Insert(hstring const& key, winrt::Windows::Foundation::Collections::IVector const& value) { - if (!ForSavePicker) + if (ForFeature_StoragePickers2) { THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); } diff --git a/dev/Interop/StoragePickers/FileTypeChoicesMap.h b/dev/Interop/StoragePickers/FileTypeChoicesMap.h index 794c5e20c3..1dc6143667 100644 --- a/dev/Interop/StoragePickers/FileTypeChoicesMap.h +++ b/dev/Interop/StoragePickers/FileTypeChoicesMap.h @@ -11,9 +11,9 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation winrt::Windows::Foundation::Collections::IMap>, winrt::Windows::Foundation::Collections::IIterable>>> { - FileTypeChoicesMap(bool forSavePicker = true); + FileTypeChoicesMap(); - bool ForSavePicker{ forSavePicker }; + bool ForFeature_StoragePickers2{ false }; // IMap> winrt::Windows::Foundation::Collections::IVector Lookup(hstring const& key) const; From 0618e5b868c2ad45c433b63868d0cfa36a3b39f2 Mon Sep 17 00:00:00 2001 From: DinahK-2SO <116714259+DinahK-2SO@users.noreply.github.com> Date: Fri, 3 Oct 2025 21:00:05 +0800 Subject: [PATCH 4/4] fix build error: fix the missing velocity head includes; graceful --- dev/Interop/StoragePickers/FileOpenPicker.cpp | 1 + dev/Interop/StoragePickers/FileOpenPicker.h | 4 ++-- dev/Interop/StoragePickers/FileSavePicker.cpp | 1 + dev/Interop/StoragePickers/FileTypeChoicesMap.cpp | 1 + dev/Interop/StoragePickers/FolderPicker.cpp | 1 + .../StoragePickers/Microsoft.Windows.Storage.Pickers.idl | 9 ++++++++- dev/Interop/StoragePickers/PickerCommon.h | 2 +- 7 files changed, 15 insertions(+), 4 deletions(-) diff --git a/dev/Interop/StoragePickers/FileOpenPicker.cpp b/dev/Interop/StoragePickers/FileOpenPicker.cpp index 3a8c108261..b61792f9ac 100644 --- a/dev/Interop/StoragePickers/FileOpenPicker.cpp +++ b/dev/Interop/StoragePickers/FileOpenPicker.cpp @@ -10,6 +10,7 @@ #include #include #include "TerminalVelocityFeatures-StoragePickers.h" +#include "TerminalVelocityFeatures-StoragePickers2.h" #include "PickerCommon.h" #include "PickFileResult.h" #include "PickerLocalization.h" diff --git a/dev/Interop/StoragePickers/FileOpenPicker.h b/dev/Interop/StoragePickers/FileOpenPicker.h index 03319b8f4d..c5ff80bc27 100644 --- a/dev/Interop/StoragePickers/FileOpenPicker.h +++ b/dev/Interop/StoragePickers/FileOpenPicker.h @@ -46,8 +46,8 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation winrt::Windows::Foundation::Collections::IMap> m_fileTypeChoices{ []() { - auto map = make(); - map.ForFeature_StoragePickers2 = true; + auto map = winrt::make_self(); + map->ForFeature_StoragePickers2 = true; return map.as>>(); }() }; diff --git a/dev/Interop/StoragePickers/FileSavePicker.cpp b/dev/Interop/StoragePickers/FileSavePicker.cpp index 6fcb3e2eb0..95e965be00 100644 --- a/dev/Interop/StoragePickers/FileSavePicker.cpp +++ b/dev/Interop/StoragePickers/FileSavePicker.cpp @@ -15,6 +15,7 @@ #include #include #include "TerminalVelocityFeatures-StoragePickers.h" +#include "TerminalVelocityFeatures-StoragePickers2.h" #include "PickerCommon.h" #include "PickerLocalization.h" #include "PickFileResult.h" diff --git a/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp b/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp index c2f23b319f..0d8571ed8b 100644 --- a/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp +++ b/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp @@ -4,6 +4,7 @@ #include "pch.h" #include "FileTypeChoicesMap.h" #include "FileTypeFilterVector.h" +#include "TerminalVelocityFeatures-StoragePickers2.h" namespace winrt::Microsoft::Windows::Storage::Pickers::implementation { diff --git a/dev/Interop/StoragePickers/FolderPicker.cpp b/dev/Interop/StoragePickers/FolderPicker.cpp index aeaea4a90a..5da7ab331e 100644 --- a/dev/Interop/StoragePickers/FolderPicker.cpp +++ b/dev/Interop/StoragePickers/FolderPicker.cpp @@ -9,6 +9,7 @@ #include #include #include "TerminalVelocityFeatures-StoragePickers.h" +#include "TerminalVelocityFeatures-StoragePickers2.h" #include "PickerCommon.h" #include "PickFolderResult.h" #include "PickerLocalization.h" diff --git a/dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl b/dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl index e70b9d7954..c71d622193 100644 --- a/dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl +++ b/dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl @@ -7,7 +7,7 @@ namespace Microsoft.Windows.Storage.Pickers { [contractversion(2.0)] apicontract StoragePickersContract {}; - + [contract(StoragePickersContract, 1.8)] enum PickerViewMode { @@ -43,7 +43,11 @@ namespace Microsoft.Windows.Storage.Pickers Microsoft.Windows.Storage.Pickers.PickerViewMode ViewMode; Microsoft.Windows.Storage.Pickers.PickerLocationId SuggestedStartLocation; String CommitButtonText; + + [contract(StoragePickersContract, 2.0)] + [feature(Feature_StoragePickers2)] Windows.Foundation.Collections.IMap > FileTypeChoices{ get; }; + Windows.Foundation.Collections.IVector FileTypeFilter{ get; }; [contract(StoragePickersContract, 2.0)] @@ -91,6 +95,9 @@ namespace Microsoft.Windows.Storage.Pickers Microsoft.Windows.Storage.Pickers.PickerViewMode ViewMode; Microsoft.Windows.Storage.Pickers.PickerLocationId SuggestedStartLocation; String CommitButtonText; + + [contract(StoragePickersContract, 2.0)] + [feature(Feature_StoragePickers2)] String SuggestedFolder; [contract(StoragePickersContract, 2.0)] diff --git a/dev/Interop/StoragePickers/PickerCommon.h b/dev/Interop/StoragePickers/PickerCommon.h index f9e419bc38..f2bc2045ab 100644 --- a/dev/Interop/StoragePickers/PickerCommon.h +++ b/dev/Interop/StoragePickers/PickerCommon.h @@ -26,7 +26,7 @@ namespace PickerCommon { void ValidateSuggestedStartLocation(winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId const& value); void ValidateSingleFileTypeFilterElement(winrt::hstring const& filter); void ValidateSuggestedFileName(winrt::hstring const& suggestedFileName); - void ValidateFolderPath(winrt::hstring const& path, std::string const& argumentName); + void ValidateFolderPath(winrt::hstring const& path, std::string const& propertyName); struct PickerParameters { HWND HWnd{};