Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions dev/Common/TerminalVelocityFeatures-StoragePickers2.h
Original file line number Diff line number Diff line change
@@ -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)
20 changes: 20 additions & 0 deletions dev/Common/TerminalVelocityFeatures-StoragePickers2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0"?>
<features xmlns="http://microsoft.com/windowsappsdk/TerminalVelocity/20210729/TerminalVelocityFeatures.xsd">

<!-- Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License. See LICENSE in the project root for license information.
-->

<!-- See docs/Coding-Guidelines/TerminalVelocity.md for more info. -->

<!-- Enabled variants -->
<feature>
<name>Feature_StoragePickers2</name>
<description>New functionalities in StoragePickers for the WindowsAppRuntime: SuggestedDefaultFolder, FileTypeChoices</description>
<state>AlwaysEnabled</state>
<alwaysDisabledChannelTokens>
<channelToken>Preview</channelToken>
<channelToken>Stable</channelToken>
</alwaysDisabledChannelTokens>
</feature>
</features>
38 changes: 33 additions & 5 deletions dev/Interop/StoragePickers/FileOpenPicker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <shobjidl_core.h>
#include <winrt/Microsoft.UI.Interop.h>
#include "TerminalVelocityFeatures-StoragePickers.h"
#include "TerminalVelocityFeatures-StoragePickers2.h"
#include "PickerCommon.h"
#include "PickFileResult.h"
#include "PickerLocalization.h"
Expand Down Expand Up @@ -49,17 +50,46 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
PickerCommon::ValidateStringNoEmbeddedNulls(value);
m_commitButtonText = value;
}
winrt::Windows::Foundation::Collections::IVector<hstring> FileOpenPicker::FileTypeFilter()
winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Windows::Foundation::Collections::IVector<winrt::hstring>> FileOpenPicker::FileTypeChoices()
{
THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled());
return m_fileTypeChoices;
}
winrt::Windows::Foundation::Collections::IVector<winrt::hstring> FileOpenPicker::FileTypeFilter()
{
return m_fileTypeFilter;
}
winrt::hstring FileOpenPicker::SuggestedFolder()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curiosity: Maybe it might be worthwhile to test performance as well? Could complex or large FileTypeChoices lists slow down picker init?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be ok. It is the same property logic existing in FileSavePicker.

{
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<winrt::Microsoft::Windows::Storage::Pickers::PickFileResult> FileOpenPicker::PickSingleFileAsync()
Expand Down Expand Up @@ -87,7 +117,6 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
auto dialog = create_instance<IFileOpenDialog>(CLSID_FileOpenDialog, CLSCTX_INPROC_SERVER);

parameters.ConfigureDialog(dialog);
check_hresult(dialog->SetFileTypeIndex(parameters.FileTypeFilterPara.size()));

{
auto hr = dialog->Show(parameters.HWnd);
Expand Down Expand Up @@ -142,7 +171,6 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
auto dialog = create_instance<IFileOpenDialog>(CLSID_FileOpenDialog, CLSCTX_INPROC_SERVER);

parameters.ConfigureDialog(dialog);
check_hresult(dialog->SetFileTypeIndex(parameters.FileTypeFilterPara.size()));

FILEOPENDIALOGOPTIONS dialogOptions;
check_hresult(dialog->GetOptions(&dialogOptions));
Expand Down
23 changes: 21 additions & 2 deletions dev/Interop/StoragePickers/FileOpenPicker.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "PickerCommon.h"
#include "StoragePickersTelemetryHelper.h"
#include <winrt/Windows.Foundation.Collections.h>
#include "FileTypeChoicesMap.h"
#include "FileTypeFilterVector.h"

namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
Expand All @@ -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<hstring> FileTypeFilter();
winrt::Windows::Foundation::Collections::IVector<winrt::hstring> FileTypeFilter();
winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Windows::Foundation::Collections::IVector<winrt::hstring>> FileTypeChoices();

winrt::hstring SuggestedFolder();
void SuggestedFolder(winrt::hstring const& value);

winrt::hstring SuggestedStartFolder();
void SuggestedStartFolder(winrt::hstring const& value);

winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::Windows::Storage::Pickers::PickFileResult> PickSingleFileAsync();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Windows::Storage::Pickers::PickFileResult>> PickMultipleFilesAsync();
Expand All @@ -34,7 +42,18 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
PickerLocationId m_suggestedStartLocation{ PickerLocationId::Unspecified };
winrt::hstring m_commitButtonText{};

winrt::Windows::Foundation::Collections::IVector<hstring> m_fileTypeFilter{ make<FileTypeFilterVector>() };
winrt::Windows::Foundation::Collections::IVector<winrt::hstring> m_fileTypeFilter{ make<FileTypeFilterVector>() };
winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Windows::Foundation::Collections::IVector<winrt::hstring>> m_fileTypeChoices{
[]()
{
auto map = winrt::make_self<FileTypeChoicesMap>();
map->ForFeature_StoragePickers2 = true;
return map.as<winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Windows::Foundation::Collections::IVector<winrt::hstring>>>();
}()
};

winrt::hstring m_suggestedFolder{};
winrt::hstring m_suggestedStartFolder{};

StoragePickersTelemetryHelper m_telemetryHelper{};

Expand Down
22 changes: 19 additions & 3 deletions dev/Interop/StoragePickers/FileSavePicker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <winrt/Microsoft.UI.Interop.h>
#include <winrt/Windows.Foundation.Collections.h>
#include "TerminalVelocityFeatures-StoragePickers.h"
#include "TerminalVelocityFeatures-StoragePickers2.h"
#include "PickerCommon.h"
#include "PickerLocalization.h"
#include "PickFileResult.h"
Expand Down Expand Up @@ -63,10 +64,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;
Expand All @@ -82,10 +95,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<winrt::hstring>{},
m_fileTypeChoices.GetView());
}

winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::Windows::Storage::Pickers::PickFileResult> FileSavePicker::PickSaveFileAsync()
Expand Down
4 changes: 4 additions & 0 deletions dev/Interop/StoragePickers/FileSavePicker.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
hstring SuggestedFolder();
void SuggestedFolder(hstring const& value);

hstring SuggestedStartFolder();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit - Is there a possibility to move common logic to a base class?

Copy link
Contributor Author

@DinahK-2SO DinahK-2SO Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is a good point. We might do some refactoring in future.

void SuggestedStartFolder(hstring const& value);

hstring SuggestedFileName();
void SuggestedFileName(hstring const& value);

Expand All @@ -41,6 +44,7 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
winrt::Windows::Foundation::Collections::IMap<hstring, winrt::Windows::Foundation::Collections::IVector<hstring>> m_fileTypeChoices{ make<FileTypeChoicesMap>() };
hstring m_defaultFileExtension{};
hstring m_suggestedFolder{};
hstring m_suggestedStartFolder{};
hstring m_suggestedFileName{};
StoragePickersTelemetryHelper m_telemetryHelper{};

Expand Down
6 changes: 6 additions & 0 deletions dev/Interop/StoragePickers/FileTypeChoicesMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "pch.h"
#include "FileTypeChoicesMap.h"
#include "FileTypeFilterVector.h"
#include "TerminalVelocityFeatures-StoragePickers2.h"

namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
{
Expand All @@ -13,6 +14,11 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation

bool FileTypeChoicesMap::Insert(hstring const& key, winrt::Windows::Foundation::Collections::IVector<hstring> const& value)
{
if (ForFeature_StoragePickers2)
{
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<FileTypeFilterVector>();

Expand Down
2 changes: 2 additions & 0 deletions dev/Interop/StoragePickers/FileTypeChoicesMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
{
FileTypeChoicesMap();

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curiosity - Can you explain the rationale behind this update?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is for velocity. The FileSavePicker already has FileTypeChoices, so it doesn't need an velocity check.
This PR is adding FileTypeChoices property to the FileOpenPicker, meaning that we need a velocity check when this customized map type is used for in the FIleOpenPicker.

In future when we remove this velocity, we can remove the forSavePicker flag too.
Note that this is an internal class, it should not impact the public API contract.

bool ForFeature_StoragePickers2{ false };

// IMap<hstring, IVector<hstring>>
winrt::Windows::Foundation::Collections::IVector<hstring> Lookup(hstring const& key) const;
uint32_t Size() const;
Expand Down
28 changes: 26 additions & 2 deletions dev/Interop/StoragePickers/FolderPicker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <shobjidl_core.h>
#include <winrt/Microsoft.UI.Interop.h>
#include "TerminalVelocityFeatures-StoragePickers.h"
#include "TerminalVelocityFeatures-StoragePickers2.h"
#include "PickerCommon.h"
#include "PickFolderResult.h"
#include "PickerLocalization.h"
Expand Down Expand Up @@ -47,15 +48,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<winrt::Microsoft::Windows::Storage::Pickers::PickFolderResult> FolderPicker::PickSingleFolderAsync()
{
// TODO: remove get strong reference when telementry is safe stop
Expand Down
8 changes: 8 additions & 0 deletions dev/Interop/StoragePickers/FolderPicker.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<winrt::Microsoft::Windows::Storage::Pickers::PickFolderResult> PickSingleFolderAsync();

private:
Expand All @@ -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);
Expand Down
Loading