diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln index 266ae49a34..2e644489bd 100644 --- a/WindowsAppRuntime.sln +++ b/WindowsAppRuntime.sln @@ -566,6 +566,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IXP", "IXP", "{7B323048-439 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IXP.TransportPackage.PackageReference", "eng\PackageReference\IXP\IXP.TransportPackage.PackageReference.csproj", "{A949149D-29CA-4AA7-B1ED-0E571B4AD9BB}" 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 Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -2002,6 +2004,22 @@ Global {A949149D-29CA-4AA7-B1ED-0E571B4AD9BB}.Release|x64.Build.0 = Release|x64 {A949149D-29CA-4AA7-B1ED-0E571B4AD9BB}.Release|x86.ActiveCfg = Release|x86 {A949149D-29CA-4AA7-B1ED-0E571B4AD9BB}.Release|x86.Build.0 = Release|x86 + {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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2181,6 +2199,7 @@ Global {D5958784-4518-44F1-A518-80514B380ED5} = {E24C263A-DE3E-4844-BA50-842DA5AD7A49} {7B323048-439F-47E9-A3D4-7342C5ADE2A5} = {5C88AE1D-AC20-4A41-9299-1EEA15B80724} {A949149D-29CA-4AA7-B1ED-0E571B4AD9BB} = {7B323048-439F-47E9-A3D4-7342C5ADE2A5} + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410} = {716C26A0-E6B0-4981-8412-D14A4D410531} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4B3D7591-CFEC-4762-9A07-ABE99938FB77} diff --git a/build/CopyFilesToStagingDir.ps1 b/build/CopyFilesToStagingDir.ps1 index 3c261aaac2..656d6e5e88 100644 --- a/build/CopyFilesToStagingDir.ps1 +++ b/build/CopyFilesToStagingDir.ps1 @@ -55,6 +55,7 @@ PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windo PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.AppNotifications.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\ @@ -126,6 +127,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 @@ -202,6 +205,7 @@ PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windo PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.AppNotifications.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 e079468216..2ee96bb190 100644 --- a/build/NuSpecs/AppxManifest.xml +++ b/build/NuSpecs/AppxManifest.xml @@ -111,6 +111,9 @@ + + + diff --git a/build/NuSpecs/WindowsAppSDK-Nuget-Native.WinRt.props b/build/NuSpecs/WindowsAppSDK-Nuget-Native.WinRt.props index 88fede76fd..02b59d588d 100644 --- a/build/NuSpecs/WindowsAppSDK-Nuget-Native.WinRt.props +++ b/build/NuSpecs/WindowsAppSDK-Nuget-Native.WinRt.props @@ -75,6 +75,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 c18bdb650a..7057bff1ae 100644 --- a/build/NuSpecs/WindowsAppSDK-Nuget-Native.targets +++ b/build/NuSpecs/WindowsAppSDK-Nuget-Native.targets @@ -135,6 +135,14 @@ + + + false + Microsoft.WindowsAppRuntime.dll + + + diff --git a/dev/Interop/StoragePicker/FileOpenPicker.cpp b/dev/Interop/StoragePicker/FileOpenPicker.cpp new file mode 100644 index 0000000000..9684ff2f98 --- /dev/null +++ b/dev/Interop/StoragePicker/FileOpenPicker.cpp @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +#include "pch.h" +#include "FileOpenPicker.h" +#include "Microsoft.Windows.Storage.Pickers.FileOpenPicker.g.cpp" +#include "StoragePickersTelemetry.h" +#include +#include +#include +#include +#include + +namespace winrt::Microsoft::Windows::Storage::Pickers::implementation +{ + winrt::Windows::Foundation::IAsyncOperation FileOpenPicker::PickSingleFileAsync() + { + bool isAppPackaged = m_telemetryHelper.IsPackagedApp(); + PCWSTR appName = m_telemetryHelper.GetAppName().c_str(); + auto logCaptureOperation{ StoragePickersTelemetry::StoragePickersOperation::Start(isAppPackaged, appName) }; + + winrt::apartment_context ui_thread; + + co_await winrt::resume_background(); + + // Handle cancellation. + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return nullptr; + } + + // TODO: should we initialize COM? + //wil::com_initialize_ex initializeCom{ COINIT_APARTMENTTHREADED }; + + wil::com_ptr fileOpenDialog; + THROW_IF_FAILED(CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&fileOpenDialog))); + + HRESULT hr = fileOpenDialog->Show(nullptr); + if (FAILED(hr) || cancellationToken()) + { + co_return nullptr; + } + + wil::com_ptr shellItem; + THROW_IF_FAILED(fileOpenDialog->GetResult(shellItem.put())); + + wil::unique_cotaskmem_string filePath; + THROW_IF_FAILED(shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath)); + + // Convert the file path to a StorageFile. + auto const& file = co_await winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(filePath.get()); + if (cancellationToken()) { + co_return nullptr; + } + + co_await ui_thread; + if (cancellationToken()) { + co_return nullptr; + } + + co_return file; + } +} diff --git a/dev/Interop/StoragePicker/FileOpenPicker.h b/dev/Interop/StoragePicker/FileOpenPicker.h new file mode 100644 index 0000000000..c97752674f --- /dev/null +++ b/dev/Interop/StoragePicker/FileOpenPicker.h @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +#pragma once +#include "Microsoft.Windows.Storage.Pickers.FileOpenPicker.g.h" +#include "TelemetryHelper.h" + +namespace winrt::Microsoft::Windows::Storage::Pickers::implementation +{ + struct FileOpenPicker : FileOpenPickerT + { + FileOpenPicker() = default; + winrt::Windows::Foundation::IAsyncOperation PickSingleFileAsync(); + + private: + TelemetryHelper m_telemetryHelper; + }; +} + +namespace winrt::Microsoft::Windows::Storage::Pickers::factory_implementation +{ + struct FileOpenPicker : FileOpenPickerT + { + }; +} diff --git a/dev/Interop/StoragePicker/FileOpenPicker.idl b/dev/Interop/StoragePicker/FileOpenPicker.idl new file mode 100644 index 0000000000..0af9f685ef --- /dev/null +++ b/dev/Interop/StoragePicker/FileOpenPicker.idl @@ -0,0 +1,13 @@ +namespace Microsoft.Windows.Storage.Pickers +{ + [contractversion(1)] + apicontract FileOpenPickerContract {}; + + [contract(FileOpenPickerContract, 1)] + runtimeclass FileOpenPicker + { + FileOpenPicker(); + + Windows.Foundation.IAsyncOperation PickSingleFileAsync(); + }; +} diff --git a/dev/Interop/StoragePicker/StoragePicker.vcxitems b/dev/Interop/StoragePicker/StoragePicker.vcxitems new file mode 100644 index 0000000000..f49e671656 --- /dev/null +++ b/dev/Interop/StoragePicker/StoragePicker.vcxitems @@ -0,0 +1,25 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {a39e7b2f-5f67-47dd-8443-531d095ca7f3} + + + + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dev/Interop/StoragePicker/StoragePickersTelemetry.h b/dev/Interop/StoragePicker/StoragePickersTelemetry.h new file mode 100644 index 0000000000..beff1e2a22 --- /dev/null +++ b/dev/Interop/StoragePicker/StoragePickersTelemetry.h @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once +#include "..\WindowsAppRuntime_Insights\WindowsAppRuntimeInsights.h" +#include + +DECLARE_TRACELOGGING_CLASS(StoragePickersTelemetryProvider, + "Microsoft.WindowsAppSDK.StoragePickersTelemetry", + // {3be0d45f-3a9d-46be-a1cf-b08465473cc4} + (0x3be0d45f, 0x3a9d, 0x46be, 0xa1, 0xcf, 0xb0, 0x84, 0x65, 0x47, 0x3c, 0xc4)); + +class StoragePickersTelemetry : public wil::TraceLoggingProvider +{ + IMPLEMENT_TELEMETRY_CLASS(StoragePickersTelemetry, StoragePickersTelemetryProvider); + +public: + BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(StoragePickersOperation, PDT_ProductAndServicePerformance); + DEFINE_ACTIVITY_START(bool isAppPackaged, PCWSTR appName) noexcept try + { + TraceLoggingClassWriteStart( + StoragePickersOperation, + _GENERIC_PARTB_FIELDS_ENABLED, + TraceLoggingBool(isAppPackaged, "IsAppPackaged"), + TraceLoggingWideString(appName, "AppName")); + } + CATCH_LOG() + END_ACTIVITY_CLASS(); +}; \ No newline at end of file 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..a13846ff90 --- /dev/null +++ b/dev/Projections/CS/Microsoft.Windows.Storage.Pickers.Projection/Microsoft.Windows.Storage.Pickers.Projection.csproj @@ -0,0 +1,58 @@ + + + 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 62e67cef13..75db43c1f0 100644 --- a/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj +++ b/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj @@ -102,6 +102,7 @@ + diff --git a/prototype-workingdir/.gitignore b/prototype-workingdir/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prototype-workingdir/Directory.Build.props b/prototype-workingdir/Directory.Build.props new file mode 100644 index 0000000000..6dc4195c32 --- /dev/null +++ b/prototype-workingdir/Directory.Build.props @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/prototype-workingdir/Directory.Packages.props b/prototype-workingdir/Directory.Packages.props new file mode 100644 index 0000000000..6dc4195c32 --- /dev/null +++ b/prototype-workingdir/Directory.Packages.props @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp new file mode 100644 index 0000000000..d3d42329d3 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp @@ -0,0 +1,154 @@ +#include "pch.h" +#include "FileOpenPicker.h" +#include "FileOpenPicker.g.cpp" +#include +#include +#include +#include +#include "PickerCommon.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + FileOpenPicker::FileOpenPicker(winrt::Microsoft::UI::WindowId const& windowId) + : m_windowId(windowId) + { + } + + winrt::Microsoft::Storage::Pickers::PickerViewMode FileOpenPicker::ViewMode() + { + return m_viewMode; + } + void FileOpenPicker::ViewMode(winrt::Microsoft::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::Storage::Pickers::PickerLocationId FileOpenPicker::SuggestedStartLocation() + { + return m_suggestedStartLocation; + } + void FileOpenPicker::SuggestedStartLocation(winrt::Microsoft::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() + { + PickerCommon::PickerParameters parameters{}; + + CaptureParameters(parameters); + + co_await winrt::resume_background(); + + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return nullptr; + } + + // TODO: should we initialize COM? + // wil::com_initialize_ex initializeCom{ COINIT_APARTMENTTHREADED }; + + auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL); + + parameters.ConfigureDialog(dialog); + + { + auto hr = dialog->Show(parameters.HWnd); + if (FAILED(hr) || cancellationToken()) + { + co_return nullptr; + } + } + + winrt::com_ptr shellItem{}; + check_hresult(dialog->GetResult(shellItem.put())); + auto file = co_await PickerCommon::CreateStorageFileFromShellItem(shellItem); + + if (cancellationToken()) + { + co_return nullptr; + } + co_return file; + } + + winrt::Windows::Foundation::IAsyncOperation> FileOpenPicker::PickMultipleFilesAsync() + { + PickerCommon::PickerParameters parameters{}; + + CaptureParameters(parameters); + + co_await winrt::resume_background(); + + winrt::Windows::Foundation::Collections::IVector results{ winrt::single_threaded_vector() }; + + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + 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()) + { + 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 file = co_await PickerCommon::CreateStorageFileFromShellItem(shellItem); + results.Append(file); + } + + if (cancellationToken()) + { + results.Clear(); + co_return results.GetView(); + } + co_return results.GetView(); + } +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.h b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.h new file mode 100644 index 0000000000..fb68a34d2b --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.h @@ -0,0 +1,44 @@ +#pragma once +#include "FileOpenPicker.g.h" +#include "PickerCommon.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + struct FileOpenPicker : FileOpenPickerT + { + FileOpenPicker(winrt::Microsoft::UI::WindowId const& windowId); + + winrt::Microsoft::Storage::Pickers::PickerViewMode ViewMode(); + void ViewMode(winrt::Microsoft::Storage::Pickers::PickerViewMode const& value); + + hstring SettingsIdentifier(); + void SettingsIdentifier(hstring const& value); + + winrt::Microsoft::Storage::Pickers::PickerLocationId SuggestedStartLocation(); + void SuggestedStartLocation(winrt::Microsoft::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() }; + + void CaptureParameters(PickerCommon::PickerParameters& parameters); + }; +} +namespace winrt::Microsoft::Storage::Pickers::factory_implementation +{ + struct FileOpenPicker : FileOpenPickerT + { + }; +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp new file mode 100644 index 0000000000..052135bf98 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp @@ -0,0 +1,138 @@ +#include "pch.h" +#include "FileSavePicker.h" +#include "FileSavePicker.g.cpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "PickerCommon.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + + FileSavePicker::FileSavePicker(winrt::Microsoft::UI::WindowId const& windowId) + : m_windowId(windowId) + { + } + hstring FileSavePicker::SettingsIdentifier() + { + return m_settingsIdentifier; + } + void FileSavePicker::SettingsIdentifier(hstring const& value) + { + m_settingsIdentifier = value; + } + winrt::Microsoft::Storage::Pickers::PickerLocationId FileSavePicker::SuggestedStartLocation() + { + return m_suggestedStartLocation; + } + void FileSavePicker::SuggestedStartLocation(winrt::Microsoft::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() + { + PickerCommon::PickerParameters parameters{}; + CaptureParameters(parameters); + auto defaultFileExtension = m_defaultFileExtension; + auto suggestedSaveFile = m_suggestedSaveFile; + auto suggestedFileName = m_suggestedFileName; + + co_await winrt::resume_background(); + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + 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)) + { + co_return nullptr; + } + } + + winrt::com_ptr shellItem{}; + check_hresult(dialog->GetResult(shellItem.put())); + auto file = co_await PickerCommon::CreateStorageFileFromShellItem(shellItem); + + if (cancellationToken()) + { + co_return nullptr; + } + co_return file; + } +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h new file mode 100644 index 0000000000..2144f51292 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h @@ -0,0 +1,53 @@ +#pragma once +#include "FileSavePicker.g.h" +#include "PickerCommon.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + struct FileSavePickerParameters; + + struct FileSavePicker : FileSavePickerT + { + FileSavePicker(winrt::Microsoft::UI::WindowId const& windowId); + + hstring SettingsIdentifier(); + void SettingsIdentifier(hstring const& value); + + winrt::Microsoft::Storage::Pickers::PickerLocationId SuggestedStartLocation(); + void SuggestedStartLocation(winrt::Microsoft::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{}; + + void CaptureParameters(PickerCommon::PickerParameters& parameters); + }; +} +namespace winrt::Microsoft::Storage::Pickers::factory_implementation +{ + struct FileSavePicker : FileSavePickerT + { + }; +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp new file mode 100644 index 0000000000..6e7c62d0be --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp @@ -0,0 +1,98 @@ +#include "pch.h" +#include "FolderPicker.h" +#include "FolderPicker.g.cpp" +#include +#include +#include +#include "PickerCommon.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + FolderPicker::FolderPicker(winrt::Microsoft::UI::WindowId const& windowId) + : m_windowId(windowId) + { + } + winrt::Microsoft::Storage::Pickers::PickerViewMode FolderPicker::ViewMode() + { + return m_viewMode; + } + void FolderPicker::ViewMode(winrt::Microsoft::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::Storage::Pickers::PickerLocationId FolderPicker::SuggestedStartLocation() + { + return m_suggestedStartLocation; + } + void FolderPicker::SuggestedStartLocation(winrt::Microsoft::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() + { + PickerCommon::PickerParameters parameters{}; + CaptureParameters(parameters); + + co_await winrt::resume_background(); + + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + 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()) + { + co_return nullptr; + } + } + + winrt::com_ptr shellItem{}; + check_hresult(dialog->GetResult(shellItem.put())); + auto folder = co_await PickerCommon::CreateStorageFolderFromShellItem(shellItem); + + if (cancellationToken()) + { + co_return nullptr; + } + co_return folder; + } +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h new file mode 100644 index 0000000000..56af65cb19 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h @@ -0,0 +1,45 @@ +#pragma once +#include "FolderPicker.g.h" +#include "PickerCommon.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + struct FolderPicker : FolderPickerT + { + FolderPicker(winrt::Microsoft::UI::WindowId const& windowId); + + winrt::Microsoft::Storage::Pickers::PickerViewMode ViewMode(); + void ViewMode(winrt::Microsoft::Storage::Pickers::PickerViewMode const& value); + + hstring SettingsIdentifier(); + void SettingsIdentifier(hstring const& value); + + winrt::Microsoft::Storage::Pickers::PickerLocationId SuggestedStartLocation(); + void SuggestedStartLocation(winrt::Microsoft::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{}; + + winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ winrt::single_threaded_vector() }; + + void CaptureParameters(PickerCommon::PickerParameters& parameters); + }; +} +namespace winrt::Microsoft::Storage::Pickers::factory_implementation +{ + struct FolderPicker : FolderPickerT + { + }; +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj new file mode 100644 index 0000000000..b1b1eaf438 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj @@ -0,0 +1,160 @@ + + + + + + + true + true + true + {349e64cf-cb0c-4202-b1b5-7f543cc6e886} + Microsoft.Storage.Pickers + Microsoft.Storage.Pickers + en-US + 16.0 + false + Windows Store + 10.0 + 10.0.22621.0 + 10.0.22000.0 + true + true + + + + + Debug + Win32 + + + Debug + x64 + + + Debug + ARM64 + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + DynamicLibrary + v143 + Unicode + false + true + + + true + true + + + false + true + false + + + + + + + + + + + + + + Use + pch.h + $(IntDir)pch.pch + Level4 + %(AdditionalOptions) /bigobj + _WINRT_DLL;%(PreprocessorDefinitions) + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + + + Console + true + Microsoft_Storage_Pickers.def + + + + + _DEBUG;%(PreprocessorDefinitions) + + + $(CoreLibraryDependencies);%(AdditionalDependencies);shell32.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + + + true + true + $(CoreLibraryDependencies);%(AdditionalDependencies);shell32.lib + + + + + + + + + + + + + + + Create + + + + + + + + + + + false + + + + + + + + + + + + + + + + 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/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj.filters b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj.filters new file mode 100644 index 0000000000..af63f3cf8e --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj.filters @@ -0,0 +1,37 @@ + + + + + accd3aa8-1ba0-4223-9bbe-0c431709210b + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms + + + {926ab91d-31b4-48c3-b9a4-e681349f27f0} + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft_Storage_Pickers.def b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft_Storage_Pickers.def new file mode 100644 index 0000000000..24e7c1235c --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft_Storage_Pickers.def @@ -0,0 +1,3 @@ +EXPORTS +DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE +DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp new file mode 100644 index 0000000000..63e29b7ebf --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp @@ -0,0 +1,200 @@ +#include "pch.h" +#include "PickerCommon.h" +#include +#include "ShObjIdl.h" +#include + +namespace { + + GUID HashHStringToGuid(winrt::hstring const& input) + { + auto algorithmProvider = 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 = algorithmProvider.HashData(buffer); + + if (hash.Length() != 16) + { + throw winrt::hresult_error(E_FAIL, L"Invalid hash length"); + } + + winrt::com_array resultBuffer{}; + winrt::Windows::Security::Cryptography::CryptographicBuffer::CopyToByteArray(hash, resultBuffer); + GUID guid = *(reinterpret_cast(resultBuffer.data())); + + // TODO: verify bit pattern code from copilot is correct to fit spec + // 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; + } + + // TODO: use better winrt implementations? + // Challenge: currently winrt based Storage.KnownFolder APIs does not provide all location id we need + winrt::com_ptr GetKnownFolderFromId(winrt::Microsoft::Storage::Pickers::PickerLocationId pickerLocationId) + { + KNOWNFOLDERID knownFolderId; + switch (pickerLocationId) + { + case winrt::Microsoft::Storage::Pickers::PickerLocationId::DocumentsLibrary: + knownFolderId = FOLDERID_Documents; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::ComputerFolder: + knownFolderId = FOLDERID_ComputerFolder; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::Desktop: + knownFolderId = FOLDERID_Desktop; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::Downloads: + knownFolderId = FOLDERID_Downloads; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::HomeGroup: + knownFolderId = FOLDERID_HomeGroup; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::MusicLibrary: + knownFolderId = FOLDERID_MusicLibrary; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::PicturesLibrary: + knownFolderId = FOLDERID_PicturesLibrary; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::VideosLibrary: + knownFolderId = FOLDERID_VideosLibrary; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::Objects3D: + knownFolderId = FOLDERID_Objects3D; + break; + default: + return nullptr; + } + + auto knownFolderManager = winrt::create_instance(CLSID_KnownFolderManager); + winrt::com_ptr knownFolder{}; + winrt::check_hresult(knownFolderManager->GetFolder(knownFolderId, knownFolder.put())); + winrt::com_ptr defaultFolder{}; + winrt::check_hresult(knownFolder->GetShellItem(0, IID_PPV_ARGS(defaultFolder.put()))); + 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) + { + // TODO: proper handling of null string reference? + return value.empty(); + } + + + // TODO: better way to convert ShellItem a StorageFile without relying on path?. + winrt::Windows::Foundation::IAsyncOperation CreateStorageFileFromShellItem(winrt::com_ptr shellItem) + { + wil::unique_cotaskmem_string filePath; + check_hresult(shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath)); + co_return co_await winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(filePath.get()); + } + + winrt::Windows::Foundation::IAsyncOperation CreateStorageFolderFromShellItem(winrt::com_ptr shellItem) + { + wil::unique_cotaskmem_string filePath; + check_hresult(shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath)); + co_return co_await winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(filePath.get()); + } + + 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 (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() }; + } + return result; + } + + 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() }; + } + 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->SetFolder(defaultFolder.get())); + check_hresult(dialog->SetDefaultFolder(defaultFolder.get())); + } + + check_hresult(dialog->SetFileTypes(FileTypeFilterPara.size(), FileTypeFilterPara.data())); + } +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h new file mode 100644 index 0000000000..de7db7ac54 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h @@ -0,0 +1,27 @@ +// TODO: use better namespace, maybe anonymous namespace? +#pragma once +#include "pch.h" +#include "ShObjIdl.h" +#include "winrt/Microsoft.Storage.Pickers.h" + +namespace PickerCommon { + winrt::Windows::Foundation::IAsyncOperation CreateStorageFileFromShellItem(winrt::com_ptr shellItem); + winrt::Windows::Foundation::IAsyncOperation CreateStorageFolderFromShellItem(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); + + // TODO: remove this if we know proper and null safe empty test for string + bool IsHStringNullOrEmpty(winrt::hstring value); + + struct PickerParameters { + HWND HWnd; + winrt::hstring CommitButtonText; + winrt::hstring SettingsIdentifierId; + winrt::Microsoft::Storage::Pickers::PickerLocationId PickerLocationId; + std::vector FileTypeFilterData{}; + std::vector FileTypeFilterPara{}; + + void ConfigureDialog(winrt::com_ptr dialog); + }; +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/Pickers.idl b/prototype-workingdir/Microsoft.Storage.Pickers/Pickers.idl new file mode 100644 index 0000000000..31c4c6c7ea --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/Pickers.idl @@ -0,0 +1,68 @@ +namespace Microsoft.Storage.Pickers +{ + enum PickerViewMode + { + List, + Thumbnail, + }; + + enum PickerLocationId + { + DocumentsLibrary, + ComputerFolder, + Desktop, + Downloads, + HomeGroup, + MusicLibrary, + PicturesLibrary, + VideosLibrary, + Objects3D, + Unspecified, + }; + + + [default_interface] + runtimeclass FileOpenPicker + { + FileOpenPicker(Microsoft.UI.WindowId windowId); + + Microsoft.Storage.Pickers.PickerViewMode ViewMode; + String SettingsIdentifier; + Microsoft.Storage.Pickers.PickerLocationId SuggestedStartLocation; + String CommitButtonText; + Windows.Foundation.Collections.IVector FileTypeFilter{ get; }; + + [remote_sync] Windows.Foundation.IAsyncOperation PickSingleFileAsync(); + [remote_sync] Windows.Foundation.IAsyncOperation > PickMultipleFilesAsync(); + } + + [default_interface] + runtimeclass FileSavePicker + { + FileSavePicker(Microsoft.UI.WindowId windowId); + + String SettingsIdentifier; + Microsoft.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(); + } + + [default_interface] + runtimeclass FolderPicker + { + FolderPicker(Microsoft.UI.WindowId windowId); + + Microsoft.Storage.Pickers.PickerViewMode ViewMode; + String SettingsIdentifier; + Microsoft.Storage.Pickers.PickerLocationId SuggestedStartLocation; + String CommitButtonText; + Windows.Foundation.Collections.IVector FileTypeFilter{ get; }; + + [remote_sync] Windows.Foundation.IAsyncOperation PickSingleFolderAsync(); + } +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/packages.config b/prototype-workingdir/Microsoft.Storage.Pickers/packages.config new file mode 100644 index 0000000000..6e553cc88c --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/pch.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/pch.cpp new file mode 100644 index 0000000000..1d9f38c57d --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/pch.h b/prototype-workingdir/Microsoft.Storage.Pickers/pch.h new file mode 100644 index 0000000000..21563b73b3 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/pch.h @@ -0,0 +1,33 @@ +#pragma once +#include +#include +#include +#include + +// Undefine GetCurrentTime macro to prevent +// conflict with Storyboard::GetCurrentTime +#undef GetCurrentTime + + +#include "winrt/Microsoft.Storage.Pickers.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/readme.txt b/prototype-workingdir/Microsoft.Storage.Pickers/readme.txt new file mode 100644 index 0000000000..6b46510cd0 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/readme.txt @@ -0,0 +1,27 @@ +======================================================================== + Microsoft.Storage.Pickers Project Overview +======================================================================== + +This project demonstrates how to get started authoring Windows Runtime +classes directly with standard C++, using the Windows App SDK and +C++/WinRT packages to generate implementation headers from interface +(IDL) files. The generated Windows Runtime component binary and WinMD +files should then be bundled with the app consuming them. + +Steps: +1. Create an interface (IDL) file to define your Windows Runtime class, + its default interface, and any other interfaces it implements. +2. Build the project once to generate module.g.cpp, module.h.cpp, and + implementation templates under the "Generated Files" folder, as + well as skeleton class definitions under "Generated Files\sources". +3. Use the skeleton class definitions for reference to implement your + Windows Runtime classes. + +======================================================================== +Learn more about Windows App SDK here: +https://docs.microsoft.com/windows/apps/windows-app-sdk/ +Learn more about WinUI3 here: +https://docs.microsoft.com/windows/apps/winui/winui3/ +Learn more about C++/WinRT here: +http://aka.ms/cppwinrt/ +======================================================================== diff --git a/prototype-workingdir/NuGet.config b/prototype-workingdir/NuGet.config new file mode 100644 index 0000000000..8e8d51bd44 --- /dev/null +++ b/prototype-workingdir/NuGet.config @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/prototype-workingdir/PickerUsageApp/App.xaml b/prototype-workingdir/PickerUsageApp/App.xaml new file mode 100644 index 0000000000..01e1e1c35d --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/App.xaml @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/prototype-workingdir/PickerUsageApp/App.xaml.cpp b/prototype-workingdir/PickerUsageApp/App.xaml.cpp new file mode 100644 index 0000000000..fb607703e2 --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/App.xaml.cpp @@ -0,0 +1,43 @@ +#include "pch.h" +#include "App.xaml.h" +#include "MainWindow.xaml.h" + +using namespace winrt; +using namespace Microsoft::UI::Xaml; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace winrt::PickerUsageApp::implementation +{ + /// + /// Initializes the singleton application object. This is the first line of authored code + /// executed, and as such is the logical equivalent of main() or WinMain(). + /// + App::App() + { + // Xaml objects should not call InitializeComponent during construction. + // See https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent + +#if defined _DEBUG && !defined DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION + UnhandledException([](IInspectable const&, UnhandledExceptionEventArgs const& e) + { + if (IsDebuggerPresent()) + { + auto errorMessage = e.Message(); + __debugbreak(); + } + }); +#endif + } + + /// + /// Invoked when the application is launched. + /// + /// Details about the launch request and process. + void App::OnLaunched([[maybe_unused]] LaunchActivatedEventArgs const& e) + { + window = make(); + window.Activate(); + } +} diff --git a/prototype-workingdir/PickerUsageApp/App.xaml.h b/prototype-workingdir/PickerUsageApp/App.xaml.h new file mode 100644 index 0000000000..fb5f632552 --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/App.xaml.h @@ -0,0 +1,16 @@ +#pragma once + +#include "App.xaml.g.h" + +namespace winrt::PickerUsageApp::implementation +{ + struct App : AppT + { + App(); + + void OnLaunched(Microsoft::UI::Xaml::LaunchActivatedEventArgs const&); + + private: + winrt::Microsoft::UI::Xaml::Window window{ nullptr }; + }; +} diff --git a/prototype-workingdir/PickerUsageApp/Assets/LockScreenLogo.scale-200.png b/prototype-workingdir/PickerUsageApp/Assets/LockScreenLogo.scale-200.png new file mode 100644 index 0000000000..7440f0d4bf Binary files /dev/null and b/prototype-workingdir/PickerUsageApp/Assets/LockScreenLogo.scale-200.png differ diff --git a/prototype-workingdir/PickerUsageApp/Assets/SplashScreen.scale-200.png b/prototype-workingdir/PickerUsageApp/Assets/SplashScreen.scale-200.png new file mode 100644 index 0000000000..32f486a867 Binary files /dev/null and b/prototype-workingdir/PickerUsageApp/Assets/SplashScreen.scale-200.png differ diff --git a/prototype-workingdir/PickerUsageApp/Assets/Square150x150Logo.scale-200.png b/prototype-workingdir/PickerUsageApp/Assets/Square150x150Logo.scale-200.png new file mode 100644 index 0000000000..53ee3777ea Binary files /dev/null and b/prototype-workingdir/PickerUsageApp/Assets/Square150x150Logo.scale-200.png differ diff --git a/prototype-workingdir/PickerUsageApp/Assets/Square44x44Logo.scale-200.png b/prototype-workingdir/PickerUsageApp/Assets/Square44x44Logo.scale-200.png new file mode 100644 index 0000000000..f713bba67f Binary files /dev/null and b/prototype-workingdir/PickerUsageApp/Assets/Square44x44Logo.scale-200.png differ diff --git a/prototype-workingdir/PickerUsageApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/prototype-workingdir/PickerUsageApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png new file mode 100644 index 0000000000..dc9f5bea0c Binary files /dev/null and b/prototype-workingdir/PickerUsageApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ diff --git a/prototype-workingdir/PickerUsageApp/Assets/StoreLogo.png b/prototype-workingdir/PickerUsageApp/Assets/StoreLogo.png new file mode 100644 index 0000000000..a4586f26bd Binary files /dev/null and b/prototype-workingdir/PickerUsageApp/Assets/StoreLogo.png differ diff --git a/prototype-workingdir/PickerUsageApp/Assets/Wide310x150Logo.scale-200.png b/prototype-workingdir/PickerUsageApp/Assets/Wide310x150Logo.scale-200.png new file mode 100644 index 0000000000..8b4a5d0dd5 Binary files /dev/null and b/prototype-workingdir/PickerUsageApp/Assets/Wide310x150Logo.scale-200.png differ diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.idl b/prototype-workingdir/PickerUsageApp/MainWindow.idl new file mode 100644 index 0000000000..90986b5614 --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/MainWindow.idl @@ -0,0 +1,8 @@ +namespace PickerUsageApp +{ + [default_interface] + runtimeclass MainWindow : Microsoft.UI.Xaml.Window + { + MainWindow(); + } +} diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.xaml b/prototype-workingdir/PickerUsageApp/MainWindow.xaml new file mode 100644 index 0000000000..d1d606df21 --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml @@ -0,0 +1,64 @@ + + + + + + + + + + + + Multi Selection + + + + CommitButtonText + Enable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp new file mode 100644 index 0000000000..054d68e36b --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp @@ -0,0 +1,322 @@ +#include "pch.h" +#include "MainWindow.xaml.h" +#if __has_include("MainWindow.g.cpp") +#include "MainWindow.g.cpp" +#endif +#include +#include +#include +#include + +using namespace winrt; +using namespace Microsoft::UI::Xaml; +//using namespace Windows::Foundation; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace winrt::PickerUsageApp::implementation +{ + Windows::Storage::Pickers::PickerViewMode Convert(Microsoft::Storage::Pickers::PickerViewMode viewMode) + { + switch (viewMode) + { + case winrt::Microsoft::Storage::Pickers::PickerViewMode::List: + return Windows::Storage::Pickers::PickerViewMode::List; + case winrt::Microsoft::Storage::Pickers::PickerViewMode::Thumbnail: + return Windows::Storage::Pickers::PickerViewMode::Thumbnail; + default: + return Windows::Storage::Pickers::PickerViewMode::List; + } + } + + winrt::Windows::Foundation::IAsyncAction MainWindow::SDKClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args) + { + labelBlock().Text(L""); + hstring message{}; + try + { + switch (m_PickerTypeIndex) + { + case 0: + message = co_await OpenFileSDKClick(sender, args); + break; + case 1: + message = co_await SaveFileSDKClick(); + break; + case 2: + message = co_await OpenFolderSDKClick(); + break; + default: + message = L"Unsupported Picker Type"; + break; + } + } + catch (winrt::hresult_error const& ex_) + { + message = ex_.message(); + } + labelBlock().Text(message); + } + + winrt::Windows::Foundation::IAsyncAction MainWindow::UWPClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args) + { + labelBlock().Text(L""); + hstring message{}; + try + { + switch (m_PickerTypeIndex) + { + case 0: + message = co_await OpenFileUWPClick(sender, args); + break; + case 1: + message = co_await SaveFileUWPClick(); + break; + case 2: + message = co_await OpenFolderUWPClick(); + break; + + default: + message = L"Unsupported Picker Type"; + break; + } + } + catch (winrt::hresult_error const& ex_) + { + message = ex_.message(); + } + labelBlock().Text(message); + } + + + Windows::Foundation::IAsyncOperation MainWindow::OpenFileUWPClick(IInspectable const&, RoutedEventArgs const&) + { + auto windowNative = this->m_inner.as(); + HWND hWnd = nullptr; + check_hresult(windowNative->get_WindowHandle(&hWnd)); + + winrt::Windows::Storage::Pickers::FileOpenPicker picker{}; + + picker.as<::IInitializeWithWindow>()->Initialize(hWnd); + SetOpenPickerOptions(picker); + picker.ViewMode(Convert(m_ViewMode)); + + if (!m_MultipleSelect) + { + auto& file = co_await picker.PickSingleFileAsync(); + if (file != nullptr) + { + co_return file.Path(); + } + } + else + { + auto& files = co_await picker.PickMultipleFilesAsync(); + winrt::hstring names = L""; + for (auto& file : files) + { + names = names + file.Path() + L"\n"; + } + co_return names; + } + co_return L"no selection"; + } + + Windows::Foundation::IAsyncOperation MainWindow::SaveFileUWPClick() + { + auto windowNative = this->m_inner.as(); + HWND hWnd = nullptr; + check_hresult(windowNative->get_WindowHandle(&hWnd)); + + winrt::Windows::Storage::Pickers::FileSavePicker picker{}; + + picker.as<::IInitializeWithWindow>()->Initialize(hWnd); + SetSavePickerOptions(picker); + + if (!m_MultipleSelect) + { + auto& file = co_await picker.PickSaveFileAsync(); + if (file != nullptr) + { + co_return file.Path(); + } + } + else + { + co_return L"File Save Picker does not support multi selection"; + } + co_return L"no selection"; + } + + winrt::Windows::Foundation::IAsyncOperation MainWindow::OpenFolderUWPClick() + { + auto windowNative = this->m_inner.as(); + HWND hWnd = nullptr; + check_hresult(windowNative->get_WindowHandle(&hWnd)); + + winrt::Windows::Storage::Pickers::FolderPicker picker{}; + + picker.as<::IInitializeWithWindow>()->Initialize(hWnd); + SetOpenPickerOptions(picker); + picker.ViewMode(Convert(m_ViewMode)); + + if (!m_MultipleSelect) + { + auto& folder = co_await picker.PickSingleFolderAsync(); + if (folder != nullptr) + { + co_return folder.Path(); + } + } + else + { + co_return L"Folder Picker does not support multi selection"; + } + co_return L"no selection"; + } + + Windows::Foundation::IAsyncOperation MainWindow::OpenFileSDKClick(IInspectable const&, RoutedEventArgs const&) + { + auto id = AppWindow().Id(); + winrt::Microsoft::Storage::Pickers::FileOpenPicker picker{ id }; + + SetOpenPickerOptions(picker); + picker.ViewMode(m_ViewMode); + if (!m_MultipleSelect) + { + auto& file = co_await picker.PickSingleFileAsync(); + if (file != nullptr) + { + co_return file.Path(); + } + } + else + { + auto& files = co_await picker.PickMultipleFilesAsync(); + winrt::hstring names = L""; + for (auto& file : files) + { + names = names + file.Path() + L"\n"; + } + co_return names; + } + co_return L"no selection"; + } + + Windows::Foundation::IAsyncOperation MainWindow::SaveFileSDKClick() + { + auto id = AppWindow().Id(); + winrt::Microsoft::Storage::Pickers::FileSavePicker picker{ id }; + + SetSavePickerOptions(picker); + if (!m_MultipleSelect) + { + auto& file = co_await picker.PickSaveFileAsync(); + if (file != nullptr) + { + co_return file.Path(); + } + } + else + { + co_return L"FileSavePicker does not support multi selection"; + } + co_return L"no selection"; + } + + winrt::Windows::Foundation::IAsyncOperation MainWindow::OpenFolderSDKClick() + { + auto id = AppWindow().Id(); + winrt::Microsoft::Storage::Pickers::FolderPicker picker{ id }; + + SetOpenPickerOptions(picker); + picker.ViewMode(m_ViewMode); + if (!m_MultipleSelect) + { + auto& folder = co_await picker.PickSingleFolderAsync(); + if (folder != nullptr) + { + co_return folder.Path(); + } + } + else + { + co_return L"Folder multiple selection is not supported"; + } + co_return L"no selection"; + } +} + + +void winrt::PickerUsageApp::implementation::MainWindow::UIFronzenTestClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) +{ + counterBlock().Text(std::to_wstring(count)); + count++; +} + + +void winrt::PickerUsageApp::implementation::MainWindow::toggleCustomLableClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) +{ + m_isUseCustomLabel = !m_isUseCustomLabel; + if (m_isUseCustomLabel) + { + useCustomLabelToggle().Content(box_value(L"Disable")); + customLabelBox().Visibility(Visibility::Visible); + } + else + { + useCustomLabelToggle().Content(box_value(L"Enable")); + customLabelBox().Visibility(Visibility::Collapsed); + } +} + + +void winrt::PickerUsageApp::implementation::MainWindow::ViewModeSelectionChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e) +{ + auto radioButtons = sender.as(); + auto selectedIndex = radioButtons.SelectedIndex(); + switch (selectedIndex) + { + case 0: + m_ViewMode = Microsoft::Storage::Pickers::PickerViewMode::List; + break; + case 1: + m_ViewMode = Microsoft::Storage::Pickers::PickerViewMode::Thumbnail; + break; + default: + break; + } +} + + +void winrt::PickerUsageApp::implementation::MainWindow::FilterTypeSelectionChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e) +{ + auto radioButtons = sender.as(); + + m_FilterTypeIndex = radioButtons.SelectedIndex(); +} + + +void winrt::PickerUsageApp::implementation::MainWindow::SettingsIdentifierChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e) +{ + auto radioButtons = sender.as(); + m_SettingsIdentifierIndex = radioButtons.SelectedIndex(); +} + +void winrt::PickerUsageApp::implementation::MainWindow::PickerLocationIdChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e) +{ + auto radioButtons = sender.as(); + m_PickerLocationIdIndex = radioButtons.SelectedIndex(); +} + + +void winrt::PickerUsageApp::implementation::MainWindow::MultiSelectToggled(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) +{ + m_MultipleSelect = sender.as().IsOn(); +} + +void winrt::PickerUsageApp::implementation::MainWindow::PickerTypeChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) +{ + m_PickerTypeIndex = sender.as().SelectedIndex(); +} diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h new file mode 100644 index 0000000000..53dee22f4f --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h @@ -0,0 +1,115 @@ +#pragma once + +#include "MainWindow.g.h" +#include + +namespace winrt::PickerUsageApp::implementation +{ + struct MainWindow : MainWindowT + { + int count{ 0 }; + + MainWindow() + { + // Xaml objects should not call InitializeComponent during construction. + // See https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent + } + + winrt::Windows::Foundation::IAsyncOperation OpenFileSDKClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); + winrt::Windows::Foundation::IAsyncOperation OpenFileUWPClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); + + winrt::Windows::Foundation::IAsyncOperation SaveFileUWPClick(); + winrt::Windows::Foundation::IAsyncOperation SaveFileSDKClick(); + + winrt::Windows::Foundation::IAsyncOperation OpenFolderSDKClick(); + winrt::Windows::Foundation::IAsyncOperation OpenFolderUWPClick(); + + + winrt::Windows::Foundation::IAsyncAction SDKClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); + winrt::Windows::Foundation::IAsyncAction UWPClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); + + void UIFronzenTestClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); + void toggleCustomLableClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); + void ViewModeSelectionChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e); + void FilterTypeSelectionChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e); + void SettingsIdentifierChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e); + void PickerLocationIdChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e); + void MultiSelectToggled(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); + void PickerTypeChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); + + private: + bool m_isUseCustomLabel{ false }; + winrt::Microsoft::Storage::Pickers::PickerViewMode m_ViewMode{ Microsoft::Storage::Pickers::PickerViewMode::List }; + int m_FilterTypeIndex{ 0 }; + int m_SettingsIdentifierIndex{ 0 }; + int m_PickerLocationIdIndex{ 0 }; + int m_PickerTypeIndex{ 0 }; + bool m_MultipleSelect{ false }; + + + // using this template approach helps us ensure use same logic on compatible user facing API + template void SetCommonPickerOptions(TPicker picker) + { + if (m_isUseCustomLabel) + { + picker.CommitButtonText(customLabelBox().Text()); + } + switch (m_SettingsIdentifierIndex) + { + case 1: + picker.SettingsIdentifier(L"Identifier1"); + break; + case 2: + picker.SettingsIdentifier(L"Identifier2"); + break; + default: + picker.SettingsIdentifier({}); + break; + } + switch (m_PickerLocationIdIndex) + { + case 1: + picker.SuggestedStartLocation(TPickerLocationId::DocumentsLibrary); + break; + case 2: + picker.SuggestedStartLocation(TPickerLocationId::Desktop); + break; + default: + break; + } + } + + template void SetOpenPickerOptions(TPicker picker) + { + SetCommonPickerOptions(picker); + switch (m_FilterTypeIndex) + { + case 1: + picker.FileTypeFilter().Append(L".jpg"); + picker.FileTypeFilter().Append(L".png"); + break; + case 2: + picker.FileTypeFilter().Append(L".jpg"); + picker.FileTypeFilter().Append(L".png"); + picker.FileTypeFilter().Append(L".json"); + break; + default: + picker.FileTypeFilter().Append(L"*"); + break; + } + } + + template void SetSavePickerOptions(TPicker picker) + { + SetCommonPickerOptions(picker); + picker.FileTypeChoices().Insert(L"Plain Text", winrt::single_threaded_vector({ L".txt" })); + } + }; +} + +namespace winrt::PickerUsageApp::factory_implementation +{ + struct MainWindow : MainWindowT + { + }; +} diff --git a/prototype-workingdir/PickerUsageApp/Package.appxmanifest b/prototype-workingdir/PickerUsageApp/Package.appxmanifest new file mode 100644 index 0000000000..a9df97a30d --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/Package.appxmanifest @@ -0,0 +1,51 @@ + + + + + + + + + + PickerUsageApp + xianghong + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/prototype-workingdir/PickerUsageApp/PickerUsageApp.vcxproj b/prototype-workingdir/PickerUsageApp/PickerUsageApp.vcxproj new file mode 100644 index 0000000000..705335bb5e --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/PickerUsageApp.vcxproj @@ -0,0 +1,199 @@ + + + + + + + true + true + true + {c0c88f67-8c6c-49f8-827e-86c0e1669f09} + PickerUsageApp + PickerUsageApp + + $(RootNamespace) + en-US + 16.0 + false + true + Windows Store + 10.0 + 10.0 + 10.0.17763.0 + true + true + + + + + Debug + Win32 + + + Debug + x64 + + + Debug + ARM64 + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + Application + v143 + Unicode + true + + + true + true + + + false + true + false + + + + + + + + + + + Use + pch.h + $(IntDir)pch.pch + Level4 + %(AdditionalOptions) /bigobj + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + NDEBUG;%(PreprocessorDefinitions) + + + true + true + + + + + Designer + + + + + + + + + App.xaml + + + MainWindow.xaml + + + + + + + + + Create + + + App.xaml + + + MainWindow.xaml + + + + + + Code + MainWindow.xaml + + + + + false + + + + + + + + + + + + + + + + + + + + + {349e64cf-cb0c-4202-b1b5-7f543cc6e886} + + + + + true + + + + + + + + + + + + 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/prototype-workingdir/PickerUsageApp/PickerUsageApp.vcxproj.filters b/prototype-workingdir/PickerUsageApp/PickerUsageApp.vcxproj.filters new file mode 100644 index 0000000000..897732b290 --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/PickerUsageApp.vcxproj.filters @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + + + {c0c88f67-8c6c-49f8-827e-86c0e1669f09} + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/prototype-workingdir/PickerUsageApp/app.manifest b/prototype-workingdir/PickerUsageApp/app.manifest new file mode 100644 index 0000000000..978e572078 --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/app.manifest @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + PerMonitorV2 + + + \ No newline at end of file diff --git a/prototype-workingdir/PickerUsageApp/packages.config b/prototype-workingdir/PickerUsageApp/packages.config new file mode 100644 index 0000000000..6e553cc88c --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/prototype-workingdir/PickerUsageApp/pch.cpp b/prototype-workingdir/PickerUsageApp/pch.cpp new file mode 100644 index 0000000000..ce9b73991b --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/pch.cpp @@ -0,0 +1,2 @@ +#include "pch.h" + diff --git a/prototype-workingdir/PickerUsageApp/pch.h b/prototype-workingdir/PickerUsageApp/pch.h new file mode 100644 index 0000000000..fe1ff28578 --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/pch.h @@ -0,0 +1,32 @@ +#pragma once +#include +#include +#include +#include + +// Undefine GetCurrentTime macro to prevent +// conflict with Storyboard::GetCurrentTime +#undef GetCurrentTime + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "winrt/Microsoft.Storage.Pickers.h" +#include "winrt/Windows.Storage.Pickers.h" +#include "winrt/Windows.Storage.h" +#include +#include +#include + +#include diff --git a/prototype-workingdir/PickerUsageApp/readme.txt b/prototype-workingdir/PickerUsageApp/readme.txt new file mode 100644 index 0000000000..0241fd41ef --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/readme.txt @@ -0,0 +1,27 @@ +======================================================================== + PickerUsageApp Project Overview +======================================================================== + +This project demonstrates how to get started writing WinUI3 apps directly +with standard C++, using the Windows App SDK and C++/WinRT packages and +XAML compiler support to generate implementation headers from interface +(IDL) files. These headers can then be used to implement the local +Windows Runtime classes referenced in the app's XAML pages. + +Steps: +1. Create an interface (IDL) file to define any local Windows Runtime + classes referenced in the app's XAML pages. +2. Build the project once to generate implementation templates under + the "Generated Files" folder, as well as skeleton class definitions + under "Generated Files\sources". +3. Use the skeleton class definitions for reference to implement your + Windows Runtime classes. + +======================================================================== +Learn more about Windows App SDK here: +https://docs.microsoft.com/windows/apps/windows-app-sdk/ +Learn more about WinUI3 here: +https://docs.microsoft.com/windows/apps/winui/winui3/ +Learn more about C++/WinRT here: +http://aka.ms/cppwinrt/ +======================================================================== diff --git a/prototype-workingdir/PickersPrototype.sln b/prototype-workingdir/PickersPrototype.sln new file mode 100644 index 0000000000..66bdb66599 --- /dev/null +++ b/prototype-workingdir/PickersPrototype.sln @@ -0,0 +1,57 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35431.28 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Storage.Pickers", "Microsoft.Storage.Pickers\Microsoft.Storage.Pickers.vcxproj", "{349E64CF-CB0C-4202-B1B5-7F543CC6E886}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PickerUsageApp", "PickerUsageApp\PickerUsageApp.vcxproj", "{C0C88F67-8C6C-49F8-827E-86C0E1669F09}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Debug|ARM64.Build.0 = Debug|ARM64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Debug|x64.ActiveCfg = Debug|x64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Debug|x64.Build.0 = Debug|x64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Debug|x86.ActiveCfg = Debug|Win32 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Debug|x86.Build.0 = Debug|Win32 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Release|ARM64.ActiveCfg = Release|ARM64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Release|ARM64.Build.0 = Release|ARM64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Release|x64.ActiveCfg = Release|x64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Release|x64.Build.0 = Release|x64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Release|x86.ActiveCfg = Release|Win32 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Release|x86.Build.0 = Release|Win32 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|ARM64.Build.0 = Debug|ARM64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|x64.ActiveCfg = Debug|x64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|x64.Build.0 = Debug|x64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|x64.Deploy.0 = Debug|x64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|x86.ActiveCfg = Debug|Win32 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|x86.Build.0 = Debug|Win32 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|x86.Deploy.0 = Debug|Win32 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|ARM64.ActiveCfg = Release|ARM64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|ARM64.Build.0 = Release|ARM64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|ARM64.Deploy.0 = Release|ARM64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|x64.ActiveCfg = Release|x64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|x64.Build.0 = Release|x64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|x64.Deploy.0 = Release|x64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|x86.ActiveCfg = Release|Win32 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|x86.Build.0 = Release|Win32 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|x86.Deploy.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4C5161F0-084E-45BA-B6B8-9A15B5EB5725} + EndGlobalSection +EndGlobal diff --git a/prototype-workingdir/README.md b/prototype-workingdir/README.md new file mode 100644 index 0000000000..3d9d6793a6 --- /dev/null +++ b/prototype-workingdir/README.md @@ -0,0 +1,26 @@ +# Picker Prototypes Implementation Notes + +This folder contains prototype implementations for adding types in `Storage.Pickers` to the Windows App SDK. It is currently under development and **not** ready for review or production use. + +NOTE: a develop certificate maybe required to run the demo app, if you encounter deployment issues, please add a new certificate to the PickerUsageApp project. + +## Current State + +- Basic implementation of most core functionalities was added in `Microsoft.Storage.Pickers/`. +- A basic demo app for testing and comparing purpose was added in `PickerUsageApp/`. + +### Next steps +- Additional argument validation needs to be added. +- More detailed error handling and exception code, with proper internationalization (localization), is required. +- Add Unit tests +- Need to be moved to proper folder and integrate with normal WinAppSDK pipeline + +## Questions + +- The implementation of `SettingsIdentifier` is based on `IFileDialog`'s `SetClientGuid` method, which requires converting the user-provided `SettingsIdentifier` string into a GUID to pass to `SetClientGuid`. We are using MD5 hashing for this conversion to avoid dependence on external state (static or other persistent states). Is this an acceptable approach? +- The implementation uses Win32 interop APIs, which require linking to `Shell32.lib`. Is this the correct way to implement pickers? +- Should we check for COM initialization? +- How can we obtain resources (i18n) for proper error reporting for hardcoded labels like `"All"` for `*` file type filters? + + + diff --git a/prototype-workingdir/environment.props b/prototype-workingdir/environment.props new file mode 100644 index 0000000000..6dc4195c32 --- /dev/null +++ b/prototype-workingdir/environment.props @@ -0,0 +1 @@ + \ No newline at end of file