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 @@ <!-- CameraCaptureUI --> <ActivatableClass ActivatableClassId="Microsoft.Windows.Media.Capture.CameraCaptureUI" ThreadingModel="both" /> + + <!-- StoragePickers --> + <ActivatableClass ActivatableClassId="Microsoft.Windows.Storage.Pickers.FileOpenPicker" ThreadingModel="both" /> </InProcessServer> </Extension> <Extension Category="windows.activatableClass.proxyStub"> 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 @@ <Implementation Condition="'$(WindowsAppSDKFrameworkPackage)' != 'true'">$(MSBuildThisFileDirectory)..\..\runtimes\win10-$(_WindowsAppSDKFoundationPlatform)\native\Microsoft.WindowsAppRuntime.dll</Implementation> <IsWinMDFile>true</IsWinMDFile> </Reference> + <Reference Include="Microsoft.Windows.Storage.Pickers.winmd" + Condition="Exists('$(MSBuildThisFileDirectory)..\..\lib\uap10.0\Microsoft.Windows.Storage.Pickers.winmd')"> + <HintPath>$(MSBuildThisFileDirectory)..\..\lib\uap10.0\Microsoft.Windows.Storage.Pickers.winmd</HintPath> + <Implementation Condition="'$(WindowsAppSDKFrameworkPackage)' != 'true'">$(MSBuildThisFileDirectory)..\..\runtimes\win10-$(_WindowsAppSDKFoundationPlatform)\native\Microsoft.WindowsAppRuntime.dll</Implementation> + <IsWinMDFile>true</IsWinMDFile> + </Reference> </ItemGroup> </Project> 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 @@ </Reference> </ItemGroup> + <ItemGroup> + <Reference Include="$(MSBuildThisFileDirectory)..\..\lib\uap10.0\Microsoft.Windows.Storage.Pickers.winmd" + Condition="Exists('$(MSBuildThisFileDirectory)..\..\lib\uap10.0\Microsoft.Windows.Storage.Pickers.winmd')"> + <Private>false</Private> + <Implementation>Microsoft.WindowsAppRuntime.dll</Implementation> + </Reference> + </ItemGroup> + <Import Project="$(MSBuildThisFileDirectory)..\Microsoft.WindowsAppSDK.BootstrapCommon.targets" /> <Import Project="$(MSBuildThisFileDirectory)WindowsAppSDK-Nuget-Native.Bootstrap.targets" Condition="'$(WindowsAppSdkBootstrapInitialize)' == 'true'"/> 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 <windows.h> +#include <shobjidl.h> +#include <wil/cppwinrt.h> +#include <wil/com.h> +#include <wil/resource.h> + +namespace winrt::Microsoft::Windows::Storage::Pickers::implementation +{ + winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> 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<IFileOpenDialog> 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<IShellItem> 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> + { + FileOpenPicker() = default; + winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> PickSingleFileAsync(); + + private: + TelemetryHelper m_telemetryHelper; + }; +} + +namespace winrt::Microsoft::Windows::Storage::Pickers::factory_implementation +{ + struct FileOpenPicker : FileOpenPickerT<FileOpenPicker, implementation::FileOpenPicker> + { + }; +} 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<Windows.Storage.StorageFile> 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup Label="Globals"> + <MSBuildAllProjects Condition="'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' < '16.0'">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects> + <HasSharedItems>true</HasSharedItems> + <ItemsProjectGuid>{a39e7b2f-5f67-47dd-8443-531d095ca7f3}</ItemsProjectGuid> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)</AdditionalIncludeDirectories> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ProjectCapability Include="SourceItemsFromImports" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="$(MSBuildThisFileDirectory)FileOpenPicker.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="$(MSBuildThisFileDirectory)FileOpenPicker.h" /> + </ItemGroup> + <ItemGroup> + <Midl Include="$(MSBuildThisFileDirectory)FileOpenPicker.idl" /> + </ItemGroup> +</Project> \ 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 <TelemetryHelper.h> + +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 @@ +<Project Sdk="Microsoft.NET.Sdk"> + <PropertyGroup> + <TargetFramework>net6.0-windows10.0.17763.0</TargetFramework> + <TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion> + <Platforms>x64;x86;arm64</Platforms> + <PlatformTarget>AnyCPU</PlatformTarget> + <GenerateAssemblyInfo>false</GenerateAssemblyInfo> + </PropertyGroup> + + <PropertyGroup> + <EnableTrimAnalyzer>true</EnableTrimAnalyzer> + <IsTrimmable>true</IsTrimmable> + </PropertyGroup> + + <!-- Suppress CS8305: Feature is for evaluation purposes only and is subject to change or removal in future updates. --> + <PropertyGroup> + <NoWarn>8305</NoWarn> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="Microsoft.SourceLink.Common"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + <PackageReference Include="Microsoft.SourceLink.GitHub"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + <PackageReference Include="Microsoft.Windows.CsWinRT" /> + </ItemGroup> + + <PropertyGroup> + <CSWinRTIncludes>Microsoft.Windows.Storage.Pickers</CSWinRTIncludes> + <CSWinRTWindowsMetadata>10.0.17763.0</CSWinRTWindowsMetadata> + <ProduceReferenceAssembly>false</ProduceReferenceAssembly> + </PropertyGroup> + + <!-- Configure the release build binary to be as required by internal API scanning tools. --> + <PropertyGroup Condition="'$(Configuration)'=='Release'"> + <DebugType>pdbonly</DebugType> + <DebugSymbols>true</DebugSymbols> + </PropertyGroup> + + <ItemGroup> + <CsWinRTInputs Include="$(OutDir)/**/*.winmd" /> + </ItemGroup> + + <ItemGroup> + <Compile Include="$(RepoRoot)\build\VersionInfo\AssemblyInfo.cs" Link="AssemblyInfo.cs" /> + </ItemGroup> + + <ItemGroup> + <Reference Include="Microsoft.Windows.Storage.Pickers"> + <HintPath>$(OutDir)..\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Storage.Pickers.winmd</HintPath> + <IsWinMDFile>true</IsWinMDFile> + </Reference> + </ItemGroup> +</Project> 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 @@ <Import Project="..\PackageManager\API\PackageManager.vcxitems" Label="Shared" /> <Import Project="..\BackgroundTask\BackgroundTaskBuilder\BackgroundTaskBuilder.vcxitems" Label="Shared" /> <Import Project="..\Interop\CameraCaptureUI\CameraCaptureUI\CameraCaptureUI.vcxitems"/> + <Import Project="..\Interop\StoragePicker\StoragePicker.vcxitems" /> </ImportGroup> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 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 @@ +<Project/> \ 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 @@ +<Project/> \ 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 <windows.h> +#include <shobjidl.h> +#include <shobjidl_core.h> +#include <winrt/Microsoft.UI.Interop.h> +#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<hstring> 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<winrt::Windows::Storage::StorageFile> 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<IFileOpenDialog>(CLSID_FileOpenDialog, CONTEXT_ALL); + + parameters.ConfigureDialog(dialog); + + { + auto hr = dialog->Show(parameters.HWnd); + if (FAILED(hr) || cancellationToken()) + { + co_return nullptr; + } + } + + winrt::com_ptr<IShellItem> 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<winrt::Windows::Foundation::Collections::IVectorView<winrt::Windows::Storage::StorageFile>> FileOpenPicker::PickMultipleFilesAsync() + { + PickerCommon::PickerParameters parameters{}; + + CaptureParameters(parameters); + + co_await winrt::resume_background(); + + winrt::Windows::Foundation::Collections::IVector<winrt::Windows::Storage::StorageFile> results{ winrt::single_threaded_vector<winrt::Windows::Storage::StorageFile>() }; + + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return results.GetView(); + } + + auto dialog = create_instance<IFileOpenDialog>(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<IShellItemArray> shellItems{}; + check_hresult(dialog->GetResults(shellItems.put())); + + DWORD itemCount = 0; + check_hresult(shellItems->GetCount(&itemCount)); + + winrt::com_ptr<IShellItem> 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> + { + 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<hstring> FileTypeFilter(); + + winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> PickSingleFileAsync(); + winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Foundation::Collections::IVectorView<winrt::Windows::Storage::StorageFile>> 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<hstring> m_fileTypeFilter{ winrt::single_threaded_vector<hstring>() }; + + void CaptureParameters(PickerCommon::PickerParameters& parameters); + }; +} +namespace winrt::Microsoft::Storage::Pickers::factory_implementation +{ + struct FileOpenPicker : FileOpenPickerT<FileOpenPicker, implementation::FileOpenPicker> + { + }; +} 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 <windows.h> +#include <shobjidl.h> +#include <shobjidl_core.h> +#include <KnownFolders.h> +#include <wil/cppwinrt.h> +#include <wil/com.h> +#include <wil/resource.h> +#include <Microsoft.Ui.Xaml.Window.h> +#include <winrt/Microsoft.UI.Interop.h> +#include <winrt/Windows.Foundation.Collections.h> +#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<hstring, winrt::Windows::Foundation::Collections::IVector<hstring>> 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<winrt::Windows::Storage::StorageFile> 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<IFileSaveDialog>(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<IShellItem> 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<IShellItem> 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> + { + 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<hstring, winrt::Windows::Foundation::Collections::IVector<hstring>> 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<winrt::Windows::Storage::StorageFile> PickSaveFileAsync(); + + private: + winrt::Microsoft::UI::WindowId m_windowId{}; + hstring m_settingsIdentifier{}; + PickerLocationId m_suggestedStartLocation{ PickerLocationId::Unspecified }; + hstring m_commitButtonText{}; + winrt::Windows::Foundation::Collections::IMap<hstring, winrt::Windows::Foundation::Collections::IVector<hstring>> m_fileTypeChoices{ winrt::single_threaded_map<hstring, winrt::Windows::Foundation::Collections::IVector<hstring>>() }; + 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<FileSavePicker, implementation::FileSavePicker> + { + }; +} 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 <shobjidl.h> +#include <shobjidl_core.h> +#include <winrt/Microsoft.UI.Interop.h> +#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<hstring> 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<winrt::Windows::Storage::StorageFolder> 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<IFileOpenDialog>(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<IShellItem> 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> + { + 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<hstring> FileTypeFilter(); + + winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFolder> 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<hstring> m_fileTypeFilter{ winrt::single_threaded_vector<hstring>() }; + + void CaptureParameters(PickerCommon::PickerParameters& parameters); + }; +} +namespace winrt::Microsoft::Storage::Pickers::factory_implementation +{ + struct FolderPicker : FolderPickerT<FolderPicker, implementation::FolderPicker> + { + }; +} 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.props')" /> + <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props')" /> + <Import Project="..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.props')" /> + <PropertyGroup Label="Globals"> + <CppWinRTOptimized>true</CppWinRTOptimized> + <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge> + <MinimalCoreWin>true</MinimalCoreWin> + <ProjectGuid>{349e64cf-cb0c-4202-b1b5-7f543cc6e886}</ProjectGuid> + <ProjectName>Microsoft.Storage.Pickers</ProjectName> + <RootNamespace>Microsoft.Storage.Pickers</RootNamespace> + <DefaultLanguage>en-US</DefaultLanguage> + <MinimumVisualStudioVersion>16.0</MinimumVisualStudioVersion> + <AppContainerApplication>false</AppContainerApplication> + <ApplicationType>Windows Store</ApplicationType> + <ApplicationTypeRevision>10.0</ApplicationTypeRevision> + <WindowsTargetPlatformVersion Condition=" '$(WindowsTargetPlatformVersion)' == '' ">10.0.22621.0</WindowsTargetPlatformVersion> + <WindowsTargetPlatformMinVersion>10.0.22000.0</WindowsTargetPlatformMinVersion> + <DesktopCompatible>true</DesktopCompatible> + <UseWinUI>true</UseWinUI> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|ARM64"> + <Configuration>Debug</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM64"> + <Configuration>Release</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v143</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + <GenerateManifest>false</GenerateManifest> + <DesktopCompatible>true</DesktopCompatible> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration"> + <UseDebugLibraries>true</UseDebugLibraries> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration"> + <UseDebugLibraries>false</UseDebugLibraries> + <WholeProgramOptimization>true</WholeProgramOptimization> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <ItemDefinitionGroup> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile> + <WarningLevel>Level4</WarningLevel> + <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions> + <PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateWindowsMetadata>true</GenerateWindowsMetadata> + <ModuleDefinitionFile>Microsoft_Storage_Pickers.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'"> + <ClCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <AdditionalDependencies>$(CoreLibraryDependencies);%(AdditionalDependencies);shell32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)'=='Release'"> + <ClCompile> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <AdditionalDependencies>$(CoreLibraryDependencies);%(AdditionalDependencies);shell32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClInclude Include="FileOpenPicker.h" /> + <ClInclude Include="FileSavePicker.h" /> + <ClInclude Include="FolderPicker.h" /> + <ClInclude Include="pch.h" /> + <ClInclude Include="PickerCommon.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="FileOpenPicker.cpp" /> + <ClCompile Include="FileSavePicker.cpp" /> + <ClCompile Include="FolderPicker.cpp" /> + <ClCompile Include="pch.cpp"> + <PrecompiledHeader>Create</PrecompiledHeader> + </ClCompile> + <ClCompile Include="$(GeneratedFilesDir)module.g.cpp" /> + <ClCompile Include="PickerCommon.cpp" /> + </ItemGroup> + <ItemGroup> + <None Include="Microsoft_Storage_Pickers.def" /> + <None Include="packages.config" /> + </ItemGroup> + <ItemGroup> + <Text Include="readme.txt"> + <DeploymentContent>false</DeploymentContent> + </Text> + </ItemGroup> + <ItemGroup> + <Midl Include="Pickers.idl" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + <Import Project="..\packages\Microsoft.Web.WebView2.1.0.2651.64\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\packages\Microsoft.Web.WebView2.1.0.2651.64\build\native\Microsoft.Web.WebView2.targets')" /> + <Import Project="..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.targets')" /> + <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets')" /> + <Import Project="..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.targets')" /> + <Import Project="..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> + </ImportGroup> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>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}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\packages\Microsoft.Web.WebView2.1.0.2651.64\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Web.WebView2.1.0.2651.64\build\native\Microsoft.Web.WebView2.targets'))" /> + <Error Condition="!Exists('..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.props'))" /> + <Error Condition="!Exists('..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.targets'))" /> + <Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props'))" /> + <Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets'))" /> + <Error Condition="!Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.props'))" /> + <Error Condition="!Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.targets'))" /> + <Error Condition="!Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" /> + </Target> +</Project> \ 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Resources"> + <UniqueIdentifier>accd3aa8-1ba0-4223-9bbe-0c431709210b</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + <Filter Include="Generated Files"> + <UniqueIdentifier>{926ab91d-31b4-48c3-b9a4-e681349f27f0}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="pch.cpp" /> + <ClCompile Include="$(GeneratedFilesDir)module.g.cpp" /> + <ClCompile Include="FileOpenPicker.cpp" /> + <ClCompile Include="FileSavePicker.cpp" /> + <ClCompile Include="FolderPicker.cpp" /> + <ClCompile Include="PickerCommon.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="pch.h" /> + <ClInclude Include="FileOpenPicker.h" /> + <ClInclude Include="FileSavePicker.h" /> + <ClInclude Include="FolderPicker.h" /> + <ClInclude Include="PickerCommon.h" /> + </ItemGroup> + <ItemGroup> + <Midl Include="Pickers.idl" /> + </ItemGroup> + <ItemGroup> + <None Include="Microsoft_Storage_Pickers.def" /> + <None Include="packages.config" /> + </ItemGroup> + <ItemGroup> + <Text Include="readme.txt" /> + </ItemGroup> +</Project> \ 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 <wil/resource.h> +#include "ShObjIdl.h" +#include <KnownFolders.h> + +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<uint8_t> resultBuffer{}; + winrt::Windows::Security::Cryptography::CryptographicBuffer::CopyToByteArray(hash, resultBuffer); + GUID guid = *(reinterpret_cast<GUID*>(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<IShellItem> 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<IKnownFolderManager>(CLSID_KnownFolderManager); + winrt::com_ptr<IKnownFolder> knownFolder{}; + winrt::check_hresult(knownFolderManager->GetFolder(knownFolderId, knownFolder.put())); + winrt::com_ptr<IShellItem> 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<winrt::hstring> 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<winrt::Windows::Storage::StorageFile> CreateStorageFileFromShellItem(winrt::com_ptr<IShellItem> 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<winrt::Windows::Storage::StorageFolder> CreateStorageFolderFromShellItem(winrt::com_ptr<IShellItem> 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<COMDLG_FILTERSPEC> CaptureFilterSpec(std::vector<winrt::hstring>& buffer, winrt::Windows::Foundation::Collections::IVectorView<winrt::hstring> filters) + { + std::vector<COMDLG_FILTERSPEC> 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<COMDLG_FILTERSPEC> CaptureFilterSpec(std::vector<winrt::hstring>& buffer, winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, winrt::Windows::Foundation::Collections::IVector<hstring>> filters) + { + std::vector<COMDLG_FILTERSPEC> 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<IFileDialog> 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<winrt::Windows::Storage::StorageFile> CreateStorageFileFromShellItem(winrt::com_ptr<IShellItem> shellItem); + winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFolder> CreateStorageFolderFromShellItem(winrt::com_ptr<IShellItem> shellItem); + + std::vector<COMDLG_FILTERSPEC> CaptureFilterSpec(std::vector<winrt::hstring>& buffer, winrt::Windows::Foundation::Collections::IVectorView<winrt::hstring> filters); + std::vector<COMDLG_FILTERSPEC> CaptureFilterSpec(std::vector<winrt::hstring>& buffer, winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, winrt::Windows::Foundation::Collections::IVector<winrt::hstring>> 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<winrt::hstring> FileTypeFilterData{}; + std::vector<COMDLG_FILTERSPEC> FileTypeFilterPara{}; + + void ConfigureDialog(winrt::com_ptr<IFileDialog> 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<String> FileTypeFilter{ get; }; + + [remote_sync] Windows.Foundation.IAsyncOperation<Windows.Storage.StorageFile> PickSingleFileAsync(); + [remote_sync] Windows.Foundation.IAsyncOperation<Windows.Foundation.Collections.IVectorView<Windows.Storage.StorageFile> > PickMultipleFilesAsync(); + } + + [default_interface] + runtimeclass FileSavePicker + { + FileSavePicker(Microsoft.UI.WindowId windowId); + + String SettingsIdentifier; + Microsoft.Storage.Pickers.PickerLocationId SuggestedStartLocation; + String CommitButtonText; + Windows.Foundation.Collections.IMap<String, Windows.Foundation.Collections.IVector<String> > FileTypeChoices{ get; }; + String DefaultFileExtension; + Windows.Storage.StorageFile SuggestedSaveFile; + String SuggestedFileName; + + [remote_sync] Windows.Foundation.IAsyncOperation<Windows.Storage.StorageFile> 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<String> FileTypeFilter{ get; }; + + [remote_sync] Windows.Foundation.IAsyncOperation<Windows.Storage.StorageFolder> 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Microsoft.Web.WebView2" version="1.0.2651.64" targetFramework="native" /> + <package id="Microsoft.Windows.CppWinRT" version="2.0.240405.15" targetFramework="native" /> + <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240803.1" targetFramework="native" /> + <package id="Microsoft.Windows.SDK.BuildTools" version="10.0.26100.1742" targetFramework="native" /> + <package id="Microsoft.WindowsAppSDK" version="1.6.241114003" targetFramework="native" /> +</packages> \ 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 <windows.h> +#include <unknwn.h> +#include <restrictederrorinfo.h> +#include <hstring.h> + +// Undefine GetCurrentTime macro to prevent +// conflict with Storyboard::GetCurrentTime +#undef GetCurrentTime + + +#include "winrt/Microsoft.Storage.Pickers.h" +#include <winrt/Microsoft.UI.h> +#include <winrt/Microsoft.UI.Composition.h> +#include <winrt/Microsoft.UI.Dispatching.h> +#include <winrt/Microsoft.UI.Windowing.h> +#include <winrt/Microsoft.UI.Xaml.h> +#include <winrt/Microsoft.UI.Xaml.Controls.h> +#include <winrt/Microsoft.UI.Xaml.Controls.Primitives.h> +#include <winrt/Microsoft.UI.Xaml.Data.h> +#include <winrt/Microsoft.UI.Xaml.Interop.h> +#include <winrt/Microsoft.UI.Xaml.Markup.h> +#include <winrt/Microsoft.UI.Xaml.Media.h> +#include <winrt/Microsoft.UI.Xaml.Navigation.h> +#include <winrt/Microsoft.UI.Xaml.Shapes.h> +#include <winrt/Windows.ApplicationModel.Activation.h> +#include <winrt/Windows.Foundation.h> +#include <winrt/Windows.Foundation.Collections.h> +#include <winrt/Windows.Security.Cryptography.h> +#include <winrt/Windows.Security.Cryptography.Core.h> +#include <winrt/Windows.Storage.h> +#include <winrt/Windows.Storage.Streams.h> +#include <winrt/Windows.UI.Xaml.Interop.h> 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<configuration> + <config> + <add key="repositoryPath" value="Packages" /> + <add key="globalPackagesFolder" value="Packages" /> + </config> + <packageSources> + <clear /> + <add key='nuget.org' value='https://api.nuget.org/v3/index.json' /> + </packageSources> + <disabledPackageSources> + <clear /> + </disabledPackageSources> + <fallbackPackageFolders> + <clear /> + </fallbackPackageFolders> +</configuration> 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<Application + x:Class="PickerUsageApp.App" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="using:PickerUsageApp"> + <Application.Resources> + <ResourceDictionary> + <ResourceDictionary.MergedDictionaries> + <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" /> + <!-- Other merged dictionaries here --> + </ResourceDictionary.MergedDictionaries> + <!-- Other app resources here --> + </ResourceDictionary> + </Application.Resources> +</Application> 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 +{ + /// <summary> + /// 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(). + /// </summary> + 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 + } + + /// <summary> + /// Invoked when the application is launched. + /// </summary> + /// <param name="e">Details about the launch request and process.</param> + void App::OnLaunched([[maybe_unused]] LaunchActivatedEventArgs const& e) + { + window = make<MainWindow>(); + 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> + { + 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<Window + x:Class="PickerUsageApp.MainWindow" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="using:PickerUsageApp" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + mc:Ignorable="d" + Title="PickerUsageApp"> + <StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center"> + <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center"> + <RadioButtons SelectedIndex="0" SelectionChanged="PickerTypeChanged" Header="Picker"> + <RadioButton Content="File Open"></RadioButton> + <RadioButton Content="File Save"></RadioButton> + <RadioButton Content="Folder"></RadioButton> + </RadioButtons> + </StackPanel> + <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"> + <TextBlock VerticalAlignment="Center">Multi Selection</TextBlock> + <ToggleSwitch Toggled="MultiSelectToggled"/> + </StackPanel> + <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"> + <TextBlock VerticalAlignment="Center" >CommitButtonText</TextBlock> + <ToggleButton x:Name="useCustomLabelToggle" Click="toggleCustomLableClick">Enable</ToggleButton> + <TextBox x:Name="customLabelBox" Visibility="Collapsed"></TextBox> + </StackPanel> + <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"> + <RadioButtons SelectedIndex="0" SelectionChanged="FilterTypeSelectionChanged" Header="Filter Type Preset"> + <RadioButton Content="All"></RadioButton> + <RadioButton Content="Images"></RadioButton> + <RadioButton Content="Images and Json"></RadioButton> + </RadioButtons> + </StackPanel> + <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"> + <RadioButtons SelectedIndex="0" SelectionChanged="SettingsIdentifierChanged" Header="SettingsIdentifier"> + <RadioButton Content="Unspecified"></RadioButton> + <RadioButton Content="Identifier1"></RadioButton> + <RadioButton Content="Identifier2"></RadioButton> + </RadioButtons> + </StackPanel> + <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"> + <RadioButtons SelectedIndex="0" SelectionChanged="PickerLocationIdChanged" Header="PickerLocationId"> + <RadioButton Content="Unspecified"></RadioButton> + <RadioButton Content="Documents"></RadioButton> + <RadioButton Content="Desktop"></RadioButton> + </RadioButtons> + </StackPanel> + <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"> + <RadioButtons SelectedIndex="0" SelectionChanged="ViewModeSelectionChanged" Header="ViewMode"> + <RadioButton Content="List"></RadioButton> + <RadioButton Content="Thumbnail"></RadioButton> + </RadioButtons> + </StackPanel> + <!--<TextBlock>!!! WARN !!! Save picker will overwrite Context in selected file with test data</TextBlock>--> + <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"> + <Button Click="SDKClick">Run SDK Picker</Button> + <Button Click="UWPClick">Run UWP Picker</Button> + <TextBlock x:Name="counterBlock"></TextBlock> + </StackPanel> + <Button Click="UIFronzenTestClick">UI Fronzen Test</Button> + <TextBlock x:Name="labelBlock"></TextBlock> + </StackPanel> +</Window> 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 <string> +#include <shobjidl.h> +#include <microsoft.ui.xaml.window.h> +#include <winrt/Windows.UI.Popups.h> + +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<hstring> MainWindow::OpenFileUWPClick(IInspectable const&, RoutedEventArgs const&) + { + auto windowNative = this->m_inner.as<IWindowNative>(); + HWND hWnd = nullptr; + check_hresult(windowNative->get_WindowHandle(&hWnd)); + + winrt::Windows::Storage::Pickers::FileOpenPicker picker{}; + + picker.as<::IInitializeWithWindow>()->Initialize(hWnd); + SetOpenPickerOptions<winrt::Windows::Storage::Pickers::FileOpenPicker, winrt::Windows::Storage::Pickers::PickerLocationId>(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<hstring> MainWindow::SaveFileUWPClick() + { + auto windowNative = this->m_inner.as<IWindowNative>(); + HWND hWnd = nullptr; + check_hresult(windowNative->get_WindowHandle(&hWnd)); + + winrt::Windows::Storage::Pickers::FileSavePicker picker{}; + + picker.as<::IInitializeWithWindow>()->Initialize(hWnd); + SetSavePickerOptions<winrt::Windows::Storage::Pickers::FileSavePicker, winrt::Windows::Storage::Pickers::PickerLocationId>(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<hstring> MainWindow::OpenFolderUWPClick() + { + auto windowNative = this->m_inner.as<IWindowNative>(); + HWND hWnd = nullptr; + check_hresult(windowNative->get_WindowHandle(&hWnd)); + + winrt::Windows::Storage::Pickers::FolderPicker picker{}; + + picker.as<::IInitializeWithWindow>()->Initialize(hWnd); + SetOpenPickerOptions<winrt::Windows::Storage::Pickers::FolderPicker, winrt::Windows::Storage::Pickers::PickerLocationId>(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<hstring> MainWindow::OpenFileSDKClick(IInspectable const&, RoutedEventArgs const&) + { + auto id = AppWindow().Id(); + winrt::Microsoft::Storage::Pickers::FileOpenPicker picker{ id }; + + SetOpenPickerOptions<winrt::Microsoft::Storage::Pickers::FileOpenPicker, winrt::Microsoft::Storage::Pickers::PickerLocationId>(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<hstring> MainWindow::SaveFileSDKClick() + { + auto id = AppWindow().Id(); + winrt::Microsoft::Storage::Pickers::FileSavePicker picker{ id }; + + SetSavePickerOptions<winrt::Microsoft::Storage::Pickers::FileSavePicker, winrt::Microsoft::Storage::Pickers::PickerLocationId>(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<hstring> MainWindow::OpenFolderSDKClick() + { + auto id = AppWindow().Id(); + winrt::Microsoft::Storage::Pickers::FolderPicker picker{ id }; + + SetOpenPickerOptions<winrt::Microsoft::Storage::Pickers::FolderPicker, winrt::Microsoft::Storage::Pickers::PickerLocationId>(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<Microsoft::UI::Xaml::Controls::RadioButtons>(); + 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<Microsoft::UI::Xaml::Controls::RadioButtons>(); + + 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<Microsoft::UI::Xaml::Controls::RadioButtons>(); + 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<Microsoft::UI::Xaml::Controls::RadioButtons>(); + 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<Microsoft::UI::Xaml::Controls::ToggleSwitch>().IsOn(); +} + +void winrt::PickerUsageApp::implementation::MainWindow::PickerTypeChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) +{ + m_PickerTypeIndex = sender.as<Microsoft::UI::Xaml::Controls::RadioButtons>().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 <functional> + +namespace winrt::PickerUsageApp::implementation +{ + struct MainWindow : MainWindowT<MainWindow> + { + 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<hstring> OpenFileSDKClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); + winrt::Windows::Foundation::IAsyncOperation<hstring> OpenFileUWPClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); + + winrt::Windows::Foundation::IAsyncOperation<hstring> SaveFileUWPClick(); + winrt::Windows::Foundation::IAsyncOperation<hstring> SaveFileSDKClick(); + + winrt::Windows::Foundation::IAsyncOperation<hstring> OpenFolderSDKClick(); + winrt::Windows::Foundation::IAsyncOperation<hstring> 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<typename TPicker, typename TPickerLocationId> 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<typename TPicker, typename TPickerLocationId> void SetOpenPickerOptions(TPicker picker) + { + SetCommonPickerOptions<TPicker, TPickerLocationId>(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<typename TPicker, typename TPickerLocationId> void SetSavePickerOptions(TPicker picker) + { + SetCommonPickerOptions<TPicker, TPickerLocationId>(picker); + picker.FileTypeChoices().Insert(L"Plain Text", winrt::single_threaded_vector<hstring>({ L".txt" })); + } + }; +} + +namespace winrt::PickerUsageApp::factory_implementation +{ + struct MainWindow : MainWindowT<MainWindow, implementation::MainWindow> + { + }; +} 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 @@ +<?xml version="1.0" encoding="utf-8"?> + +<Package + xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" + xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" + xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" + xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" + IgnorableNamespaces="uap rescap"> + + <Identity + Name="d920e858-bb7b-4ffd-97b1-74a964a37df7" + Publisher="CN=xianghong" + Version="1.0.0.0" /> + + <mp:PhoneIdentity PhoneProductId="d920e858-bb7b-4ffd-97b1-74a964a37df7" PhonePublisherId="00000000-0000-0000-0000-000000000000"/> + + <Properties> + <DisplayName>PickerUsageApp</DisplayName> + <PublisherDisplayName>xianghong</PublisherDisplayName> + <Logo>Assets\StoreLogo.png</Logo> + </Properties> + + <Dependencies> + <TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" /> + <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" /> + </Dependencies> + + <Resources> + <Resource Language="x-generate"/> + </Resources> + + <Applications> + <Application Id="App" + Executable="$targetnametoken$.exe" + EntryPoint="$targetentrypoint$"> + <uap:VisualElements + DisplayName="PickerUsageApp" + Description="PickerUsageApp" + BackgroundColor="transparent" + Square150x150Logo="Assets\Square150x150Logo.png" + Square44x44Logo="Assets\Square44x44Logo.png"> + <uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" /> + <uap:SplashScreen Image="Assets\SplashScreen.png" /> + </uap:VisualElements> + </Application> + </Applications> + + <Capabilities> + <rescap:Capability Name="runFullTrust" /> + </Capabilities> +</Package> 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.props')" /> + <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props')" /> + <Import Project="..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.props')" /> + <PropertyGroup Label="Globals"> + <CppWinRTOptimized>true</CppWinRTOptimized> + <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge> + <MinimalCoreWin>true</MinimalCoreWin> + <ProjectGuid>{c0c88f67-8c6c-49f8-827e-86c0e1669f09}</ProjectGuid> + <ProjectName>PickerUsageApp</ProjectName> + <RootNamespace>PickerUsageApp</RootNamespace> + <!-- + $(TargetName) should be same as $(RootNamespace) so that the produced binaries (.exe/.pri/etc.) + have a name that matches the .winmd + --> + <TargetName>$(RootNamespace)</TargetName> + <DefaultLanguage>en-US</DefaultLanguage> + <MinimumVisualStudioVersion>16.0</MinimumVisualStudioVersion> + <AppContainerApplication>false</AppContainerApplication> + <AppxPackage>true</AppxPackage> + <ApplicationType>Windows Store</ApplicationType> + <ApplicationTypeRevision>10.0</ApplicationTypeRevision> + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> + <WindowsTargetPlatformMinVersion>10.0.17763.0</WindowsTargetPlatformMinVersion> + <UseWinUI>true</UseWinUI> + <EnableMsixTooling>true</EnableMsixTooling> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|ARM64"> + <Configuration>Debug</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM64"> + <Configuration>Release</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v143</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + <DesktopCompatible>true</DesktopCompatible> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration"> + <UseDebugLibraries>true</UseDebugLibraries> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration"> + <UseDebugLibraries>false</UseDebugLibraries> + <WholeProgramOptimization>true</WholeProgramOptimization> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <ItemDefinitionGroup> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile> + <WarningLevel>Level4</WarningLevel> + <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'"> + <ClCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)'=='Release'"> + <ClCompile> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup Condition="'$(WindowsPackageType)'!='None' and Exists('Package.appxmanifest')"> + <AppxManifest Include="Package.appxmanifest"> + <SubType>Designer</SubType> + </AppxManifest> + </ItemGroup> + <ItemGroup> + <Manifest Include="app.manifest" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="pch.h" /> + <ClInclude Include="App.xaml.h"> + <DependentUpon>App.xaml</DependentUpon> + </ClInclude> + <ClInclude Include="MainWindow.xaml.h"> + <DependentUpon>MainWindow.xaml</DependentUpon> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ApplicationDefinition Include="App.xaml" /> + <Page Include="MainWindow.xaml" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="pch.cpp"> + <PrecompiledHeader>Create</PrecompiledHeader> + </ClCompile> + <ClCompile Include="App.xaml.cpp"> + <DependentUpon>App.xaml</DependentUpon> + </ClCompile> + <ClCompile Include="MainWindow.xaml.cpp"> + <DependentUpon>MainWindow.xaml</DependentUpon> + </ClCompile> + <ClCompile Include="$(GeneratedFilesDir)module.g.cpp" /> + </ItemGroup> + <ItemGroup> + <Midl Include="MainWindow.idl"> + <SubType>Code</SubType> + <DependentUpon>MainWindow.xaml</DependentUpon> + </Midl> + </ItemGroup> + <ItemGroup> + <Text Include="readme.txt"> + <DeploymentContent>false</DeploymentContent> + </Text> + </ItemGroup> + <ItemGroup> + <Image Include="Assets\LockScreenLogo.scale-200.png" /> + <Image Include="Assets\SplashScreen.scale-200.png" /> + <Image Include="Assets\Square150x150Logo.scale-200.png" /> + <Image Include="Assets\Square44x44Logo.scale-200.png" /> + <Image Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" /> + <Image Include="Assets\StoreLogo.png" /> + <Image Include="Assets\Wide310x150Logo.scale-200.png" /> + </ItemGroup> + <!-- + Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging + Tools extension to be activated for this project even if the Windows App SDK Nuget + package has not yet been restored. + --> + <ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'"> + <ProjectCapability Include="Msix" /> + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\Microsoft.Storage.Pickers\Microsoft.Storage.Pickers.vcxproj"> + <Project>{349e64cf-cb0c-4202-b1b5-7f543cc6e886}</Project> + </ProjectReference> + </ItemGroup> + <!-- + Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution + Explorer "Package and Publish" context menu entry to be enabled for this project even if + the Windows App SDK Nuget package has not yet been restored. + --> + <PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'"> + <HasPackageAndPublishMenu>true</HasPackageAndPublishMenu> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + <Import Project="..\packages\Microsoft.Web.WebView2.1.0.2651.64\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\packages\Microsoft.Web.WebView2.1.0.2651.64\build\native\Microsoft.Web.WebView2.targets')" /> + <Import Project="..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.targets')" /> + <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets')" /> + <Import Project="..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.targets')" /> + <Import Project="..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> + </ImportGroup> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>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}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\packages\Microsoft.Web.WebView2.1.0.2651.64\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Web.WebView2.1.0.2651.64\build\native\Microsoft.Web.WebView2.targets'))" /> + <Error Condition="!Exists('..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.props'))" /> + <Error Condition="!Exists('..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.WindowsAppSDK.1.6.241114003\build\native\Microsoft.WindowsAppSDK.targets'))" /> + <Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props'))" /> + <Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets'))" /> + <Error Condition="!Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.props'))" /> + <Error Condition="!Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.1742\build\Microsoft.Windows.SDK.BuildTools.targets'))" /> + <Error Condition="!Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" /> + </Target> +</Project> \ 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ApplicationDefinition Include="App.xaml" /> + </ItemGroup> + <ItemGroup> + <Page Include="MainWindow.xaml" /> + </ItemGroup> + <ItemGroup> + <Midl Include="MainWindow.idl" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="pch.cpp" /> + <ClCompile Include="$(GeneratedFilesDir)module.g.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="pch.h" /> + </ItemGroup> + <ItemGroup> + <Image Include="Assets\Wide310x150Logo.scale-200.png"> + <Filter>Assets</Filter> + </Image> + <Image Include="Assets\StoreLogo.png"> + <Filter>Assets</Filter> + </Image> + <Image Include="Assets\Square150x150Logo.scale-200.png"> + <Filter>Assets</Filter> + </Image> + <Image Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png"> + <Filter>Assets</Filter> + </Image> + <Image Include="Assets\Square44x44Logo.scale-200.png"> + <Filter>Assets</Filter> + </Image> + <Image Include="Assets\SplashScreen.scale-200.png"> + <Filter>Assets</Filter> + </Image> + <Image Include="Assets\LockScreenLogo.scale-200.png"> + <Filter>Assets</Filter> + </Image> + </ItemGroup> + <ItemGroup> + <Filter Include="Assets"> + <UniqueIdentifier>{c0c88f67-8c6c-49f8-827e-86c0e1669f09}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <Text Include="readme.txt" /> + </ItemGroup> + <ItemGroup> + <Manifest Include="app.manifest" /> + </ItemGroup> + <ItemGroup> + <AppxManifest Include="Package.appxmanifest" /> + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + </ItemGroup> +</Project> \ 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> + <assemblyIdentity version="1.0.0.0" name="PickerUsageApp.app"/> + + <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> + <application> + <!-- The ID below informs the system that this application is compatible with OS features first introduced in Windows 10. + It is necessary to support features in unpackaged applications, for example the custom titlebar implementation. + For more info see https://docs.microsoft.com/windows/apps/windows-app-sdk/use-windows-app-sdk-run-time#declare-os-compatibility-in-your-application-manifest --> + <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /> + </application> + </compatibility> + + <application xmlns="urn:schemas-microsoft-com:asm.v3"> + <windowsSettings> + <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness> + </windowsSettings> + </application> +</assembly> \ 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Microsoft.Web.WebView2" version="1.0.2651.64" targetFramework="native" /> + <package id="Microsoft.Windows.CppWinRT" version="2.0.240405.15" targetFramework="native" /> + <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240803.1" targetFramework="native" /> + <package id="Microsoft.Windows.SDK.BuildTools" version="10.0.26100.1742" targetFramework="native" /> + <package id="Microsoft.WindowsAppSDK" version="1.6.241114003" targetFramework="native" /> +</packages> \ 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 <windows.h> +#include <unknwn.h> +#include <restrictederrorinfo.h> +#include <hstring.h> + +// Undefine GetCurrentTime macro to prevent +// conflict with Storyboard::GetCurrentTime +#undef GetCurrentTime + +#include <winrt/Windows.Foundation.h> +#include <winrt/Windows.Foundation.Collections.h> +#include <winrt/Windows.ApplicationModel.Activation.h> +#include <winrt/Microsoft.UI.Composition.h> +#include <winrt/Microsoft.UI.Xaml.h> +#include <winrt/Microsoft.UI.Xaml.Controls.h> +#include <winrt/Microsoft.UI.Xaml.Controls.Primitives.h> +#include <winrt/Microsoft.UI.Xaml.Data.h> +#include <winrt/Microsoft.UI.Xaml.Interop.h> +#include <winrt/Microsoft.UI.Xaml.Markup.h> +#include <winrt/Microsoft.UI.Xaml.Media.h> +#include <winrt/Microsoft.UI.Xaml.Navigation.h> +#include <winrt/Microsoft.UI.Xaml.Shapes.h> +#include <winrt/Microsoft.UI.Dispatching.h> +#include "winrt/Microsoft.Storage.Pickers.h" +#include "winrt/Windows.Storage.Pickers.h" +#include "winrt/Windows.Storage.h" +#include <winrt/Microsoft.UI.Interop.h> +#include <winrt/Microsoft.UI.Windowing.h> +#include <winrt/Microsoft.UI.h> + +#include <wil/cppwinrt_helpers.h> 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 @@ +<Project/> \ No newline at end of file