diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln
index b3759be95e..e79cd9d891 100644
--- a/WindowsAppRuntime.sln
+++ b/WindowsAppRuntime.sln
@@ -678,6 +678,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloWorldAdvancedCS_NoThro
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BadgeNotificationTest", "test\BadgeNotificationTest\BadgeNotificationTest.vcxproj", "{7C8BEED1-7B27-41C5-A22F-9D6B4468F52A}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Windows.Storage.Pickers.Projection", "dev\Projections\CS\Microsoft.Windows.Storage.Pickers.Projection\Microsoft.Windows.Storage.Pickers.Projection.csproj", "{8E01AA4F-A16A-4E3F-A59F-6D49422B4410}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StoragePickers", "dev\Interop\StoragePickers\StoragePickers.vcxitems", "{A39E7B2F-5F67-47DD-8443-531D095CA7F3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StoragePickersTests", "test\StoragePickersTests\StoragePickersTests.vcxproj", "{85C86306-46D1-4563-8303-0A79DF923586}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -2348,6 +2354,38 @@ Global
{7C8BEED1-7B27-41C5-A22F-9D6B4468F52A}.Release|x64.Build.0 = Release|x64
{7C8BEED1-7B27-41C5-A22F-9D6B4468F52A}.Release|x86.ActiveCfg = Release|Win32
{7C8BEED1-7B27-41C5-A22F-9D6B4468F52A}.Release|x86.Build.0 = Release|Win32
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|Any CPU.Build.0 = Debug|x64
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|ARM64.ActiveCfg = Debug|arm64
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|ARM64.Build.0 = Debug|arm64
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|x64.ActiveCfg = Debug|x64
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|x64.Build.0 = Debug|x64
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|x86.ActiveCfg = Debug|x86
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|x86.Build.0 = Debug|x86
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|Any CPU.ActiveCfg = Release|x64
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|Any CPU.Build.0 = Release|x64
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|ARM64.ActiveCfg = Release|arm64
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|ARM64.Build.0 = Release|arm64
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|x64.ActiveCfg = Release|x64
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|x64.Build.0 = Release|x64
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|x86.ActiveCfg = Release|x86
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|x86.Build.0 = Release|x86
+ {85C86306-46D1-4563-8303-0A79DF923586}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {85C86306-46D1-4563-8303-0A79DF923586}.Debug|Any CPU.Build.0 = Debug|x64
+ {85C86306-46D1-4563-8303-0A79DF923586}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {85C86306-46D1-4563-8303-0A79DF923586}.Debug|ARM64.Build.0 = Debug|ARM64
+ {85C86306-46D1-4563-8303-0A79DF923586}.Debug|x64.ActiveCfg = Debug|x64
+ {85C86306-46D1-4563-8303-0A79DF923586}.Debug|x64.Build.0 = Debug|x64
+ {85C86306-46D1-4563-8303-0A79DF923586}.Debug|x86.ActiveCfg = Debug|Win32
+ {85C86306-46D1-4563-8303-0A79DF923586}.Debug|x86.Build.0 = Debug|Win32
+ {85C86306-46D1-4563-8303-0A79DF923586}.Release|Any CPU.ActiveCfg = Release|x64
+ {85C86306-46D1-4563-8303-0A79DF923586}.Release|Any CPU.Build.0 = Release|x64
+ {85C86306-46D1-4563-8303-0A79DF923586}.Release|ARM64.ActiveCfg = Release|ARM64
+ {85C86306-46D1-4563-8303-0A79DF923586}.Release|ARM64.Build.0 = Release|ARM64
+ {85C86306-46D1-4563-8303-0A79DF923586}.Release|x64.ActiveCfg = Release|x64
+ {85C86306-46D1-4563-8303-0A79DF923586}.Release|x64.Build.0 = Release|x64
+ {85C86306-46D1-4563-8303-0A79DF923586}.Release|x86.ActiveCfg = Release|Win32
+ {85C86306-46D1-4563-8303-0A79DF923586}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2553,6 +2591,9 @@ Global
{9369C7DD-430B-4B52-822A-231AA2791D23} = {63196919-AEA8-4EA8-BFB4-08CE824249A3}
{9D26A965-065A-4897-B476-4F15B0F5A19F} = {63196919-AEA8-4EA8-BFB4-08CE824249A3}
{7C8BEED1-7B27-41C5-A22F-9D6B4468F52A} = {1FDC307C-2DB7-4B40-8F18-F1057E9E0969}
+ {8E01AA4F-A16A-4E3F-A59F-6D49422B4410} = {716C26A0-E6B0-4981-8412-D14A4D410531}
+ {A39E7B2F-5F67-47DD-8443-531D095CA7F3} = {3B706C5C-55E0-4B76-BF59-89E20FE46795}
+ {85C86306-46D1-4563-8303-0A79DF923586} = {8630F7AA-2969-4DC9-8700-9B468C1DC21D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4B3D7591-CFEC-4762-9A07-ABE99938FB77}
@@ -2579,6 +2620,7 @@ Global
dev\PackageManager\API\PackageManager.vcxitems*{8a9a0c85-65a8-4bca-a49e-45fc4fdbc7d2}*SharedItemsImports = 9
test\inc\inc.vcxitems*{8e52d7ea-a200-4a6b-ba74-8efb49468caf}*SharedItemsImports = 4
dev\Interop\CameraCaptureUI\CameraCaptureUI\CameraCaptureUI.vcxitems*{95409d1e-843f-4316-8d8e-471b3e203f94}*SharedItemsImports = 9
+ dev\Interop\StoragePickers\StoragePickers.vcxitems*{a39e7b2f-5f67-47dd-8443-531d095ca7f3}*SharedItemsImports = 9
dev\AppNotifications\AppNotifications.vcxitems*{b4824897-88e0-4927-8fb9-e60106f01ed9}*SharedItemsImports = 9
test\inc\inc.vcxitems*{b567fe2e-3a03-48d0-b2b5-760cdec35891}*SharedItemsImports = 9
dev\ApplicationData\ApplicationData.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4
diff --git a/build/AzurePipelinesTemplates/WindowsAppSDK-SetupBuildEnvironment-Steps.yml b/build/AzurePipelinesTemplates/WindowsAppSDK-SetupBuildEnvironment-Steps.yml
index 46ebe1f9df..a8d8deb6f8 100644
--- a/build/AzurePipelinesTemplates/WindowsAppSDK-SetupBuildEnvironment-Steps.yml
+++ b/build/AzurePipelinesTemplates/WindowsAppSDK-SetupBuildEnvironment-Steps.yml
@@ -187,6 +187,14 @@ steps:
arguments: -Path $(Build.SourcesDirectory)\dev\common\TerminalVelocityFeatures-CameraCaptureUI.xml -Channel $(channel) -Language C++ -Namespace Microsoft.Windows.Media.Capture -Output $(Build.SourcesDirectory)\dev\common\TerminalVelocityFeatures-CameraCaptureUI.h
workingDirectory: '$(Build.SourcesDirectory)'
+- task: powershell@2
+ displayName: 'Create OAuth2Manager TerminalVelocity features'
+ inputs:
+ targetType: filePath
+ filePath: tools\TerminalVelocity\Generate-TerminalVelocityFeatures.ps1
+ arguments: -Path $(Build.SourcesDirectory)\dev\common\TerminalVelocityFeatures-StoragePickers.xml -Channel $(channel) -Language C++ -Namespace Microsoft.Windows.Storage.Pickers -Output $(Build.SourcesDirectory)\dev\common\TerminalVelocityFeatures-StoragePickers.h
+ workingDirectory: '$(Build.SourcesDirectory)'
+
- task: powershell@2
displayName: 'Create OAuth2Manager TerminalVelocity features'
inputs:
diff --git a/build/CopyFilesToStagingDir.ps1 b/build/CopyFilesToStagingDir.ps1
index 3c280a1ad9..90ec0cf422 100644
--- a/build/CopyFilesToStagingDir.ps1
+++ b/build/CopyFilesToStagingDir.ps1
@@ -56,6 +56,7 @@ PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windo
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.BadgeNotifications.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Management.Deployment.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Media.Capture.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
+PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Storage.Pickers.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.PushNotifications.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Security.AccessControl.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Security.Authentication.OAuth.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\
@@ -129,6 +130,8 @@ PublishFile $FullBuildOutput\Microsoft.Windows.Management.Deployment.Projection\
PublishFile $FullBuildOutput\Microsoft.Windows.Management.Deployment.Projection\Microsoft.Windows.Management.Deployment.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0
PublishFile $FullBuildOutput\Microsoft.Windows.Media.Capture.Projection\Microsoft.Windows.Media.Capture.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0
PublishFile $FullBuildOutput\Microsoft.Windows.Media.Capture.Projection\Microsoft.Windows.Media.Capture.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0
+PublishFile $FullBuildOutput\Microsoft.Windows.Storage.Pickers.Projection\Microsoft.Windows.Storage.Pickers.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0
+PublishFile $FullBuildOutput\Microsoft.Windows.Storage.Pickers.Projection\Microsoft.Windows.Storage.Pickers.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0
PublishFile $FullBuildOutput\Microsoft.Windows.PushNotifications.Projection\Microsoft.Windows.PushNotifications.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0
PublishFile $FullBuildOutput\Microsoft.Windows.PushNotifications.Projection\Microsoft.Windows.PushNotifications.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0
PublishFile $FullBuildOutput\Microsoft.Windows.Security.AccessControl.Projection\Microsoft.Windows.Security.AccessControl.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0
@@ -206,6 +209,7 @@ PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windo
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.BadgeNotifications.winmd $NugetDir\lib\uap10.0
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Management.Deployment.winmd $NugetDir\lib\uap10.0
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Media.Capture.winmd $NugetDir\lib\uap10.0
+PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Storage.Pickers.winmd $NugetDir\lib\uap10.0
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.PushNotifications.winmd $NugetDir\lib\uap10.0
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Security.AccessControl.winmd $NugetDir\lib\uap10.0
PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Security.Authentication.OAuth.winmd $NugetDir\lib\uap10.0
diff --git a/build/NuSpecs/AppxManifest.xml b/build/NuSpecs/AppxManifest.xml
index 23bafeec28..12fe8e6c5f 100644
--- a/build/NuSpecs/AppxManifest.xml
+++ b/build/NuSpecs/AppxManifest.xml
@@ -116,6 +116,11 @@
+
+
+
+
+
diff --git a/build/NuSpecs/WindowsAppSDK-Nuget-Native.WinRt.props b/build/NuSpecs/WindowsAppSDK-Nuget-Native.WinRt.props
index 45fe60f31a..e99257f152 100644
--- a/build/NuSpecs/WindowsAppSDK-Nuget-Native.WinRt.props
+++ b/build/NuSpecs/WindowsAppSDK-Nuget-Native.WinRt.props
@@ -81,6 +81,12 @@
$(MSBuildThisFileDirectory)..\..\runtimes\win10-$(_WindowsAppSDKFoundationPlatform)\native\Microsoft.WindowsAppRuntime.dll
true
+
+ $(MSBuildThisFileDirectory)..\..\lib\uap10.0\Microsoft.Windows.Storage.Pickers.winmd
+ $(MSBuildThisFileDirectory)..\..\runtimes\win10-$(_WindowsAppSDKFoundationPlatform)\native\Microsoft.WindowsAppRuntime.dll
+ true
+
diff --git a/build/NuSpecs/WindowsAppSDK-Nuget-Native.targets b/build/NuSpecs/WindowsAppSDK-Nuget-Native.targets
index a51d55d97c..ae295ae46f 100644
--- a/build/NuSpecs/WindowsAppSDK-Nuget-Native.targets
+++ b/build/NuSpecs/WindowsAppSDK-Nuget-Native.targets
@@ -143,6 +143,14 @@
+
+
+ false
+ Microsoft.WindowsAppRuntime.dll
+
+
+
diff --git a/dev/Common/TerminalVelocityFeatures-StoragePickers.h b/dev/Common/TerminalVelocityFeatures-StoragePickers.h
new file mode 100644
index 0000000000..85d77e743d
--- /dev/null
+++ b/dev/Common/TerminalVelocityFeatures-StoragePickers.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-StoragePickers.xml
+// OPTIONS: -Channel Experimental -Language C++ -Namespace Microsoft.Windows.Storage.Pickers -Path dev\Common\TerminalVelocityFeatures-StoragePickers.xml -Output dev\Common\TerminalVelocityFeatures-StoragePickers.h
+
+#if defined(__midlrt)
+namespace features
+{
+ feature_name Feature_StoragePickers = { DisabledByDefault, FALSE };
+}
+#endif // defined(__midlrt)
+
+// Feature constants
+#define WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_STORAGE_PICKERS_FEATURE_STORAGEPICKERS_ENABLED 1
+
+#if defined(__cplusplus)
+
+namespace Microsoft::Windows::Storage::Pickers
+{
+
+__pragma(detect_mismatch("ODR_violation_WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_STORAGE_PICKERS_FEATURE_STORAGEPICKERS_ENABLED_mismatch", "AlwaysEnabled"))
+struct Feature_StoragePickers
+{
+ static constexpr bool IsEnabled() { return WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_STORAGE_PICKERS_FEATURE_STORAGEPICKERS_ENABLED == 1; }
+};
+
+} // namespace Microsoft.Windows.Storage.Pickers
+
+#endif // defined(__cplusplus)
diff --git a/dev/Common/TerminalVelocityFeatures-StoragePickers.xml b/dev/Common/TerminalVelocityFeatures-StoragePickers.xml
new file mode 100644
index 0000000000..123cf78ecb
--- /dev/null
+++ b/dev/Common/TerminalVelocityFeatures-StoragePickers.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+ Feature_StoragePickers
+ StoragePickers for the WindowsAppRuntime
+ AlwaysEnabled
+
+ Preview
+ Stable
+
+
+
diff --git a/dev/Interop/StoragePickers/FileOpenPicker.cpp b/dev/Interop/StoragePickers/FileOpenPicker.cpp
new file mode 100644
index 0000000000..7f6181c946
--- /dev/null
+++ b/dev/Interop/StoragePickers/FileOpenPicker.cpp
@@ -0,0 +1,190 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "FileOpenPicker.h"
+#include "Microsoft.Windows.Storage.Pickers.FileOpenPicker.g.cpp"
+#include "StoragePickersTelemetry.h"
+#include
+#include
+#include
+#include
+#include "PickerCommon.h"
+#include "PickFileResult.h"
+
+namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
+{
+ FileOpenPicker::FileOpenPicker(winrt::Microsoft::UI::WindowId const& windowId)
+ : m_windowId(windowId)
+ {
+ THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers::IsEnabled());
+ }
+
+ winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode FileOpenPicker::ViewMode()
+ {
+ return m_viewMode;
+ }
+ void FileOpenPicker::ViewMode(winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode const& value)
+ {
+ m_viewMode = value;
+ }
+ hstring FileOpenPicker::SettingsIdentifier()
+ {
+ return m_settingsIdentifier;
+ }
+ void FileOpenPicker::SettingsIdentifier(hstring const& value)
+ {
+ m_settingsIdentifier = value;
+ }
+ winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId FileOpenPicker::SuggestedStartLocation()
+ {
+ return m_suggestedStartLocation;
+ }
+ void FileOpenPicker::SuggestedStartLocation(winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId const& value)
+ {
+ m_suggestedStartLocation = value;
+ }
+ winrt::hstring FileOpenPicker::CommitButtonText()
+ {
+ return m_commitButtonText;
+ }
+ void FileOpenPicker::CommitButtonText(winrt::hstring const& value)
+ {
+ m_commitButtonText = value;
+ }
+ winrt::Windows::Foundation::Collections::IVector FileOpenPicker::FileTypeFilter()
+ {
+ return m_fileTypeFilter;
+ }
+
+ void FileOpenPicker::CaptureParameters(PickerCommon::PickerParameters& parameters)
+ {
+ parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId);
+ parameters.CommitButtonText = m_commitButtonText;
+ parameters.SettingsIdentifierId = m_settingsIdentifier;
+ parameters.PickerLocationId = m_suggestedStartLocation;
+ parameters.FileTypeFilterPara = PickerCommon::CaptureFilterSpec(parameters.FileTypeFilterData, m_fileTypeFilter.GetView());
+ }
+
+ winrt::Windows::Foundation::IAsyncOperation FileOpenPicker::PickSingleFileAsync()
+ {
+ // TODO: remove get strong reference when telementry is safe stop
+ auto lifetime { get_strong() };
+
+ auto logTelemetry{ StoragePickersTelemetry::FileOpenPickerPickSingleFile::Start(m_telemetryHelper) };
+
+ PickerCommon::PickerParameters parameters{};
+
+ CaptureParameters(parameters);
+
+ auto cancellationToken = co_await winrt::get_cancellation_token();
+ cancellationToken.enable_propagation(true);
+ co_await winrt::resume_background();
+
+ if (cancellationToken())
+ {
+ logTelemetry.Stop(m_telemetryHelper, false);
+ co_return nullptr;
+ }
+
+ auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL);
+
+ parameters.ConfigureDialog(dialog);
+
+ {
+ auto hr = dialog->Show(parameters.HWnd);
+ if (FAILED(hr) || cancellationToken())
+ {
+ logTelemetry.Stop(m_telemetryHelper, false);
+ co_return nullptr;
+ }
+ }
+
+ winrt::com_ptr shellItem{};
+ check_hresult(dialog->GetResult(shellItem.put()));
+ auto path = PickerCommon::GetPathFromShellItem(shellItem);
+
+ if (cancellationToken())
+ {
+ logTelemetry.Stop(m_telemetryHelper, false);
+ co_return nullptr;
+ }
+
+ auto result = make(path);
+
+ logTelemetry.Stop(m_telemetryHelper, true);
+ co_return result;
+ }
+
+ winrt::Windows::Foundation::IAsyncOperation > FileOpenPicker::PickMultipleFilesAsync()
+ {
+ // TODO: remove get strong reference when telementry is safe stop
+ auto lifetime { get_strong() };
+
+ auto logTelemetry{ StoragePickersTelemetry::FileOpenPickerPickMultipleFile::Start(m_telemetryHelper) };
+
+ // capture parameters to avoid using get strong referece of picker
+ PickerCommon::PickerParameters parameters{};
+ CaptureParameters(parameters);
+
+ auto cancellationToken = co_await winrt::get_cancellation_token();
+ cancellationToken.enable_propagation(true);
+ co_await winrt::resume_background();
+
+ winrt::Windows::Foundation::Collections::IVector results{ winrt::single_threaded_vector() };
+
+ if (cancellationToken())
+ {
+ logTelemetry.Stop(m_telemetryHelper, true, false);
+ co_return results.GetView();
+ }
+
+ auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL);
+
+ parameters.ConfigureDialog(dialog);
+
+ check_hresult(dialog->SetOptions(FOS_ALLOWMULTISELECT));
+
+ {
+ auto hr = dialog->Show(parameters.HWnd);
+ if (FAILED(hr) || cancellationToken())
+ {
+ logTelemetry.Stop(m_telemetryHelper, true, false);
+ co_return results.GetView();
+ }
+ }
+
+ winrt::com_ptr shellItems{};
+ check_hresult(dialog->GetResults(shellItems.put()));
+
+ DWORD itemCount = 0;
+ check_hresult(shellItems->GetCount(&itemCount));
+
+ winrt::com_ptr shellItem{};
+ for (DWORD i = 0; i < itemCount; i++)
+ {
+ check_hresult(shellItems->GetItemAt(i, shellItem.put()));
+ auto path = PickerCommon::GetPathFromShellItem(shellItem);
+ auto result{ make(path) };
+ results.Append(result);
+ }
+
+ bool isCancelled = false;
+ if (cancellationToken())
+ {
+ results.Clear();
+ isCancelled = true;
+ }
+ auto resultView = results.GetView();
+
+ if (results.Size() > 0)
+ {
+ logTelemetry.Stop(m_telemetryHelper, isCancelled, true);
+ }
+ else
+ {
+ logTelemetry.Stop(m_telemetryHelper, isCancelled, false);
+ }
+ co_return resultView;
+ }
+}
diff --git a/dev/Interop/StoragePickers/FileOpenPicker.h b/dev/Interop/StoragePickers/FileOpenPicker.h
new file mode 100644
index 0000000000..208025488d
--- /dev/null
+++ b/dev/Interop/StoragePickers/FileOpenPicker.h
@@ -0,0 +1,49 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+#include "Microsoft.Windows.Storage.Pickers.FileOpenPicker.g.h"
+#include "PickerCommon.h"
+#include "StoragePickersTelemetryHelper.h"
+
+namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
+{
+ struct FileOpenPicker : FileOpenPickerT
+ {
+ FileOpenPicker(winrt::Microsoft::UI::WindowId const& windowId);
+
+ winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode ViewMode();
+ void ViewMode(winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode const& value);
+
+ hstring SettingsIdentifier();
+ void SettingsIdentifier(hstring const& value);
+
+ winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId SuggestedStartLocation();
+ void SuggestedStartLocation(winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId const& value);
+
+ winrt::hstring CommitButtonText();
+ void CommitButtonText(winrt::hstring const& value);
+
+ winrt::Windows::Foundation::Collections::IVector FileTypeFilter();
+
+ winrt::Windows::Foundation::IAsyncOperation PickSingleFileAsync();
+ winrt::Windows::Foundation::IAsyncOperation> PickMultipleFilesAsync();
+
+ private:
+ winrt::Microsoft::UI::WindowId m_windowId{};
+ PickerViewMode m_viewMode{ PickerViewMode::List };
+ winrt::hstring m_settingsIdentifier{};
+ PickerLocationId m_suggestedStartLocation{ PickerLocationId::Unspecified };
+ winrt::hstring m_commitButtonText{};
+ winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ winrt::single_threaded_vector() };
+ StoragePickersTelemetryHelper m_telemetryHelper{};
+
+ void CaptureParameters(PickerCommon::PickerParameters& parameters);
+ };
+}
+namespace winrt::Microsoft::Windows::Storage::Pickers::factory_implementation
+{
+ struct FileOpenPicker : FileOpenPickerT
+ {
+ };
+}
diff --git a/dev/Interop/StoragePickers/FileSavePicker.cpp b/dev/Interop/StoragePickers/FileSavePicker.cpp
new file mode 100644
index 0000000000..339cfaea9a
--- /dev/null
+++ b/dev/Interop/StoragePickers/FileSavePicker.cpp
@@ -0,0 +1,187 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "FileSavePicker.h"
+#include "Microsoft.Windows.Storage.Pickers.FileSavePicker.g.cpp"
+#include "StoragePickersTelemetry.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "PickerCommon.h"
+#include "PickFileResult.h"
+
+namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
+{
+
+ FileSavePicker::FileSavePicker(winrt::Microsoft::UI::WindowId const& windowId)
+ : m_windowId(windowId)
+ {
+ THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers::IsEnabled());
+ }
+ hstring FileSavePicker::SettingsIdentifier()
+ {
+ return m_settingsIdentifier;
+ }
+ void FileSavePicker::SettingsIdentifier(hstring const& value)
+ {
+ m_settingsIdentifier = value;
+ }
+ winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId FileSavePicker::SuggestedStartLocation()
+ {
+ return m_suggestedStartLocation;
+ }
+ void FileSavePicker::SuggestedStartLocation(winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId const& value)
+ {
+ m_suggestedStartLocation = value;
+ }
+ hstring FileSavePicker::CommitButtonText()
+ {
+ return m_commitButtonText;
+ }
+ void FileSavePicker::CommitButtonText(hstring const& value)
+ {
+ m_commitButtonText = value;
+ }
+ winrt::Windows::Foundation::Collections::IMap> FileSavePicker::FileTypeChoices()
+ {
+ return m_fileTypeChoices;
+ }
+ hstring FileSavePicker::DefaultFileExtension()
+ {
+ return m_defaultFileExtension;
+ }
+ void FileSavePicker::DefaultFileExtension(hstring const& value)
+ {
+ m_defaultFileExtension = value;
+ }
+ winrt::Windows::Storage::StorageFile FileSavePicker::SuggestedSaveFile()
+ {
+ return m_suggestedSaveFile;
+ }
+ void FileSavePicker::SuggestedSaveFile(winrt::Windows::Storage::StorageFile const& value)
+ {
+ m_suggestedSaveFile = value;
+ }
+ hstring FileSavePicker::SuggestedFileName()
+ {
+ return m_suggestedFileName;
+ }
+ void FileSavePicker::SuggestedFileName(hstring const& value)
+ {
+ m_suggestedFileName = value;
+ }
+
+
+ void FileSavePicker::CaptureParameters(PickerCommon::PickerParameters& parameters)
+ {
+ parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId);
+ parameters.CommitButtonText = m_commitButtonText;
+ parameters.SettingsIdentifierId = m_settingsIdentifier;
+ parameters.PickerLocationId = m_suggestedStartLocation;
+ parameters.FileTypeFilterPara = PickerCommon::CaptureFilterSpec(parameters.FileTypeFilterData, m_fileTypeChoices.GetView());
+
+ }
+
+ winrt::Windows::Foundation::IAsyncOperation FileSavePicker::PickSaveFileAsync()
+ {
+ // TODO: remove get strong reference when telementry is safe stop
+ auto lifetime{ get_strong() };
+
+ auto logTelemetry{ StoragePickersTelemetry::FileSavePickerPickSingleFile::Start(m_telemetryHelper) };
+
+ PickerCommon::PickerParameters parameters{};
+ CaptureParameters(parameters);
+ auto defaultFileExtension = m_defaultFileExtension;
+ auto suggestedSaveFile = m_suggestedSaveFile;
+ auto suggestedFileName = m_suggestedFileName;
+ auto fileTypeChoices = m_fileTypeChoices;
+
+ auto cancellationToken = co_await winrt::get_cancellation_token();
+ cancellationToken.enable_propagation(true);
+ co_await winrt::resume_background();
+
+ if (cancellationToken())
+ {
+ logTelemetry.Stop(m_telemetryHelper, false);
+ co_return nullptr;
+ }
+
+ auto dialog = create_instance(CLSID_FileSaveDialog, CONTEXT_ALL);
+ parameters.ConfigureDialog(dialog);
+
+ if (!PickerCommon::IsHStringNullOrEmpty(defaultFileExtension))
+ {
+ check_hresult(dialog->SetDefaultExtension(defaultFileExtension.c_str()));
+ }
+
+ if (!PickerCommon::IsHStringNullOrEmpty(suggestedFileName))
+ {
+ check_hresult(dialog->SetFileName(suggestedFileName.c_str()));
+ }
+
+ if (suggestedSaveFile != nullptr)
+ {
+ winrt::com_ptr shellItem;
+ check_hresult(SHCreateItemFromParsingName(suggestedSaveFile.Path().c_str(), nullptr, IID_PPV_ARGS(shellItem.put())));
+ check_hresult(dialog->SetSaveAsItem(shellItem.get()));
+ }
+
+ {
+ auto hr = dialog->Show(parameters.HWnd);
+ if (FAILED(hr))
+ {
+ logTelemetry.Stop(m_telemetryHelper, false);
+ co_return nullptr;
+ }
+ }
+
+ winrt::com_ptr shellItem{};
+ check_hresult(dialog->GetResult(shellItem.put()));
+
+ // Get the file path from the dialog
+ wil::unique_cotaskmem_string filePath{};
+ check_hresult(shellItem->GetDisplayName(SIGDN_FILESYSPATH, filePath.put()));
+ winrt::hstring pathStr(filePath.get());
+
+ wil::unique_cotaskmem_string fileName;
+ check_hresult(shellItem->GetDisplayName(SIGDN_NORMALDISPLAY, fileName.put()));
+ std::wstring fileNameStr(fileName.get());
+
+ // Check if the file name has an extension
+ if ((fileNameStr.find_last_of(L".") == std::wstring::npos) && (fileTypeChoices.Size() > 0))
+ {
+ // If the user defined file name doesn't have an extension,
+ // automatically use the first extension from the first category in fileTypeChoices.
+ auto firstCategory = fileTypeChoices.First().Current();
+ auto value = firstCategory.Value();
+ if (value.Size() > 0)
+ {
+ auto firstExtension = value.GetAt(0);
+ pathStr = pathStr + firstExtension;
+ }
+ }
+
+ // Create a file. If the file already exists,
+ // since common item dialog prompts to let user select cancel or override, thus we can safely truncate here.
+ // Due to our design spec to align with UWP pickers, we need ensure existance of picked file.
+ auto [handle, _] = wil::try_open_or_truncate_existing_file(pathStr.c_str(), GENERIC_WRITE);
+
+ if (cancellationToken())
+ {
+ logTelemetry.Stop(m_telemetryHelper, false);
+ co_return nullptr;
+ }
+
+ auto result = make(pathStr);
+
+ logTelemetry.Stop(m_telemetryHelper, true);
+ co_return result;
+ }
+}
diff --git a/dev/Interop/StoragePickers/FileSavePicker.h b/dev/Interop/StoragePickers/FileSavePicker.h
new file mode 100644
index 0000000000..92825d661f
--- /dev/null
+++ b/dev/Interop/StoragePickers/FileSavePicker.h
@@ -0,0 +1,58 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+#include "Microsoft.Windows.Storage.Pickers.FileSavePicker.g.h"
+#include "PickerCommon.h"
+#include "StoragePickersTelemetryHelper.h"
+
+namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
+{
+ struct FileSavePickerParameters;
+
+ struct FileSavePicker : FileSavePickerT
+ {
+ FileSavePicker(winrt::Microsoft::UI::WindowId const& windowId);
+
+ hstring SettingsIdentifier();
+ void SettingsIdentifier(hstring const& value);
+
+ winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId SuggestedStartLocation();
+ void SuggestedStartLocation(winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId const& value);
+
+ hstring CommitButtonText();
+ void CommitButtonText(hstring const& value);
+
+ winrt::Windows::Foundation::Collections::IMap> FileTypeChoices();
+
+ hstring DefaultFileExtension();
+ void DefaultFileExtension(hstring const& value);
+
+ winrt::Windows::Storage::StorageFile SuggestedSaveFile();
+ void SuggestedSaveFile(winrt::Windows::Storage::StorageFile const& value);
+
+ hstring SuggestedFileName();
+ void SuggestedFileName(hstring const& value);
+
+ winrt::Windows::Foundation::IAsyncOperation PickSaveFileAsync();
+
+ private:
+ winrt::Microsoft::UI::WindowId m_windowId{};
+ hstring m_settingsIdentifier{};
+ PickerLocationId m_suggestedStartLocation{ PickerLocationId::Unspecified };
+ hstring m_commitButtonText{};
+ winrt::Windows::Foundation::Collections::IMap> m_fileTypeChoices{ winrt::single_threaded_map>() };
+ hstring m_defaultFileExtension{};
+ winrt::Windows::Storage::StorageFile m_suggestedSaveFile{ nullptr };
+ hstring m_suggestedFileName{};
+ StoragePickersTelemetryHelper m_telemetryHelper{};
+
+ void CaptureParameters(PickerCommon::PickerParameters& parameters);
+ };
+}
+namespace winrt::Microsoft::Windows::Storage::Pickers::factory_implementation
+{
+ struct FileSavePicker : FileSavePickerT
+ {
+ };
+}
diff --git a/dev/Interop/StoragePickers/FolderPicker.cpp b/dev/Interop/StoragePickers/FolderPicker.cpp
new file mode 100644
index 0000000000..42b8aaa5f4
--- /dev/null
+++ b/dev/Interop/StoragePickers/FolderPicker.cpp
@@ -0,0 +1,117 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "FolderPicker.h"
+#include "Microsoft.Windows.Storage.Pickers.FolderPicker.g.cpp"
+#include "StoragePickersTelemetry.h"
+#include
+#include
+#include
+#include "PickerCommon.h"
+#include "PickFolderResult.h"
+
+namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
+{
+ FolderPicker::FolderPicker(winrt::Microsoft::UI::WindowId const& windowId)
+ : m_windowId(windowId)
+ {
+ THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers::IsEnabled());
+ }
+ winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode FolderPicker::ViewMode()
+ {
+ return m_viewMode;
+ }
+ void FolderPicker::ViewMode(winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode const& value)
+ {
+ m_viewMode = value;
+ }
+ hstring FolderPicker::SettingsIdentifier()
+ {
+ return m_settingsIdentifier;
+ }
+ void FolderPicker::SettingsIdentifier(hstring const& value)
+ {
+ m_settingsIdentifier = value;
+ }
+ winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId FolderPicker::SuggestedStartLocation()
+ {
+ return m_suggestedStartLocation;
+ }
+ void FolderPicker::SuggestedStartLocation(winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId const& value)
+ {
+ m_suggestedStartLocation = value;
+ }
+ hstring FolderPicker::CommitButtonText()
+ {
+ return m_commitButtonText;
+ }
+ void FolderPicker::CommitButtonText(hstring const& value)
+ {
+ m_commitButtonText = value;
+ }
+ winrt::Windows::Foundation::Collections::IVector FolderPicker::FileTypeFilter()
+ {
+ return m_fileTypeFilter;
+ }
+
+ void FolderPicker::CaptureParameters(PickerCommon::PickerParameters& parameters)
+ {
+ parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId);
+ parameters.CommitButtonText = m_commitButtonText;
+ parameters.SettingsIdentifierId = m_settingsIdentifier;
+ parameters.PickerLocationId = m_suggestedStartLocation;
+ parameters.FileTypeFilterPara = PickerCommon::CaptureFilterSpec(parameters.FileTypeFilterData, m_fileTypeFilter.GetView());
+ }
+
+
+ winrt::Windows::Foundation::IAsyncOperation FolderPicker::PickSingleFolderAsync()
+ {
+ // TODO: remove get strong reference when telementry is safe stop
+ auto lifetime{ get_strong() };
+
+ auto logTelemetry{ StoragePickersTelemetry::FolderPickerPickSingleFolder::Start(m_telemetryHelper) };
+
+ PickerCommon::PickerParameters parameters{};
+ CaptureParameters(parameters);
+
+ auto cancellationToken = co_await winrt::get_cancellation_token();
+ cancellationToken.enable_propagation(true);
+ co_await winrt::resume_background();
+
+ if (cancellationToken())
+ {
+ logTelemetry.Stop(m_telemetryHelper, false);
+ co_return nullptr;
+ }
+
+ auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL);
+
+ parameters.ConfigureDialog(dialog);
+ dialog->SetOptions(FOS_PICKFOLDERS);
+
+ {
+ auto hr = dialog->Show(parameters.HWnd);
+ if (FAILED(hr) || cancellationToken())
+ {
+ logTelemetry.Stop(m_telemetryHelper, false);
+ co_return nullptr;
+ }
+ }
+
+ winrt::com_ptr shellItem{};
+ check_hresult(dialog->GetResult(shellItem.put()));
+ auto path = PickerCommon::GetPathFromShellItem(shellItem);
+
+ if (cancellationToken())
+ {
+ logTelemetry.Stop(m_telemetryHelper, false);
+ co_return nullptr;
+ }
+
+ auto result = make(path);
+
+ logTelemetry.Stop(m_telemetryHelper, true);
+ co_return result;
+ }
+}
diff --git a/dev/Interop/StoragePickers/FolderPicker.h b/dev/Interop/StoragePickers/FolderPicker.h
new file mode 100644
index 0000000000..6bd8f2e718
--- /dev/null
+++ b/dev/Interop/StoragePickers/FolderPicker.h
@@ -0,0 +1,50 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+#include "Microsoft.Windows.Storage.Pickers.FolderPicker.g.h"
+#include "PickerCommon.h"
+#include "StoragePickersTelemetryHelper.h"
+
+namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
+{
+ struct FolderPicker : FolderPickerT
+ {
+ FolderPicker(winrt::Microsoft::UI::WindowId const& windowId);
+
+ winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode ViewMode();
+ void ViewMode(winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode const& value);
+
+ hstring SettingsIdentifier();
+ void SettingsIdentifier(hstring const& value);
+
+ winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId SuggestedStartLocation();
+ void SuggestedStartLocation(winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId const& value);
+
+ hstring CommitButtonText();
+ void CommitButtonText(hstring const& value);
+
+ winrt::Windows::Foundation::Collections::IVector FileTypeFilter();
+
+ winrt::Windows::Foundation::IAsyncOperation PickSingleFolderAsync();
+
+ private:
+ winrt::Microsoft::UI::WindowId m_windowId{};
+
+ PickerViewMode m_viewMode{ PickerViewMode::List };
+ hstring m_settingsIdentifier{};
+ PickerLocationId m_suggestedStartLocation{ PickerLocationId::Unspecified };
+ hstring m_commitButtonText{};
+ StoragePickersTelemetryHelper m_telemetryHelper{};
+
+ winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ winrt::single_threaded_vector() };
+
+ void CaptureParameters(PickerCommon::PickerParameters& parameters);
+ };
+}
+namespace winrt::Microsoft::Windows::Storage::Pickers::factory_implementation
+{
+ struct FolderPicker : FolderPickerT
+ {
+ };
+}
diff --git a/dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl b/dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl
new file mode 100644
index 0000000000..55a64b4fe8
--- /dev/null
+++ b/dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl
@@ -0,0 +1,85 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include
+namespace Microsoft.Windows.Storage.Pickers
+{
+ [feature(Feature_StoragePickers)]
+ enum PickerViewMode
+ {
+ List,
+ Thumbnail,
+ };
+
+ [feature(Feature_StoragePickers)]
+ enum PickerLocationId
+ {
+ DocumentsLibrary,
+ ComputerFolder,
+ Desktop,
+ Downloads,
+ HomeGroup,
+ MusicLibrary,
+ PicturesLibrary,
+ VideosLibrary,
+ Objects3D,
+ Unspecified,
+ };
+
+ [feature(Feature_StoragePickers)]
+ runtimeclass PickFileResult
+ {
+ String Path { get; };
+ }
+
+ [feature(Feature_StoragePickers)]
+ runtimeclass FileOpenPicker
+ {
+ FileOpenPicker(Microsoft.UI.WindowId windowId);
+
+ Microsoft.Windows.Storage.Pickers.PickerViewMode ViewMode;
+ String SettingsIdentifier;
+ Microsoft.Windows.Storage.Pickers.PickerLocationId SuggestedStartLocation;
+ String CommitButtonText;
+ Windows.Foundation.Collections.IVector FileTypeFilter{ get; };
+
+ [remote_sync] Windows.Foundation.IAsyncOperation PickSingleFileAsync();
+ [remote_sync] Windows.Foundation.IAsyncOperation > PickMultipleFilesAsync();
+ }
+
+ [feature(Feature_StoragePickers)]
+ runtimeclass FileSavePicker
+ {
+ FileSavePicker(Microsoft.UI.WindowId windowId);
+
+ String SettingsIdentifier;
+ Microsoft.Windows.Storage.Pickers.PickerLocationId SuggestedStartLocation;
+ String CommitButtonText;
+ Windows.Foundation.Collections.IMap > FileTypeChoices{ get; };
+ String DefaultFileExtension;
+ Windows.Storage.StorageFile SuggestedSaveFile;
+ String SuggestedFileName;
+
+ [remote_sync] Windows.Foundation.IAsyncOperation PickSaveFileAsync();
+ }
+
+ [feature(Feature_StoragePickers)]
+ runtimeclass PickFolderResult
+ {
+ String Path { get; };
+ }
+
+ [feature(Feature_StoragePickers)]
+ runtimeclass FolderPicker
+ {
+ FolderPicker(Microsoft.UI.WindowId windowId);
+
+ Microsoft.Windows.Storage.Pickers.PickerViewMode ViewMode;
+ String SettingsIdentifier;
+ Microsoft.Windows.Storage.Pickers.PickerLocationId SuggestedStartLocation;
+ String CommitButtonText;
+ Windows.Foundation.Collections.IVector FileTypeFilter{ get; };
+
+ [remote_sync] Windows.Foundation.IAsyncOperation PickSingleFolderAsync();
+ }
+}
diff --git a/dev/Interop/StoragePickers/PickFileResult.cpp b/dev/Interop/StoragePickers/PickFileResult.cpp
new file mode 100644
index 0000000000..c2029e3757
--- /dev/null
+++ b/dev/Interop/StoragePickers/PickFileResult.cpp
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "PickFileResult.h"
+#include "Microsoft.Windows.Storage.Pickers.PickFileResult.g.cpp"
+
+namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
+{
+ PickFileResult::PickFileResult(hstring const& path) :
+ m_path(path)
+ {
+ }
+
+ hstring PickFileResult::Path()
+ {
+ return m_path;
+ }
+}
diff --git a/dev/Interop/StoragePickers/PickFileResult.h b/dev/Interop/StoragePickers/PickFileResult.h
new file mode 100644
index 0000000000..36e6dee336
--- /dev/null
+++ b/dev/Interop/StoragePickers/PickFileResult.h
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+#include "Microsoft.Windows.Storage.Pickers.PickFileResult.g.h"
+#include "PickerCommon.h"
+
+namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
+{
+ struct PickFileResult : PickFileResultT
+ {
+ PickFileResult() = default;
+
+ PickFileResult(winrt::hstring const& path);
+
+ hstring Path();
+
+ private:
+ hstring m_path{};
+ };
+}
diff --git a/dev/Interop/StoragePickers/PickFolderResult.cpp b/dev/Interop/StoragePickers/PickFolderResult.cpp
new file mode 100644
index 0000000000..2e61733811
--- /dev/null
+++ b/dev/Interop/StoragePickers/PickFolderResult.cpp
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "PickFolderResult.h"
+#include "Microsoft.Windows.Storage.Pickers.PickFolderResult.g.cpp"
+
+namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
+{
+ PickFolderResult::PickFolderResult(winrt::hstring const& path)
+ : m_path(path)
+ {
+ }
+
+ hstring PickFolderResult::Path()
+ {
+ return m_path;
+ }
+}
diff --git a/dev/Interop/StoragePickers/PickFolderResult.h b/dev/Interop/StoragePickers/PickFolderResult.h
new file mode 100644
index 0000000000..3fa4c827ed
--- /dev/null
+++ b/dev/Interop/StoragePickers/PickFolderResult.h
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+#include "Microsoft.Windows.Storage.Pickers.PickFolderResult.g.h"
+#include "PickerCommon.h"
+
+namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
+{
+ struct PickFolderResult : PickFolderResultT
+ {
+ PickFolderResult() = default;
+
+ PickFolderResult(winrt::hstring const& path);
+
+ hstring Path();
+
+ private:
+ hstring m_path{};
+ };
+}
diff --git a/dev/Interop/StoragePickers/PickerCommon.cpp b/dev/Interop/StoragePickers/PickerCommon.cpp
new file mode 100644
index 0000000000..13e456e3cf
--- /dev/null
+++ b/dev/Interop/StoragePickers/PickerCommon.cpp
@@ -0,0 +1,229 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "PickerCommon.h"
+#include
+#include "ShObjIdl.h"
+#include
+
+namespace {
+
+ GUID HashHStringToGuid(winrt::hstring const& input)
+ {
+ auto algorithm = winrt::Windows::Security::Cryptography::Core::HashAlgorithmProvider::OpenAlgorithm(winrt::Windows::Security::Cryptography::Core::HashAlgorithmNames::Md5());
+
+ auto buffer = winrt::Windows::Security::Cryptography::CryptographicBuffer::ConvertStringToBinary(input, winrt::Windows::Security::Cryptography::BinaryStringEncoding::Utf16LE);
+
+ auto hash = algorithm.HashData(buffer);
+
+ if (hash.Length() != sizeof(GUID))
+ {
+ throw winrt::hresult_error(E_FAIL, L"Invalid hash length");
+ }
+
+ winrt::com_array resultBuffer(sizeof(GUID));
+ winrt::Windows::Security::Cryptography::CryptographicBuffer::CopyToByteArray(hash, resultBuffer);
+ GUID guid = *(reinterpret_cast(resultBuffer.data()));
+
+ // Adjust the GUID to conform to version 3 UUID (MD5-based)
+ guid.Data3 = (guid.Data3 & 0x0FFF) | 0x3000; // Set the version to 3
+ guid.Data4[0] = (guid.Data4[0] & 0x3F) | 0x80; // Set variant to RFC 4122
+
+ return guid;
+ }
+
+ winrt::com_ptr GetKnownFolderFromId(winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId pickerLocationId)
+ {
+ KNOWNFOLDERID knownFolderId;
+ switch (pickerLocationId)
+ {
+ case winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::DocumentsLibrary:
+ knownFolderId = FOLDERID_Documents;
+ break;
+ case winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::ComputerFolder:
+ knownFolderId = FOLDERID_ComputerFolder;
+ break;
+ case winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::Desktop:
+ knownFolderId = FOLDERID_Desktop;
+ break;
+ case winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::Downloads:
+ knownFolderId = FOLDERID_Downloads;
+ break;
+ case winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::HomeGroup:
+ knownFolderId = FOLDERID_HomeGroup;
+ break;
+ case winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::MusicLibrary:
+ knownFolderId = FOLDERID_MusicLibrary;
+ break;
+ case winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::PicturesLibrary:
+ knownFolderId = FOLDERID_PicturesLibrary;
+ break;
+ case winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::VideosLibrary:
+ knownFolderId = FOLDERID_VideosLibrary;
+ break;
+ case winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::Objects3D:
+ knownFolderId = FOLDERID_Objects3D;
+ break;
+ default:
+ return nullptr;
+ }
+
+ auto knownFolderManager = winrt::create_instance(CLSID_KnownFolderManager);
+
+ winrt::com_ptr knownFolder{};
+ winrt::hresult hr = knownFolderManager->GetFolder(knownFolderId, knownFolder.put());
+ if (!knownFolder)
+ {
+ knownFolderManager->GetFolder(FOLDERID_Documents, knownFolder.put());
+ }
+ if (!knownFolder)
+ {
+ return nullptr;
+ }
+
+ winrt::com_ptr defaultFolder{};
+ hr = knownFolder->GetShellItem(0, IID_PPV_ARGS(defaultFolder.put()));
+ if (FAILED(hr))
+ {
+ return nullptr;
+ }
+
+ return defaultFolder;
+ }
+
+
+ winrt::hstring FormatExtensionWithWildcard(winrt::hstring extension)
+ {
+ if (!extension.empty() && extension[0] == L'*')
+ {
+ return extension;
+ }
+ else
+ {
+ return L"*" + extension;
+ }
+ }
+
+ winrt::hstring JoinExtensions(winrt::Windows::Foundation::Collections::IVectorView extensions)
+ {
+ winrt::hstring result;
+ bool first = true;
+ for (const auto& ext : extensions)
+ {
+ if (first)
+ {
+ result = FormatExtensionWithWildcard(ext);
+ first = false;
+ }
+ else
+ {
+ result = result + L";" + FormatExtensionWithWildcard(ext);
+ }
+ }
+ return result;
+ }
+}
+
+
+namespace PickerCommon {
+
+ using namespace winrt;
+
+ bool IsHStringNullOrEmpty(winrt::hstring value)
+ {
+ return value.empty();
+ }
+
+ winrt::hstring GetPathFromShellItem(winrt::com_ptr shellItem)
+ {
+ wil::unique_cotaskmem_string filePath;
+ check_hresult(shellItem->GetDisplayName(SIGDN_FILESYSPATH, filePath.put()));
+ return winrt::hstring{ filePath.get() };
+ }
+
+ ///
+ /// Capture and processing pickers filter inputs and convert them into Common Item Dialog's accepting type
+ ///
+ /// temp buffer to hold dynamically transformed strings
+ /// winrt style filters
+ /// result Coomon Item Dialog style filters, note only raw pointers here,
+ /// they are valid up to lifetime of buffer
+ ///
+ std::vector CaptureFilterSpec(std::vector& buffer, winrt::Windows::Foundation::Collections::IVectorView filters)
+ {
+ std::vector result(filters.Size());
+ buffer.clear();
+ buffer.reserve(filters.Size() * (size_t)2);
+ for (const auto& filter : filters)
+ {
+ auto ext = FormatExtensionWithWildcard(filter);
+ buffer.push_back(filter);
+ buffer.push_back(ext);
+ }
+ for (size_t i = 0; i < filters.Size(); i++)
+ {
+ result.at(i) = { buffer.at(i * 2).c_str(), buffer.at(i * 2 + 1).c_str() };
+ }
+
+ if (result.size() == 0)
+ {
+ result.push_back({ L"All Files", L"*.*" });
+ }
+ return result;
+ }
+
+ ///
+ /// Capture and processing pickers filter inputs and convert them into Common Item Dialog's accepting type
+ ///
+ /// temp buffer to hold dynamically transformed strings
+ /// winrt style filters
+ /// result Coomon Item Dialog style filters, note only raw pointers here,
+ /// they are valid up to lifetime of buffer
+ ///
+ std::vector CaptureFilterSpec(std::vector& buffer, winrt::Windows::Foundation::Collections::IMapView> filters)
+ {
+ std::vector result(filters.Size());
+ buffer.clear();
+ buffer.reserve(filters.Size() * (size_t)2);
+
+ for (const auto& filter : filters)
+ {
+ buffer.push_back(filter.Key());
+ auto extensionList = JoinExtensions(filter.Value().GetView());
+ buffer.push_back(extensionList);
+ }
+ for (size_t i = 0; i < filters.Size(); i++)
+ {
+ result.at(i) = { buffer.at(i * 2).c_str(), buffer.at(i * 2 + 1).c_str() };
+ }
+
+ if (result.empty())
+ {
+ result.push_back({ L"All Files", L"*.*" });
+ }
+ return result;
+ }
+
+ void PickerParameters::ConfigureDialog(winrt::com_ptr dialog)
+ {
+ if (!IsHStringNullOrEmpty(CommitButtonText))
+ {
+ check_hresult(dialog->SetOkButtonLabel(CommitButtonText.c_str()));
+ }
+
+ if (!IsHStringNullOrEmpty(SettingsIdentifierId))
+ {
+ auto guid = HashHStringToGuid(SettingsIdentifierId);
+ check_hresult(dialog->SetClientGuid(guid));
+ }
+
+ auto defaultFolder = GetKnownFolderFromId(PickerLocationId);
+ if (defaultFolder != nullptr)
+ {
+ check_hresult(dialog->SetDefaultFolder(defaultFolder.get()));
+ }
+
+ check_hresult(dialog->SetFileTypes((UINT)FileTypeFilterPara.size(), FileTypeFilterPara.data()));
+ }
+}
diff --git a/dev/Interop/StoragePickers/PickerCommon.h b/dev/Interop/StoragePickers/PickerCommon.h
new file mode 100644
index 0000000000..ad2e314b51
--- /dev/null
+++ b/dev/Interop/StoragePickers/PickerCommon.h
@@ -0,0 +1,33 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#pragma once
+#include "pch.h"
+#include "ShObjIdl.h"
+#include "wil/cppwinrt.h"
+#include "winrt/base.h"
+#include "winrt/Microsoft.Windows.Storage.Pickers.h"
+#include "TerminalVelocityFeatures-StoragePickers.h"
+#include
+#include
+#include
+
+namespace PickerCommon {
+ winrt::hstring GetPathFromShellItem(winrt::com_ptr shellItem);
+
+ std::vector CaptureFilterSpec(std::vector& buffer, winrt::Windows::Foundation::Collections::IVectorView filters);
+ std::vector CaptureFilterSpec(std::vector& buffer, winrt::Windows::Foundation::Collections::IMapView> filters);
+
+ bool IsHStringNullOrEmpty(winrt::hstring value);
+
+ struct PickerParameters {
+ HWND HWnd{};
+ winrt::hstring CommitButtonText;
+ winrt::hstring SettingsIdentifierId;
+ winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId PickerLocationId;
+ std::vector FileTypeFilterData{};
+ std::vector FileTypeFilterPara{};
+
+ void ConfigureDialog(winrt::com_ptr dialog);
+ };
+}
diff --git a/dev/Interop/StoragePickers/StoragePickers.vcxitems b/dev/Interop/StoragePickers/StoragePickers.vcxitems
new file mode 100644
index 0000000000..f733b72cb1
--- /dev/null
+++ b/dev/Interop/StoragePickers/StoragePickers.vcxitems
@@ -0,0 +1,49 @@
+
+
+
+ $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
+ true
+ {a39e7b2f-5f67-47dd-8443-531d095ca7f3}
+
+
+
+ %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dev/Interop/StoragePickers/StoragePickersTelemetry.h b/dev/Interop/StoragePickers/StoragePickersTelemetry.h
new file mode 100644
index 0000000000..2811d82a1b
--- /dev/null
+++ b/dev/Interop/StoragePickers/StoragePickersTelemetry.h
@@ -0,0 +1,127 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#pragma once
+#include "..\WindowsAppRuntime_Insights\WindowsAppRuntimeInsights.h"
+#include
+
+DECLARE_TRACELOGGING_CLASS(StoragePickersTelemetryProvider,
+ "Microsoft.WindowsAppSDK.StoragePickersTelemetry",
+ // {6ddc5826-bf0a-522e-cc84-0e70eda439ed}
+ (0x6ddc5826,0xbf0a,0x522e,0xcc,0x84,0x0e,0x70,0xed,0xa4,0x39,0xed));
+
+class StoragePickersTelemetry : public wil::TraceLoggingProvider
+{
+ IMPLEMENT_TELEMETRY_CLASS(StoragePickersTelemetry, StoragePickersTelemetryProvider);
+
+public:
+ BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(FileOpenPickerPickSingleFile, PDT_ProductAndServicePerformance);
+ DEFINE_ACTIVITY_START(StoragePickersTelemetryHelper& telemetryHelper) noexcept try
+ {
+ TraceLoggingClassWriteStart(
+ FileOpenPickerPickSingleFile,
+ _GENERIC_PARTB_FIELDS_ENABLED,
+ TraceLoggingBool(telemetryHelper.IsPackagedApp(), "IsAppPackaged"),
+ TraceLoggingBool(telemetryHelper.IsRunningAsAdmin(), "IsRunningAsAdmin"),
+ TraceLoggingBool(telemetryHelper.IsRunningInContainer(), "IsRunningInContainer"),
+ TraceLoggingWideString(telemetryHelper.GetAppName().c_str(), "AppName")
+ );
+ }
+ CATCH_LOG()
+
+ DEFINE_ACTIVITY_STOP(StoragePickersTelemetryHelper& telemetryHelper, bool const resultNotNull) noexcept try
+ {
+ TraceLoggingClassWriteStop(
+ FileOpenPickerPickSingleFile,
+ _GENERIC_PARTB_FIELDS_ENABLED,
+ TraceLoggingBool(resultNotNull, "resultNotNull"),
+ TraceLoggingBool(telemetryHelper.IsPackagedApp(), "IsAppPackaged"),
+ TraceLoggingBool(telemetryHelper.IsRunningAsAdmin(), "IsRunningAsAdmin"),
+ TraceLoggingBool(telemetryHelper.IsRunningInContainer(), "IsRunningInContainer"),
+ TraceLoggingWideString(telemetryHelper.GetAppName().c_str(), "AppName"));
+ }
+ CATCH_LOG()
+ END_ACTIVITY_CLASS();
+
+ BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(FileOpenPickerPickMultipleFile, PDT_ProductAndServicePerformance);
+ DEFINE_ACTIVITY_START(StoragePickersTelemetryHelper& telemetryHelper) noexcept try
+ {
+ TraceLoggingClassWriteStart(
+ FileOpenPickerPickMultipleFile,
+ _GENERIC_PARTB_FIELDS_ENABLED,
+ TraceLoggingBool(telemetryHelper.IsPackagedApp(), "IsAppPackaged"),
+ TraceLoggingBool(telemetryHelper.IsRunningAsAdmin(), "IsRunningAsAdmin"),
+ TraceLoggingBool(telemetryHelper.IsRunningInContainer(), "IsRunningInContainer"),
+ TraceLoggingWideString(telemetryHelper.GetAppName().c_str(), "AppName"));
+ }
+ CATCH_LOG()
+
+ DEFINE_ACTIVITY_STOP(StoragePickersTelemetryHelper& telemetryHelper, bool const resultCancelled, bool const resultNotEmpty) noexcept try
+ {
+ TraceLoggingClassWriteStop(
+ FileOpenPickerPickMultipleFile,
+ _GENERIC_PARTB_FIELDS_ENABLED,
+ TraceLoggingBool(resultCancelled, "resultCancelled"),
+ TraceLoggingBool(resultNotEmpty, "resultNotEmpty"),
+ TraceLoggingBool(telemetryHelper.IsPackagedApp(), "IsAppPackaged"),
+ TraceLoggingBool(telemetryHelper.IsRunningAsAdmin(), "IsRunningAsAdmin"),
+ TraceLoggingBool(telemetryHelper.IsRunningInContainer(), "IsRunningInContainer"),
+ TraceLoggingWideString(telemetryHelper.GetAppName().c_str(), "AppName"));
+ }
+ CATCH_LOG()
+ END_ACTIVITY_CLASS();
+
+ BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(FileSavePickerPickSingleFile, PDT_ProductAndServicePerformance);
+ DEFINE_ACTIVITY_START(StoragePickersTelemetryHelper& telemetryHelper) noexcept try
+ {
+ TraceLoggingClassWriteStart(
+ FileSavePickerPickSingleFile,
+ _GENERIC_PARTB_FIELDS_ENABLED,
+ TraceLoggingBool(telemetryHelper.IsPackagedApp(), "IsAppPackaged"),
+ TraceLoggingBool(telemetryHelper.IsRunningAsAdmin(), "IsRunningAsAdmin"),
+ TraceLoggingBool(telemetryHelper.IsRunningInContainer(), "IsRunningInContainer"),
+ TraceLoggingWideString(telemetryHelper.GetAppName().c_str(), "AppName"));
+ }
+ CATCH_LOG()
+
+ DEFINE_ACTIVITY_STOP(StoragePickersTelemetryHelper& telemetryHelper, bool const resultNotNull) noexcept try
+ {
+ TraceLoggingClassWriteStop(
+ FileSavePickerPickSingleFile,
+ _GENERIC_PARTB_FIELDS_ENABLED,
+ TraceLoggingBool(resultNotNull, "resultNotNull"),
+ TraceLoggingBool(telemetryHelper.IsPackagedApp(), "IsAppPackaged"),
+ TraceLoggingBool(telemetryHelper.IsRunningAsAdmin(), "IsRunningAsAdmin"),
+ TraceLoggingBool(telemetryHelper.IsRunningInContainer(), "IsRunningInContainer"),
+ TraceLoggingWideString(telemetryHelper.GetAppName().c_str(), "AppName"));
+ }
+ CATCH_LOG()
+ END_ACTIVITY_CLASS();
+
+ BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(FolderPickerPickSingleFolder, PDT_ProductAndServicePerformance);
+ DEFINE_ACTIVITY_START(StoragePickersTelemetryHelper& telemetryHelper) noexcept try
+ {
+ TraceLoggingClassWriteStart(
+ FolderPickerPickSingleFolder,
+ _GENERIC_PARTB_FIELDS_ENABLED,
+ TraceLoggingBool(telemetryHelper.IsPackagedApp(), "IsAppPackaged"),
+ TraceLoggingBool(telemetryHelper.IsRunningAsAdmin(), "IsRunningAsAdmin"),
+ TraceLoggingBool(telemetryHelper.IsRunningInContainer(), "IsRunningInContainer"),
+ TraceLoggingWideString(telemetryHelper.GetAppName().c_str(), "AppName"));
+ }
+ CATCH_LOG()
+
+ DEFINE_ACTIVITY_STOP(StoragePickersTelemetryHelper& telemetryHelper, bool const resultNotNull) noexcept try
+ {
+ TraceLoggingClassWriteStop(
+ FolderPickerPickSingleFolder,
+ _GENERIC_PARTB_FIELDS_ENABLED,
+ TraceLoggingBool(resultNotNull, "resultNotNull"),
+ TraceLoggingBool(telemetryHelper.IsPackagedApp(), "IsAppPackaged"),
+ TraceLoggingBool(telemetryHelper.IsRunningAsAdmin(), "IsRunningAsAdmin"),
+ TraceLoggingBool(telemetryHelper.IsRunningInContainer(), "IsRunningInContainer"),
+ TraceLoggingWideString(telemetryHelper.GetAppName().c_str(), "AppName"));
+ }
+ CATCH_LOG()
+ END_ACTIVITY_CLASS();
+};
diff --git a/dev/Interop/StoragePickers/StoragePickersTelemetryHelper.h b/dev/Interop/StoragePickers/StoragePickersTelemetryHelper.h
new file mode 100644
index 0000000000..fae7f391d6
--- /dev/null
+++ b/dev/Interop/StoragePickers/StoragePickersTelemetryHelper.h
@@ -0,0 +1,92 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+#pragma once
+
+#include "TelemetryHelper.h"
+#include // For IsUserAnAdmin
+#include // For process APIs
+#include
+
+class StoragePickersTelemetryHelper : public TelemetryHelper
+{
+public:
+ StoragePickersTelemetryHelper() : TelemetryHelper()
+ {
+ m_asAdmin = IsAsAdmin();
+ m_inContainer = IsInContainer();
+ }
+
+ inline bool IsRunningAsAdmin() const
+ {
+ return m_asAdmin;
+ }
+
+ inline bool IsRunningInContainer() const
+ {
+ return m_inContainer;
+ }
+
+private:
+ bool m_asAdmin;
+ bool m_inContainer;
+
+ BOOL IsAsAdmin()
+ {
+ BOOL fIsRunAsAdmin = FALSE;
+ DWORD dwError = ERROR_SUCCESS;
+ PSID pAdministratorsGroup = NULL;
+
+ // Allocate and initialize a SID of the administrators group.
+ SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
+ if (!AllocateAndInitializeSid(&NtAuthority, 2,
+ SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &pAdministratorsGroup))
+ {
+ dwError = GetLastError();
+ }
+ else
+ {
+ // Determine whether the SID of administrators group is enabled in
+ // the primary access token of the process.
+ if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin))
+ {
+ dwError = GetLastError();
+ }
+
+ FreeSid(pAdministratorsGroup);
+ }
+
+ return fIsRunAsAdmin;
+ }
+
+ BOOL IsInContainer()
+ {
+ BOOL fIsInSandbox = FALSE;
+ DWORD dwError = ERROR_SUCCESS;
+
+ // Get the process token
+ HANDLE hToken = NULL;
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
+ {
+ dwError = GetLastError();
+ return FALSE;
+ }
+
+ // Check if the process is running in an AppContainer
+ DWORD dwIsAppContainer = 0;
+ DWORD dwSize = sizeof(dwIsAppContainer);
+ BOOL ans = GetTokenInformation(hToken, TokenIsAppContainer, &dwIsAppContainer, dwSize, &dwSize);
+ if (!ans)
+ {
+ dwError = GetLastError();
+ CloseHandle(hToken);
+ return FALSE;
+ }
+
+ fIsInSandbox = (dwIsAppContainer != 0);
+
+ CloseHandle(hToken);
+ return fIsInSandbox;
+ }
+};
diff --git a/dev/Projections/CS/Microsoft.Windows.Storage.Pickers.Projection/Microsoft.Windows.Storage.Pickers.Projection.csproj b/dev/Projections/CS/Microsoft.Windows.Storage.Pickers.Projection/Microsoft.Windows.Storage.Pickers.Projection.csproj
new file mode 100644
index 0000000000..46e216e9bc
--- /dev/null
+++ b/dev/Projections/CS/Microsoft.Windows.Storage.Pickers.Projection/Microsoft.Windows.Storage.Pickers.Projection.csproj
@@ -0,0 +1,59 @@
+
+
+ net6.0-windows10.0.17763.0
+ 10.0.17763.0
+ x64;x86;arm64
+ AnyCPU
+ false
+
+
+
+ true
+ true
+
+
+
+
+ 8305
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+ Microsoft.Windows.Storage.Pickers
+ 10.0.17763.0
+ false
+
+
+
+
+ pdbonly
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+ $(OutDir)..\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Storage.Pickers.winmd
+ true
+
+
+
diff --git a/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj b/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj
index 455d992f8a..c5ac889f59 100644
--- a/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj
+++ b/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj
@@ -105,6 +105,7 @@
+
@@ -153,9 +154,9 @@
Windows
false
- onecore.lib;onecoreuap.lib;%(AdditionalDependencies)
+ onecore.lib;onecoreuap.lib;shell32.lib;%(AdditionalDependencies)
WindowsAppRuntime.def
- Microsoft.Internal.FrameworkUdk.dll;%(DelayLoadDLLs)
+ Microsoft.Internal.FrameworkUdk.dll;shell32.dll;%(DelayLoadDLLs)
$(RepoRoot)\dev\common
@@ -171,9 +172,9 @@
Windows
false
- onecore.lib;onecoreuap.lib;%(AdditionalDependencies)
+ onecore.lib;onecoreuap.lib;shell32.lib;%(AdditionalDependencies)
WindowsAppRuntime.def
- Microsoft.Internal.FrameworkUdk.dll;%(DelayLoadDLLs)
+ Microsoft.Internal.FrameworkUdk.dll;shell32.dll;%(DelayLoadDLLs)
$(RepoRoot)\dev\common
@@ -189,9 +190,9 @@
Windows
false
- onecore.lib;onecoreuap.lib;%(AdditionalDependencies)
+ onecore.lib;onecoreuap.lib;shell32.lib;%(AdditionalDependencies)
WindowsAppRuntime.def
- Microsoft.Internal.FrameworkUdk.dll;%(DelayLoadDLLs)
+ Microsoft.Internal.FrameworkUdk.dll;shell32.dll;%(DelayLoadDLLs)
$(RepoRoot)\dev\common
@@ -207,9 +208,9 @@
Windows
false
- onecore.lib;onecoreuap.lib;%(AdditionalDependencies)
+ onecore.lib;onecoreuap.lib;shell32.lib;%(AdditionalDependencies)
WindowsAppRuntime.def
- Microsoft.Internal.FrameworkUdk.dll;%(DelayLoadDLLs)
+ Microsoft.Internal.FrameworkUdk.dll;shell32.dll;%(DelayLoadDLLs)
$(RepoRoot)\dev\common
@@ -225,9 +226,9 @@
Windows
false
- onecore.lib;onecoreuap.lib;%(AdditionalDependencies)
+ onecore.lib;onecoreuap.lib;shell32.lib;%(AdditionalDependencies)
WindowsAppRuntime.def
- Microsoft.Internal.FrameworkUdk.dll;%(DelayLoadDLLs)
+ Microsoft.Internal.FrameworkUdk.dll;shell32.dll;%(DelayLoadDLLs)
$(RepoRoot)\dev\common
@@ -243,9 +244,9 @@
Windows
false
- onecore.lib;onecoreuap.lib;%(AdditionalDependencies)
+ onecore.lib;onecoreuap.lib;shell32.lib;%(AdditionalDependencies)
WindowsAppRuntime.def
- Microsoft.Internal.FrameworkUdk.dll;%(DelayLoadDLLs)
+ Microsoft.Internal.FrameworkUdk.dll;shell32.dll;%(DelayLoadDLLs)
$(RepoRoot)\dev\common
@@ -329,4 +330,4 @@
-
+
\ No newline at end of file
diff --git a/test/DynamicDependency/data/Microsoft.WindowsAppRuntime.Framework/appxmanifest.xml b/test/DynamicDependency/data/Microsoft.WindowsAppRuntime.Framework/appxmanifest.xml
index 81bbf799f8..7666d7f656 100644
--- a/test/DynamicDependency/data/Microsoft.WindowsAppRuntime.Framework/appxmanifest.xml
+++ b/test/DynamicDependency/data/Microsoft.WindowsAppRuntime.Framework/appxmanifest.xml
@@ -141,6 +141,14 @@
+
+
+ Microsoft.WindowsAppRuntime.dll
+
+
+
+
+
Microsoft.WindowsAppRuntime.dll
diff --git a/test/StoragePickersTests/StoragePickersTests.cpp b/test/StoragePickersTests/StoragePickersTests.cpp
new file mode 100644
index 0000000000..95369d5151
--- /dev/null
+++ b/test/StoragePickersTests/StoragePickersTests.cpp
@@ -0,0 +1,208 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "AssemblyInfo.h"
+
+#include
+#include
+#include
+
+namespace TB = ::Test::Bootstrap;
+namespace TP = ::Test::Packages;
+
+using namespace WEX::Common;
+using namespace WEX::Logging;
+using namespace WEX::TestExecution;
+
+namespace Test::StoragePickersTests
+{
+ class StoragePickersTests
+ {
+ public:
+ BEGIN_TEST_CLASS(StoragePickersTests)
+ TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA") // MTA is required for ::Test::Bootstrap::SetupPackages()
+ TEST_CLASS_PROPERTY(L"RunFixtureAs:Class", L"RestrictedUser")
+ //TEST_CLASS_PROPERTY(L"RunFixtureAs:Class", L"UAP")
+ //TEST_CLASS_PROPERTY(L"RunAs", L"UAP")
+
+ END_TEST_CLASS()
+
+ TEST_CLASS_SETUP(ClassSetup)
+ {
+ ::Test::Bootstrap::SetupPackages();
+ return true;
+ }
+
+ TEST_CLASS_CLEANUP(ClassCleanup)
+ {
+ ::Test::Bootstrap::CleanupPackages();
+ return true;
+ }
+
+ TEST_METHOD_SETUP(MethodInit)
+ {
+ VERIFY_IS_TRUE(TP::IsPackageRegistered_WindowsAppRuntimeFramework());
+
+ // The test method setup and execution is on a different thread than the class setup.
+ // Initialize the framework for the test thread.
+ ::Test::Bootstrap::SetupBootstrap();
+ return true;
+ }
+
+ TEST_METHOD_CLEANUP(MethodUninit)
+ {
+ VERIFY_IS_TRUE(TP::IsPackageRegistered_WindowsAppRuntimeFramework());
+ ::Test::Bootstrap::CleanupBootstrap();
+ return true;
+ }
+ // The unit tests will be updated,first test might is there for testing purpose locally.
+ // Focusing solely on functional tests for now.
+
+ // Commenting out this test as it is an E2E scenario test that requires UI automation for pipeline execution.
+ /*
+
+ TEST_METHOD(FileOpenPicker_ShouldPickFile)
+ {
+ try
+ {
+ auto parentWindow = ::GetForegroundWindow();
+ winrt::Microsoft::UI::WindowId windowId{ reinterpret_cast(parentWindow) };
+ winrt::Microsoft::Windows::Storage::Pickers::FileOpenPicker picker{ windowId };
+ picker.FileTypeFilter().Append(L"*");
+ // Act
+ auto operation = picker.PickSingleFileAsync();
+ auto file = operation.get();
+ auto path = file.Path();
+ // Assert
+ if (file != nullptr)
+ {
+ Log::Comment(L"File open was successful");
+ }
+ else
+ {
+ Log::Error(L"File open canceled.");
+ }
+ }
+ catch (const winrt::hresult_error& ex)
+ {
+ Log::Error((std::wstring(L"Exception thrown: ") + ex.message().c_str()).c_str());
+ VERIFY_FAIL(L"Exception occurred during file open picker.");
+ }
+ catch (const std::exception& ex)
+ {
+ Log::Error((std::wstring(L"Standard exception thrown: ") + winrt::to_hstring(ex.what()).c_str()).c_str());
+ VERIFY_FAIL(L"Standard exception occurred during file open picker.");
+ }
+ }
+
+ TEST_METHOD(FileSavePicker_ShouldCreateNewFile)
+ {
+ try
+ {
+ auto parentWindow = ::GetForegroundWindow();
+ winrt::Microsoft::UI::WindowId windowId{ reinterpret_cast(parentWindow) };
+ winrt::Microsoft::Windows::Storage::Pickers::FileSavePicker savePicker(windowId);
+ //savePicker.SuggestedStartLocation(winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::DocumentsLibrary);
+ savePicker.FileTypeChoices().Insert(L"Plain Text", winrt::single_threaded_vector({ L".txt" }));
+ savePicker.SuggestedFileName(L"test.txt");
+ // Act
+ auto fileOperation = savePicker.PickSaveFileAsync();
+ auto file = fileOperation.get();
+ auto path = file.Path();
+
+ // Assert
+ if (file != nullptr)
+ {
+ Log::Comment(L"File save was successful.");
+ }
+ else
+ {
+ Log::Error(L"File save failed or was canceled.");
+ }
+ }
+ catch (const winrt::hresult_error& ex)
+ {
+ Log::Error((std::wstring(L"Exception thrown: ") + ex.message().c_str()).c_str());
+ VERIFY_FAIL(L"Exception occurred during file save picker.");
+ }
+ catch (const std::exception& ex)
+ {
+ Log::Error((std::wstring(L"Standard exception thrown: ") + winrt::to_hstring(ex.what()).c_str()).c_str());
+ VERIFY_FAIL(L"Standard exception occurred during file save picker.");
+ }
+ }
+
+ */
+
+
+ TEST_METHOD(VerifyFileOpenPickerOptionsAreReadCorrectly)
+ {
+ winrt::Microsoft::UI::WindowId windowId{};
+ winrt::Microsoft::Windows::Storage::Pickers::FileOpenPicker picker(windowId);
+
+ picker.ViewMode(winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode::List);
+ VERIFY_ARE_EQUAL(picker.ViewMode(), winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode::List);
+
+ picker.ViewMode(winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode::Thumbnail);
+ VERIFY_ARE_EQUAL(picker.ViewMode(), winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode::Thumbnail);
+
+ picker.SettingsIdentifier(L"id");
+ VERIFY_ARE_EQUAL(picker.SettingsIdentifier(), L"id");
+
+ picker.SuggestedStartLocation(winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::DocumentsLibrary);
+ VERIFY_ARE_EQUAL(picker.SuggestedStartLocation(), winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::DocumentsLibrary);
+
+ picker.CommitButtonText(L"commit");
+ VERIFY_ARE_EQUAL(picker.CommitButtonText(), L"commit");
+
+ picker.FileTypeFilter().Append(L"*");
+ VERIFY_ARE_EQUAL(picker.FileTypeFilter().GetAt(0), L"*");
+ }
+
+ TEST_METHOD(VerifyFileSavePickerOptionsAreReadCorrectly)
+ {
+ winrt::Microsoft::UI::WindowId windowId{};
+ winrt::Microsoft::Windows::Storage::Pickers::FileSavePicker picker(windowId);
+
+ picker.SettingsIdentifier(L"id");
+ VERIFY_ARE_EQUAL(picker.SettingsIdentifier(), L"id");
+
+ picker.SuggestedStartLocation(winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::DocumentsLibrary);
+ VERIFY_ARE_EQUAL(picker.SuggestedStartLocation(), winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::DocumentsLibrary);
+
+ picker.CommitButtonText(L"commit");
+ VERIFY_ARE_EQUAL(picker.CommitButtonText(), L"commit");
+
+ auto filters = winrt::single_threaded_vector();
+ filters.Append(L"*");
+ picker.FileTypeChoices().Insert(L"All Files", filters);
+ VERIFY_ARE_EQUAL(picker.FileTypeChoices().Lookup(L"All Files").GetAt(0), L"*");
+ }
+
+ TEST_METHOD(VerifyFolderPickerOptionsAreReadCorrectly)
+ {
+ auto parentWindow = ::GetForegroundWindow();
+ winrt::Microsoft::UI::WindowId windowId{};
+ winrt::Microsoft::Windows::Storage::Pickers::FolderPicker picker(windowId);
+
+ picker.ViewMode(winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode::List);
+ VERIFY_ARE_EQUAL(picker.ViewMode(), winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode::List);
+
+ picker.ViewMode(winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode::Thumbnail);
+ VERIFY_ARE_EQUAL(picker.ViewMode(), winrt::Microsoft::Windows::Storage::Pickers::PickerViewMode::Thumbnail);
+
+ picker.SettingsIdentifier(L"id");
+ VERIFY_ARE_EQUAL(picker.SettingsIdentifier(), L"id");
+
+ picker.SuggestedStartLocation(winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::DocumentsLibrary);
+ VERIFY_ARE_EQUAL(picker.SuggestedStartLocation(), winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId::DocumentsLibrary);
+
+ picker.CommitButtonText(L"commit");
+ VERIFY_ARE_EQUAL(picker.CommitButtonText(), L"commit");
+
+ picker.FileTypeFilter().Append(L"*");
+ VERIFY_ARE_EQUAL(picker.FileTypeFilter().GetAt(0), L"*");
+ }
+ };
+}
diff --git a/test/StoragePickersTests/StoragePickersTests.vcxproj b/test/StoragePickersTests/StoragePickersTests.vcxproj
new file mode 100644
index 0000000000..ebe73a74e7
--- /dev/null
+++ b/test/StoragePickersTests/StoragePickersTests.vcxproj
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+ 17.0
+ Win32Proj
+ {85C86306-46D1-4563-8303-0A79DF923586}
+ StoragePickersTests
+ 10.0
+ StoragePickersTests
+
+
+ DynamicLibrary
+ v143
+ Unicode
+
+
+ false
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use
+ true
+ pch.h
+ $(RepoRoot)\test\inc;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories);$(OutDir)\..\WindowsAppRuntime_DLL;$(OutDir)\..\WindowsAppRuntime_BootstrapDLL;$(RepoRoot)\dev\common
+ $(RepoRoot);%(AdditionalIncludeDirectories)
+
+
+ Windows
+ onecore.lib;onecoreuap.lib;Microsoft.WindowsAppRuntime.lib;wex.common.lib;wex.logger.lib;te.common.lib;%(AdditionalDependencies)
+ $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories);$(OutDir)\..\WindowsAppRuntime_DLL
+
+
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+
+
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+
+
+
+
+ WIN32;%(PreprocessorDefinitions)
+
+
+
+
+ Create
+
+
+ $(RepoRoot)\build\VersionInfo;%(AdditionalIncludeDirectories)
+
+
+
+
+
+
+
+
+
+
+ $(OutDir)\..\WindowsAppRuntime_DLL\Microsoft.Windows.Storage.Pickers.winmd
+ true
+
+
+
+
+ {f76b776e-86f5-48c5-8fc7-d2795ecc9746}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/StoragePickersTests/StoragePickersTests.vcxproj.filters b/test/StoragePickersTests/StoragePickersTests.vcxproj.filters
new file mode 100644
index 0000000000..404acd038b
--- /dev/null
+++ b/test/StoragePickersTests/StoragePickersTests.vcxproj.filters
@@ -0,0 +1,36 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+
+
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/test/StoragePickersTests/packages.config b/test/StoragePickersTests/packages.config
new file mode 100644
index 0000000000..1a51bd1772
--- /dev/null
+++ b/test/StoragePickersTests/packages.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/test/StoragePickersTests/pch.cpp b/test/StoragePickersTests/pch.cpp
new file mode 100644
index 0000000000..a77728ba07
--- /dev/null
+++ b/test/StoragePickersTests/pch.cpp
@@ -0,0 +1,8 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+// pch.cpp: source file corresponding to the pre-compiled header
+
+#include "pch.h"
+
+// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
diff --git a/test/StoragePickersTests/pch.h b/test/StoragePickersTests/pch.h
new file mode 100644
index 0000000000..0c38a1ba77
--- /dev/null
+++ b/test/StoragePickersTests/pch.h
@@ -0,0 +1,22 @@
+// Copyright (c) Microsoft Corporation and Contributors.
+// Licensed under the MIT License.
+
+#ifndef PCH_H
+#define PCH_H
+
+#include
+
+#include
+
+#include
+#include
+
+#include "winrt/Microsoft.Windows.Storage.Pickers.h"
+
+#include
+
+#include
+#include
+#include
+
+#endif //PCH_H