From 34556bd7594bf6bd4c2e1493320b10588d049214 Mon Sep 17 00:00:00 2001 From: Xiang Hong Date: Fri, 6 Dec 2024 22:51:55 +0800 Subject: [PATCH 01/13] feature: add COM based picker prototype basic implementation --- prototype-workingdir/.gitignore | 0 prototype-workingdir/Directory.Build.props | 1 + prototype-workingdir/Directory.Packages.props | 1 + .../FileOpenPicker.cpp | 170 +++++++++++++++ .../FileOpenPicker.h | 44 ++++ .../FileSavePicker.cpp | 91 ++++++++ .../FileSavePicker.h | 44 ++++ .../FolderPicker.cpp | 119 +++++++++++ .../Microsoft.Storage.Pickers/FolderPicker.h | 40 ++++ .../Microsoft.Storage.Pickers.vcxproj | 156 ++++++++++++++ .../Microsoft.Storage.Pickers.vcxproj.filters | 40 ++++ .../Microsoft_Storage_Pickers.def | 3 + .../PickerCommon.cpp | 138 ++++++++++++ .../Microsoft.Storage.Pickers/PickerCommon.h | 19 ++ .../Microsoft.Storage.Pickers/Pickers.idl | 68 ++++++ .../Microsoft.Storage.Pickers/packages.config | 8 + .../Microsoft.Storage.Pickers/pch.cpp | 1 + .../Microsoft.Storage.Pickers/pch.h | 29 +++ .../Microsoft.Storage.Pickers/readme.txt | 27 +++ prototype-workingdir/NuGet.config | 17 ++ prototype-workingdir/PickerUsageApp/App.xaml | 16 ++ .../PickerUsageApp/App.xaml.cpp | 43 ++++ .../PickerUsageApp/App.xaml.h | 16 ++ .../Assets/LockScreenLogo.scale-200.png | Bin 0 -> 432 bytes .../Assets/SplashScreen.scale-200.png | Bin 0 -> 5372 bytes .../Assets/Square150x150Logo.scale-200.png | Bin 0 -> 1755 bytes .../Assets/Square44x44Logo.scale-200.png | Bin 0 -> 637 bytes ...x44Logo.targetsize-24_altform-unplated.png | Bin 0 -> 283 bytes .../PickerUsageApp/Assets/StoreLogo.png | Bin 0 -> 456 bytes .../Assets/Wide310x150Logo.scale-200.png | Bin 0 -> 2097 bytes .../PickerUsageApp/MainWindow.idl | 8 + .../PickerUsageApp/MainWindow.xaml | 56 +++++ .../PickerUsageApp/MainWindow.xaml.cpp | 186 ++++++++++++++++ .../PickerUsageApp/MainWindow.xaml.h | 93 ++++++++ .../PickerUsageApp/Package.appxmanifest | 51 +++++ .../PickerUsageApp/PickerUsageApp.vcxproj | 199 ++++++++++++++++++ .../PickerUsageApp.vcxproj.filters | 59 ++++++ .../PickerUsageApp/app.manifest | 19 ++ .../PickerUsageApp/packages.config | 8 + prototype-workingdir/PickerUsageApp/pch.cpp | 2 + prototype-workingdir/PickerUsageApp/pch.h | 32 +++ .../PickerUsageApp/readme.txt | 27 +++ prototype-workingdir/PickersPrototype.sln | 57 +++++ prototype-workingdir/environment.props | 1 + 44 files changed, 1889 insertions(+) create mode 100644 prototype-workingdir/.gitignore create mode 100644 prototype-workingdir/Directory.Build.props create mode 100644 prototype-workingdir/Directory.Packages.props create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.h create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj.filters create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/Microsoft_Storage_Pickers.def create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/Pickers.idl create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/packages.config create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/pch.cpp create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/pch.h create mode 100644 prototype-workingdir/Microsoft.Storage.Pickers/readme.txt create mode 100644 prototype-workingdir/NuGet.config create mode 100644 prototype-workingdir/PickerUsageApp/App.xaml create mode 100644 prototype-workingdir/PickerUsageApp/App.xaml.cpp create mode 100644 prototype-workingdir/PickerUsageApp/App.xaml.h create mode 100644 prototype-workingdir/PickerUsageApp/Assets/LockScreenLogo.scale-200.png create mode 100644 prototype-workingdir/PickerUsageApp/Assets/SplashScreen.scale-200.png create mode 100644 prototype-workingdir/PickerUsageApp/Assets/Square150x150Logo.scale-200.png create mode 100644 prototype-workingdir/PickerUsageApp/Assets/Square44x44Logo.scale-200.png create mode 100644 prototype-workingdir/PickerUsageApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png create mode 100644 prototype-workingdir/PickerUsageApp/Assets/StoreLogo.png create mode 100644 prototype-workingdir/PickerUsageApp/Assets/Wide310x150Logo.scale-200.png create mode 100644 prototype-workingdir/PickerUsageApp/MainWindow.idl create mode 100644 prototype-workingdir/PickerUsageApp/MainWindow.xaml create mode 100644 prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp create mode 100644 prototype-workingdir/PickerUsageApp/MainWindow.xaml.h create mode 100644 prototype-workingdir/PickerUsageApp/Package.appxmanifest create mode 100644 prototype-workingdir/PickerUsageApp/PickerUsageApp.vcxproj create mode 100644 prototype-workingdir/PickerUsageApp/PickerUsageApp.vcxproj.filters create mode 100644 prototype-workingdir/PickerUsageApp/app.manifest create mode 100644 prototype-workingdir/PickerUsageApp/packages.config create mode 100644 prototype-workingdir/PickerUsageApp/pch.cpp create mode 100644 prototype-workingdir/PickerUsageApp/pch.h create mode 100644 prototype-workingdir/PickerUsageApp/readme.txt create mode 100644 prototype-workingdir/PickersPrototype.sln create mode 100644 prototype-workingdir/environment.props diff --git a/prototype-workingdir/.gitignore b/prototype-workingdir/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prototype-workingdir/Directory.Build.props b/prototype-workingdir/Directory.Build.props new file mode 100644 index 0000000000..6dc4195c32 --- /dev/null +++ b/prototype-workingdir/Directory.Build.props @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/prototype-workingdir/Directory.Packages.props b/prototype-workingdir/Directory.Packages.props new file mode 100644 index 0000000000..6dc4195c32 --- /dev/null +++ b/prototype-workingdir/Directory.Packages.props @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp new file mode 100644 index 0000000000..a423868fbb --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp @@ -0,0 +1,170 @@ +#include "pch.h" +#include "FileOpenPicker.h" +#include "FileOpenPicker.g.cpp" +#include +#include +#include +#include +#include "PickerCommon.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + FileOpenPicker::FileOpenPicker(winrt::Microsoft::UI::WindowId const& windowId) + : m_windowId(windowId) + { + } + + winrt::Microsoft::Storage::Pickers::PickerViewMode FileOpenPicker::ViewMode() + { + return m_ViewMode; + } + void FileOpenPicker::ViewMode(winrt::Microsoft::Storage::Pickers::PickerViewMode const& value) + { + m_ViewMode = value; + } + hstring FileOpenPicker::SettingsIdentifier() + { + return m_SettingsIdentifier; + } + void FileOpenPicker::SettingsIdentifier(hstring const& value) + { + m_SettingsIdentifier = value; + } + winrt::Microsoft::Storage::Pickers::PickerLocationId FileOpenPicker::SuggestedStartLocation() + { + return m_PickerLocationId; + } + void FileOpenPicker::SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value) + { + m_PickerLocationId = value; + } + winrt::hstring FileOpenPicker::CommitButtonText() + { + return m_commitButtonText; + } + void FileOpenPicker::CommitButtonText(winrt::hstring const& value) + { + m_commitButtonText = value; + } + winrt::Windows::Foundation::Collections::IVector FileOpenPicker::FileTypeFilter() + { + return m_fileTypeFilter; + } + + struct FileOpenPickerParameters { + winrt::hstring CommitButtonText; + winrt::hstring SettingsIdentifierId; + PickerLocationId PickerLocationId; + std::vector FileTypeFilterData{}; + std::vector FileTypeFilterPara{}; + HWND HWnd; + + void ConfigureDialog(winrt::com_ptr dialog) { + PickerCommon::ConfigureDialogCommon(dialog, CommitButtonText, SettingsIdentifierId, PickerLocationId); + check_hresult(dialog->SetFileTypes(FileTypeFilterPara.size(), FileTypeFilterPara.data())); + } + }; + + void FileOpenPicker::CaptureParameters(FileOpenPickerParameters& parameters) { + parameters.CommitButtonText = m_commitButtonText; + parameters.SettingsIdentifierId = m_SettingsIdentifier; + parameters.PickerLocationId = m_PickerLocationId; + for (size_t i = 0; i < m_fileTypeFilter.Size(); i++) + { + parameters.FileTypeFilterData.push_back(m_fileTypeFilter.GetAt(i)); + parameters.FileTypeFilterPara.push_back({ L"", parameters.FileTypeFilterData[i].c_str() }); + } + parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); + } + + winrt::Windows::Foundation::IAsyncOperation FileOpenPicker::PickSingleFileAsync() + { + FileOpenPickerParameters parameters{}; + + CaptureParameters(parameters); + + co_await winrt::resume_background(); + + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return nullptr; + } + + // TODO: should we initialize COM? + // wil::com_initialize_ex initializeCom{ COINIT_APARTMENTTHREADED }; + + auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL); + + parameters.ConfigureDialog(dialog); + + auto hr = dialog->Show(parameters.HWnd); + if (FAILED(hr) || cancellationToken()) + { + co_return nullptr; + } + + winrt::com_ptr shellItem{}; + check_hresult(dialog->GetResult(shellItem.put())); + + auto& file = co_await PickerCommon::CreateStorageFileFromShellItem(shellItem); + if (cancellationToken()) + { + co_return nullptr; + } + + co_return file; + } + + winrt::Windows::Foundation::IAsyncOperation> FileOpenPicker::PickMultipleFilesAsync() + { + FileOpenPickerParameters parameters{}; + + CaptureParameters(parameters); + + co_await winrt::resume_background(); + + winrt::Windows::Foundation::Collections::IVector results{ winrt::single_threaded_vector() }; + + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return results.GetView(); + } + + auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL); + + parameters.ConfigureDialog(dialog); + + auto pickerOptions = FOS_ALLOWMULTISELECT; + check_hresult(dialog->SetOptions(pickerOptions)); + + auto hr = dialog->Show(parameters.HWnd); + if (FAILED(hr) || cancellationToken()) + { + co_return results.GetView(); + } + + winrt::com_ptr shellItems{}; + check_hresult(dialog->GetResults(shellItems.put())); + + DWORD itemCount = 0; + check_hresult(shellItems->GetCount(&itemCount)); + + winrt::com_ptr shellItem{}; + for (auto 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..36fa417263 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.h @@ -0,0 +1,44 @@ +#pragma once +#include "FileOpenPicker.g.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + struct FileOpenPickerParameters; + + struct FileOpenPicker : FileOpenPickerT + { + FileOpenPicker(winrt::Microsoft::UI::WindowId const& windowId); + + winrt::Microsoft::Storage::Pickers::PickerViewMode ViewMode(); + void ViewMode(winrt::Microsoft::Storage::Pickers::PickerViewMode const& value); + hstring SettingsIdentifier(); + void SettingsIdentifier(hstring const& value); + winrt::Microsoft::Storage::Pickers::PickerLocationId SuggestedStartLocation(); + void SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value); + winrt::hstring CommitButtonText(); + void CommitButtonText(winrt::hstring const& value); + + winrt::Windows::Foundation::Collections::IVector FileTypeFilter(); + + winrt::Windows::Foundation::IAsyncOperation PickSingleFileAsync(); + winrt::Windows::Foundation::IAsyncOperation> PickMultipleFilesAsync(); + + private: + winrt::Microsoft::UI::WindowId m_windowId{}; + winrt::hstring m_SettingsIdentifier{}; + PickerLocationId m_PickerLocationId{ PickerLocationId::Unspecified }; + winrt::hstring m_commitButtonText{}; + + PickerViewMode m_ViewMode{ PickerViewMode::List }; + + winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ winrt::single_threaded_vector() }; + + void CaptureParameters(FileOpenPickerParameters& parameters); + }; +} +namespace winrt::Microsoft::Storage::Pickers::factory_implementation +{ + struct FileOpenPicker : FileOpenPickerT + { + }; +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp new file mode 100644 index 0000000000..302ca462bd --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp @@ -0,0 +1,91 @@ +#include "pch.h" +#include "FileSavePicker.h" +#include "FileSavePicker.g.cpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "PickerCommon.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + + FileSavePicker::FileSavePicker(winrt::Microsoft::UI::WindowId const& windowId) + : m_windowId(windowId) + { + } + hstring FileSavePicker::SettingsIdentifier() + { + return m_SettingsIdentifier; + } + void FileSavePicker::SettingsIdentifier(hstring const& value) + { + m_SettingsIdentifier = value; + } + winrt::Microsoft::Storage::Pickers::PickerLocationId FileSavePicker::SuggestedStartLocation() + { + return m_PickerLocationId; + } + void FileSavePicker::SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value) + { + m_PickerLocationId = value; + } + hstring FileSavePicker::CommitButtonText() + { + return m_commitButtonText; + } + void FileSavePicker::CommitButtonText(hstring const& value) + { + m_commitButtonText = value; + } + winrt::Windows::Foundation::Collections::IMap> FileSavePicker::FileTypeChoices() + { + return m_fileTypeChoices; + } + hstring FileSavePicker::DefaultFileExtension() + { + return m_defaultFileExtension; + } + void FileSavePicker::DefaultFileExtension(hstring const& value) + { + m_defaultFileExtension = value; + } + winrt::Windows::Storage::StorageFile FileSavePicker::SuggestedSaveFile() + { + return m_suggestedSaveFile; + } + void FileSavePicker::SuggestedSaveFile(winrt::Windows::Storage::StorageFile const& value) + { + m_suggestedSaveFile = value; + } + hstring FileSavePicker::SuggestedFileName() + { + return m_suggestedFileName; + } + void FileSavePicker::SuggestedFileName(hstring const& value) + { + m_suggestedFileName = value; + } + + struct FileOpenPickerParameters { + HWND HWnd; + winrt::hstring CommitButtonText; + winrt::hstring SettingsIdentifierId; + PickerLocationId PickerLocationId; + + void ConfigureDialog(winrt::com_ptr dialog) { + PickerCommon::ConfigureDialogCommon(dialog, CommitButtonText, SettingsIdentifierId, PickerLocationId); + } + }; + + winrt::Windows::Foundation::IAsyncOperation FileSavePicker::PickSaveFileAsync() + { + throw hresult_not_implemented(); + } +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h new file mode 100644 index 0000000000..b0ab42ddcd --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h @@ -0,0 +1,44 @@ +#pragma once +#include "FileSavePicker.g.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + struct FileSavePickerParameters; + + struct FileSavePicker : FileSavePickerT + { + FileSavePicker(winrt::Microsoft::UI::WindowId const& windowId); + hstring SettingsIdentifier(); + void SettingsIdentifier(hstring const& value); + winrt::Microsoft::Storage::Pickers::PickerLocationId SuggestedStartLocation(); + void SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value); + hstring CommitButtonText(); + void CommitButtonText(hstring const& value); + winrt::Windows::Foundation::Collections::IMap> FileTypeChoices(); + hstring DefaultFileExtension(); + void DefaultFileExtension(hstring const& value); + winrt::Windows::Storage::StorageFile SuggestedSaveFile(); + void SuggestedSaveFile(winrt::Windows::Storage::StorageFile const& value); + hstring SuggestedFileName(); + void SuggestedFileName(hstring const& value); + winrt::Windows::Foundation::IAsyncOperation PickSaveFileAsync(); + private: + winrt::Microsoft::UI::WindowId m_windowId{}; + + hstring m_SettingsIdentifier{}; + PickerLocationId m_PickerLocationId{ PickerLocationId::Unspecified }; + hstring m_commitButtonText{}; + hstring m_defaultFileExtension{}; + winrt::Windows::Storage::StorageFile m_suggestedSaveFile{ nullptr }; + hstring m_suggestedFileName{}; + winrt::Windows::Foundation::Collections::IMap> m_fileTypeChoices{ winrt::single_threaded_map>() }; + + void CaptureParameters(FileSavePickerParameters& parameters); + }; +} +namespace winrt::Microsoft::Storage::Pickers::factory_implementation +{ + struct FileSavePicker : FileSavePickerT + { + }; +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp new file mode 100644 index 0000000000..7827f53fc3 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp @@ -0,0 +1,119 @@ +#include "pch.h" +#include "FolderPicker.h" +#include "FolderPicker.g.cpp" +#include +#include +#include +#include "PickerCommon.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + FolderPicker::FolderPicker(winrt::Microsoft::UI::WindowId const& windowId) + : m_windowId(windowId) + { + } + winrt::Microsoft::Storage::Pickers::PickerViewMode FolderPicker::ViewMode() + { + return m_ViewMode; + } + void FolderPicker::ViewMode(winrt::Microsoft::Storage::Pickers::PickerViewMode const& value) + { + m_ViewMode = value; + } + hstring FolderPicker::SettingsIdentifier() + { + return m_SettingsIdentifier; + } + void FolderPicker::SettingsIdentifier(hstring const& value) + { + m_SettingsIdentifier = value; + } + winrt::Microsoft::Storage::Pickers::PickerLocationId FolderPicker::SuggestedStartLocation() + { + return m_PickerLocationId; + } + void FolderPicker::SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value) + { + m_PickerLocationId = value; + } + hstring FolderPicker::CommitButtonText() + { + return m_commitButtonText; + } + void FolderPicker::CommitButtonText(hstring const& value) + { + m_commitButtonText = value; + } + winrt::Windows::Foundation::Collections::IVector FolderPicker::FileTypeFilter() + { + return m_fileTypeFilter; + + } + + struct FolderPickerParameters { + winrt::hstring CommitButtonText; + winrt::hstring SettingsIdentifierId; + PickerLocationId PickerLocationId; + std::vector FileTypeFilterData{}; + std::vector FileTypeFilterPara{}; + HWND HWnd; + + void ConfigureDialog(winrt::com_ptr dialog) { + PickerCommon::ConfigureDialogCommon(dialog, CommitButtonText, SettingsIdentifierId, PickerLocationId); + check_hresult(dialog->SetFileTypes(FileTypeFilterPara.size(), FileTypeFilterPara.data())); + } + }; + + void FolderPicker::CaptureParameters(FolderPickerParameters& parameters) { + parameters.CommitButtonText = m_commitButtonText; + parameters.SettingsIdentifierId = m_SettingsIdentifier; + parameters.PickerLocationId = m_PickerLocationId; + for (size_t i = 0; i < m_fileTypeFilter.Size(); i++) + { + parameters.FileTypeFilterData.push_back(m_fileTypeFilter.GetAt(i)); + parameters.FileTypeFilterPara.push_back({ L"", parameters.FileTypeFilterData[i].c_str() }); + } + parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); + } + + + winrt::Windows::Foundation::IAsyncOperation FolderPicker::PickSingleFolderAsync() + { + FolderPickerParameters parameters{}; + + CaptureParameters(parameters); + + co_await winrt::resume_background(); + + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return nullptr; + } + + // TODO: should we initialize COM? + // wil::com_initialize_ex initializeCom{ COINIT_APARTMENTTHREADED }; + + auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL); + + parameters.ConfigureDialog(dialog); + dialog->SetOptions(FOS_PICKFOLDERS); + + auto hr = dialog->Show(parameters.HWnd); + if (FAILED(hr) || cancellationToken()) + { + co_return nullptr; + } + + winrt::com_ptr shellItem{}; + check_hresult(dialog->GetResult(shellItem.put())); + + auto& folder = co_await PickerCommon::CreateStorageFolderFromShellItem(shellItem); + if (cancellationToken()) + { + co_return nullptr; + } + + co_return folder; + } +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h new file mode 100644 index 0000000000..ffaae2105c --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h @@ -0,0 +1,40 @@ +#pragma once +#include "FolderPicker.g.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + struct FolderPickerParameters; + + struct FolderPicker : FolderPickerT + { + FolderPicker(winrt::Microsoft::UI::WindowId const& windowId); + winrt::Microsoft::Storage::Pickers::PickerViewMode ViewMode(); + void ViewMode(winrt::Microsoft::Storage::Pickers::PickerViewMode const& value); + hstring SettingsIdentifier(); + void SettingsIdentifier(hstring const& value); + winrt::Microsoft::Storage::Pickers::PickerLocationId SuggestedStartLocation(); + void SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value); + hstring CommitButtonText(); + void CommitButtonText(hstring const& value); + winrt::Windows::Foundation::Collections::IVector FileTypeFilter(); + winrt::Windows::Foundation::IAsyncOperation PickSingleFolderAsync(); + + private: + winrt::Microsoft::UI::WindowId m_windowId{}; + + PickerViewMode m_ViewMode{ PickerViewMode::List }; + hstring m_SettingsIdentifier{}; + PickerLocationId m_PickerLocationId{ PickerLocationId::Unspecified }; + hstring m_commitButtonText{}; + + winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ winrt::single_threaded_vector() }; + + void CaptureParameters(FolderPickerParameters& parameters); + }; +} +namespace winrt::Microsoft::Storage::Pickers::factory_implementation +{ + struct FolderPicker : FolderPickerT + { + }; +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj new file mode 100644 index 0000000000..f5d1f51ae8 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj @@ -0,0 +1,156 @@ + + + + + + + true + true + true + {349e64cf-cb0c-4202-b1b5-7f543cc6e886} + Microsoft.Storage.Pickers + Microsoft.Storage.Pickers + en-US + 16.0 + false + Windows Store + 10.0 + 10.0.22621.0 + 10.0.22000.0 + true + true + + + + + Debug + Win32 + + + Debug + x64 + + + Debug + ARM64 + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + DynamicLibrary + v143 + Unicode + false + true + + + true + true + + + false + true + false + + + + + + + + + + + + + + Use + pch.h + $(IntDir)pch.pch + Level4 + %(AdditionalOptions) /bigobj + _WINRT_DLL;%(PreprocessorDefinitions) + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + + + Console + true + Microsoft_Storage_Pickers.def + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + NDEBUG;%(PreprocessorDefinitions) + + + true + true + + + + + + + + + + + + + + + Create + + + + + + + + + + + false + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + \ No newline at end of file diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj.filters b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj.filters new file mode 100644 index 0000000000..71954b81d9 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj.filters @@ -0,0 +1,40 @@ + + + + + accd3aa8-1ba0-4223-9bbe-0c431709210b + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms + + + {926ab91d-31b4-48c3-b9a4-e681349f27f0} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft_Storage_Pickers.def b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft_Storage_Pickers.def new file mode 100644 index 0000000000..24e7c1235c --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft_Storage_Pickers.def @@ -0,0 +1,3 @@ +EXPORTS +DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE +DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp new file mode 100644 index 0000000000..f9d207621b --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp @@ -0,0 +1,138 @@ +#include "pch.h" +#include "PickerCommon.h" +#include +#include "ShObjIdl.h" +#include +#include "winrt/Microsoft.Storage.Pickers.h" +#include + +namespace { + bool IsHStringNullOrEmpty(winrt::hstring value) { + // TODO: proper handling of null string reference? + return value.empty(); + } + + // TODO: rewrite use WinRT APIs https://learn.microsoft.com/en-us/uwp/api/windows.security.cryptography.core.hashalgorithmprovider?view=winrt-26100 + GUID HashHStringToGuid(winrt::hstring const& input) + { + // Convert the hstring to bytes (UTF-16LE encoding) + const BYTE* data = reinterpret_cast(input.data()); + DWORD dataSize = static_cast(input.size() * sizeof(wchar_t)); + + // Acquire a cryptographic provider context + wil::unique_hcryptprov cryptProv; + THROW_IF_WIN32_BOOL_FALSE(CryptAcquireContextW(&cryptProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)); + + // Create an MD5 hash object + wil::unique_hcrypthash hash; + THROW_IF_WIN32_BOOL_FALSE(CryptCreateHash(cryptProv.get(), CALG_MD5, 0, 0, &hash)); + + // Hash the data + THROW_IF_WIN32_BOOL_FALSE(CryptHashData(hash.get(), data, dataSize, 0)); + + // Get the hash value + BYTE hashValue[16]; // MD5 hash is 16 bytes + DWORD hashSize = sizeof(hashValue); + THROW_IF_WIN32_BOOL_FALSE(CryptGetHashParam(hash.get(), HP_HASHVAL, hashValue, &hashSize, 0)); + + // Copy the hash into a GUID + GUID guid; + memcpy(&guid, hashValue, sizeof(GUID)); + + // TODO: Need to modify genreated bit patterns to fit GUID specification + // like need to specify some bits to make it a valid GUID (maybe v3 or v5) + return guid; + } + + // TODO: use better winrt implementations? + // Challenge: currently winrt based Storage.KnownFolder APIs does not provide all location id we need + winrt::com_ptr GetKnownFolderFromId(winrt::Microsoft::Storage::Pickers::PickerLocationId pickerLocationId) { + KNOWNFOLDERID knownFolderId; + switch (pickerLocationId) + { + case winrt::Microsoft::Storage::Pickers::PickerLocationId::DocumentsLibrary: + knownFolderId = FOLDERID_Documents; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::ComputerFolder: + knownFolderId = FOLDERID_ComputerFolder; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::Desktop: + knownFolderId = FOLDERID_Desktop; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::Downloads: + knownFolderId = FOLDERID_Downloads; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::HomeGroup: + knownFolderId = FOLDERID_HomeGroup; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::MusicLibrary: + knownFolderId = FOLDERID_MusicLibrary; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::PicturesLibrary: + knownFolderId = FOLDERID_PicturesLibrary; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::VideosLibrary: + knownFolderId = FOLDERID_VideosLibrary; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::Objects3D: + knownFolderId = FOLDERID_Objects3D; + break; + default: + return nullptr; + } + + auto knownFolderManager = winrt::create_instance(CLSID_KnownFolderManager); + winrt::com_ptr knownFolder; + winrt::check_hresult(knownFolderManager->GetFolder(knownFolderId, knownFolder.put())); + winrt::com_ptr defaultFolder; + winrt::check_hresult(knownFolder->GetShellItem(0, IID_PPV_ARGS(defaultFolder.put()))); + return defaultFolder; + } +} + + +namespace PickerCommon { + + using namespace winrt; + + void ConfigureDialogCommon( + winrt::com_ptr dialog, + winrt::hstring commitButtonText, + winrt::hstring settingIdentifierId, + winrt::Microsoft::Storage::Pickers::PickerLocationId pickerLocationId + ) { + if (!IsHStringNullOrEmpty(commitButtonText)) + { + check_hresult(dialog->SetOkButtonLabel(commitButtonText.c_str())); + } + + if (!IsHStringNullOrEmpty(settingIdentifierId)) { + auto guid = HashHStringToGuid(settingIdentifierId); + check_hresult(dialog->SetClientGuid(guid)); + } + + + auto defaultFolder = GetKnownFolderFromId(pickerLocationId); + if (defaultFolder != nullptr) { + check_hresult(dialog->SetFolder(defaultFolder.get())); + check_hresult(dialog->SetDefaultFolder(defaultFolder.get())); + } + } + + // TODO: better way to convert ShellItem a StorageFile without relying on path?. + winrt::Windows::Foundation::IAsyncOperation CreateStorageFileFromShellItem(winrt::com_ptr shellItem) + { + wil::unique_cotaskmem_string filePath; + check_hresult(shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath)); + auto& result = co_await winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(filePath.get()); + co_return result; + } + + winrt::Windows::Foundation::IAsyncOperation CreateStorageFolderFromShellItem(winrt::com_ptr shellItem) + { + wil::unique_cotaskmem_string filePath; + check_hresult(shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath)); + auto& result = co_await winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(filePath.get()); + co_return result; + } +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h new file mode 100644 index 0000000000..f7c4443d31 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h @@ -0,0 +1,19 @@ +// TODO: use better namespace, maybe anonymous namespace? +#pragma once +#include "pch.h" +#include "ShObjIdl.h" +#include "winrt/Microsoft.Storage.Pickers.h" + +#pragma once + +namespace PickerCommon { + void ConfigureDialogCommon( + winrt::com_ptr dialog, + winrt::hstring commitButtonText, + winrt::hstring settingIdentifierId, + winrt::Microsoft::Storage::Pickers::PickerLocationId pickerLocationId + ); + + winrt::Windows::Foundation::IAsyncOperation CreateStorageFileFromShellItem(winrt::com_ptr shellItem); + winrt::Windows::Foundation::IAsyncOperation CreateStorageFolderFromShellItem(winrt::com_ptr shellItem); +} \ No newline at end of file diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/Pickers.idl b/prototype-workingdir/Microsoft.Storage.Pickers/Pickers.idl new file mode 100644 index 0000000000..31c4c6c7ea --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/Pickers.idl @@ -0,0 +1,68 @@ +namespace Microsoft.Storage.Pickers +{ + enum PickerViewMode + { + List, + Thumbnail, + }; + + enum PickerLocationId + { + DocumentsLibrary, + ComputerFolder, + Desktop, + Downloads, + HomeGroup, + MusicLibrary, + PicturesLibrary, + VideosLibrary, + Objects3D, + Unspecified, + }; + + + [default_interface] + runtimeclass FileOpenPicker + { + FileOpenPicker(Microsoft.UI.WindowId windowId); + + Microsoft.Storage.Pickers.PickerViewMode ViewMode; + String SettingsIdentifier; + Microsoft.Storage.Pickers.PickerLocationId SuggestedStartLocation; + String CommitButtonText; + Windows.Foundation.Collections.IVector FileTypeFilter{ get; }; + + [remote_sync] Windows.Foundation.IAsyncOperation PickSingleFileAsync(); + [remote_sync] Windows.Foundation.IAsyncOperation > PickMultipleFilesAsync(); + } + + [default_interface] + runtimeclass FileSavePicker + { + FileSavePicker(Microsoft.UI.WindowId windowId); + + String SettingsIdentifier; + Microsoft.Storage.Pickers.PickerLocationId SuggestedStartLocation; + String CommitButtonText; + Windows.Foundation.Collections.IMap > FileTypeChoices{ get; }; + String DefaultFileExtension; + Windows.Storage.StorageFile SuggestedSaveFile; + String SuggestedFileName; + + [remote_sync] Windows.Foundation.IAsyncOperation PickSaveFileAsync(); + } + + [default_interface] + runtimeclass FolderPicker + { + FolderPicker(Microsoft.UI.WindowId windowId); + + Microsoft.Storage.Pickers.PickerViewMode ViewMode; + String SettingsIdentifier; + Microsoft.Storage.Pickers.PickerLocationId SuggestedStartLocation; + String CommitButtonText; + Windows.Foundation.Collections.IVector FileTypeFilter{ get; }; + + [remote_sync] Windows.Foundation.IAsyncOperation PickSingleFolderAsync(); + } +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/packages.config b/prototype-workingdir/Microsoft.Storage.Pickers/packages.config new file mode 100644 index 0000000000..6e553cc88c --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/pch.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/pch.cpp new file mode 100644 index 0000000000..1d9f38c57d --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/pch.h b/prototype-workingdir/Microsoft.Storage.Pickers/pch.h new file mode 100644 index 0000000000..a70ce5f978 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/pch.h @@ -0,0 +1,29 @@ +#pragma once +#include +#include +#include +#include + +// Undefine GetCurrentTime macro to prevent +// conflict with Storyboard::GetCurrentTime +#undef GetCurrentTime + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/readme.txt b/prototype-workingdir/Microsoft.Storage.Pickers/readme.txt new file mode 100644 index 0000000000..6b46510cd0 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/readme.txt @@ -0,0 +1,27 @@ +======================================================================== + Microsoft.Storage.Pickers Project Overview +======================================================================== + +This project demonstrates how to get started authoring Windows Runtime +classes directly with standard C++, using the Windows App SDK and +C++/WinRT packages to generate implementation headers from interface +(IDL) files. The generated Windows Runtime component binary and WinMD +files should then be bundled with the app consuming them. + +Steps: +1. Create an interface (IDL) file to define your Windows Runtime class, + its default interface, and any other interfaces it implements. +2. Build the project once to generate module.g.cpp, module.h.cpp, and + implementation templates under the "Generated Files" folder, as + well as skeleton class definitions under "Generated Files\sources". +3. Use the skeleton class definitions for reference to implement your + Windows Runtime classes. + +======================================================================== +Learn more about Windows App SDK here: +https://docs.microsoft.com/windows/apps/windows-app-sdk/ +Learn more about WinUI3 here: +https://docs.microsoft.com/windows/apps/winui/winui3/ +Learn more about C++/WinRT here: +http://aka.ms/cppwinrt/ +======================================================================== diff --git a/prototype-workingdir/NuGet.config b/prototype-workingdir/NuGet.config new file mode 100644 index 0000000000..8e8d51bd44 --- /dev/null +++ b/prototype-workingdir/NuGet.config @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/prototype-workingdir/PickerUsageApp/App.xaml b/prototype-workingdir/PickerUsageApp/App.xaml new file mode 100644 index 0000000000..01e1e1c35d --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/App.xaml @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/prototype-workingdir/PickerUsageApp/App.xaml.cpp b/prototype-workingdir/PickerUsageApp/App.xaml.cpp new file mode 100644 index 0000000000..fb607703e2 --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/App.xaml.cpp @@ -0,0 +1,43 @@ +#include "pch.h" +#include "App.xaml.h" +#include "MainWindow.xaml.h" + +using namespace winrt; +using namespace Microsoft::UI::Xaml; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace winrt::PickerUsageApp::implementation +{ + /// + /// Initializes the singleton application object. This is the first line of authored code + /// executed, and as such is the logical equivalent of main() or WinMain(). + /// + App::App() + { + // Xaml objects should not call InitializeComponent during construction. + // See https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent + +#if defined _DEBUG && !defined DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION + UnhandledException([](IInspectable const&, UnhandledExceptionEventArgs const& e) + { + if (IsDebuggerPresent()) + { + auto errorMessage = e.Message(); + __debugbreak(); + } + }); +#endif + } + + /// + /// Invoked when the application is launched. + /// + /// Details about the launch request and process. + void App::OnLaunched([[maybe_unused]] LaunchActivatedEventArgs const& e) + { + window = make(); + window.Activate(); + } +} diff --git a/prototype-workingdir/PickerUsageApp/App.xaml.h b/prototype-workingdir/PickerUsageApp/App.xaml.h new file mode 100644 index 0000000000..fb5f632552 --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/App.xaml.h @@ -0,0 +1,16 @@ +#pragma once + +#include "App.xaml.g.h" + +namespace winrt::PickerUsageApp::implementation +{ + struct App : AppT + { + App(); + + void OnLaunched(Microsoft::UI::Xaml::LaunchActivatedEventArgs const&); + + private: + winrt::Microsoft::UI::Xaml::Window window{ nullptr }; + }; +} diff --git a/prototype-workingdir/PickerUsageApp/Assets/LockScreenLogo.scale-200.png b/prototype-workingdir/PickerUsageApp/Assets/LockScreenLogo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..7440f0d4bf7c7e26e4e36328738c68e624ee851e GIT binary patch literal 432 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezr3(FqV6|IEGZ*x-#9g>~Mkr+x6^F zy~CDX2QIMs&Gcs3RnRBoxBA!*(Mfw0KTCYuYk0WlEIV>qBmPl! zq4ukrvfADX@#p8fbLY(H47N+k`FZ(FZh?cDro7>{8mkBO3>^oaIx`3!Jl)Qq)HI!+ z(S=1{o~eT)&W^=Ea8C`-17(Jv5(nHFJ{dOjGdxLVkY_y6&S1whfuFI4MM0kF0f&cO zPDVpV%nz;Id$>+0Ga5e9625-JcI)oq=#Pa3p^>8BB}21BUw@eN!-6@w%X+^`+Vn?! zryu|3T>kVWNBYyBc=7Y6H#s1Ah!OI_nezW zXTqOdkv2Az6KKBV=$yHdF^R3Fqw(TZEoNSZX>reXJ#bwX42%f|Pgg&ebxsLQ010xn AssI20 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..32f486a86792a5e34cd9a8261b394c49b48f86be GIT binary patch literal 5372 zcmd5=Z){Ul6u)iv53sCbIJKLzl(EF%0tzcEY@|pLrfgF~2Dk$KFtU+$kbYqDN5W%7 z>?DBo!@y06eh{Oux>brrNT^{MO(tkiC@nH(2}}G_1|uvcMD(0{?|W^Gxo!tG~hW2Rn&7%b`-Kd_^`BCrb>XVtRKONoEw6%NswzMxk+kbocuk&}kJ#hSP z>8uR{r%LJ?I#)aaWW;uEixz+DzyTpp)MTEo&R%nEA92~g{^eXQwKV1m{xl5K<@k3FacT+Z zrwfy=VocIptI>t%@p5a;Rt=WXVnU;2SUdr7Yk>gw_2z_ICK^23$|Cg7{3Eg5j@N*F zetT?>30(*S_7ld-Yt&u7T{(hEjjM#vPlXibjrq?;pBBx3*>_2~VFGdsH5L zQKme_LAebV}aOX#+rQafZtp+4jK}V!>pn1?+eUH$0%6}z(Kul9!^2z zXi+d@jnx)RW7!j9uFEdv5N&1sCW#Z6Ej5Y7c;o28Q7i%U0(2v5J>o9P zl$#C8&9r)nL;?J65^GIeSOHYr3B7}}R~}@2Tx_xo5*YdU#g1bO}95cq69J!efdlE+xj1qG#ZUqh~1Sn#dBsZfDvcupM zXOFoyJ0$s+RHQKpzr#T>c&EUbq)lGvZDxuI!9unMI=#;ob2&gT)WqOjt6^X`_N21r`&eh6h0xpT!n6Z9rvE&+bFU$vTJO2? z#^tBNOx*2N)~(+TH8d>ep6``8V=3JEfdUUahVZ-xN+k#V&32x|%qnX(XBii5<@`%^ zV#Ky4f1!6RJqJXBU3M4~tmj2;;r`8_j&w?h5g35uMH(QI$Xpesb zG|*XRT?kh6M(jj0Y&vF^M*9g-iDMW%G%9%Pa}6ERQ9b0%6z1v}Ja=|L@G#5ZI>JS9 z*(K12nMvS?oyG8s9|q~{w`ajtI`KSHSiJ;)%X@M&eCE(VqI#F(XL?L@A$TUT?6av5 zkPWIR391XjSC%d6L}7F71Qpw(;c_~)mSZo-&Fm^FHlPX|Fu}1B3E+9j0}o1a(4HFS zUItE22CC%XZi!b4%~vWn>rpV9&CUEvt!?Q{Pr*L~51&(0Sz{VJJFrJtWw2PwXd|J{ zgH%3vAY$flodH=4&ruCHX;(3t;o}n?!0~3EE|5qRz$!VIkphxa4@_jyfiE9m;0 zjcYJ2;26N&MTB8X4joZ&?SUe|VS$^I%dt{!c2O;%3SdqW@K_14r8eyC1s&VcU5+2~ z_O1Cc*w|aIA=VC6AT_EFoL}W#Rl;7CZe)e}RS*e;8CVyM6i8a(yO@|S709VYY(y2g zc+QxB>Bw^B^2Db~*o)=i$m-aUNQFkYy5(eJW$cez>C{POds*p3cy#tHnvActP;dBP zdEf)C;lq}&#PE?XCD<~ngrzYUg|nS`#MS`Rd7cT>xlR19P#~4Qg5!J}@glCUq)z_2 zjvyv%aSq0 z)njao1dV0XNw&c@qmj1e*jgQ$l@_urW5G4RSY#rT1z`#%3;{EB`aJK|TH^lb_3nAT z-_Q4X-(K&IS8UyqsnjYdippfmN-HT!X2MT;Dpcy~-#$k6V z|MR4vU#O&p7TC46pTflb3 zoUJ;ZRf#&8&EwXy5s%!&(q6cN62swD#FH%O-RJsjWPZN3^^@FCIQ&MxXIFo7!I#VI zkpIstuWqUV5uhgs07?k$*!`uiZ=5b#$lI|0c+XJvj(}zSE3MN#EyOK zql(#yA}~Ibl*r(s1}Z^5mmn*-n93g?-ccM+^PN?6HH~h0hjy6@XY*^i<-V)+OZ;p7 z7j`p_sT55xnYsedNIIel^QIIg7i@`2Qi}x5$!tk29$2OQI zs^kQXAKE}5ZJu$)2@Dxn?}}O@f@6@^!%9Tj+o>=jd!^ZuvBE4jb4g}Z5WMBtcmy^~ zoFGVS5|0FA!(1Q%fL?Bj*L+9ZL{mjSO8lzqrQ0UCZ)X zPwk$1HNFgaK%NxGpuXz}#ywXvf2JQ?BQ5uOZM2up4S#ieaxS$!o9o6Z=czNQb} zwAh|xLZ>+WyN%o?^uCAQw&&4o?S$DJ`WP(Hr*grL*qNXlqU0osCQ(Up5F(^$Z5;n&oJIO4uF`k&QL*j{f zU=;#MZ5{@b%qMbjTB3dh-5#mqY>%{0jgS+WdHyG literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f713bba67f551ef91020b75716a4dc8ebd744b1c GIT binary patch literal 637 zcmeAS@N?(olHy`uVBq!ia0vp^5g^RL1|$oo8kjIJFu8cTIEGZ*dUI*J;2{SImxtDO zm%3!R$UazoY}x{$j0P5ABYXWr(l=jxJ6ps1W{tV=^>{Dl><3nv3A}sm=EZ)#l3`NR zpZda3^rNox*D1%NC98Z~L*6zipLw~Gxn&(Y-;KmJ+aR6eLabU-L#y8HW%7P-E_-VlLqIabbHPHKT*)fT@9iWJ7iWgOT9%0}Lrj>lztPxWq6sPw3pi z#-<=#$jjrP_DD*i!RLsn0mIA=>4~N)IMYWIf=j%-zuKCdMG%tHYot70D1| zvWa0wMhauW#S>1CnI_;>!1Q3zMA17@DOVq{MQ+{U7^a&yA+%dMCG;WNPV0i;w$tu; zX^b}UKziPM)(<;)ruW;-`)bBN+rQNM*Zs_>?n$|FVFo-e*PZb*@U7VAd+tHb4e?=Blc~}S6K)wL}r*Gf`BM#QB z+y>N$mCswb4d{^{S9v_!eQj4fTRMOwOCi?lSk9%<=vAz}jM-*PQtH@Odn1LZcd^j#o> hW$4xn+CT+ep9lJ{OAO?njobhL002ovPDHLkV1nYebbkN< literal 0 HcmV?d00001 diff --git a/prototype-workingdir/PickerUsageApp/Assets/StoreLogo.png b/prototype-workingdir/PickerUsageApp/Assets/StoreLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..a4586f26bdf7841cad10f39cdffe2aca3af252c1 GIT binary patch literal 456 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2o;fF!p=8IEGZ*dUM0H=rDtTTVkd2 z(%lbKn@VS_lUaADVB&;Z6F#LM+mPsa?e>FnHo;HND^!P`-lX%BH~FOg%y&x+t*x!? zg$#_1A1kgsSvO(fw`bOmo;lrJX8byO1j^gf7qohR%mmt z@L)WX;>gqgK|tWJvQ5j;4;=gt4HXVKSMYRv5RhY5vS~TqfK_NAP*r{h!!g^BZ;w4r z7CGdsai)y;fJQc`7{Zc2b==h%o`Op$|bg6a&nL{*m7-=0>k4M4-PXlU;G-?%*(*g>iFt^ U$m#7DfHB12>FVdQ&MBb@0G`#n8vpc0sq%A~kJcD9FY~qQRMt?ZR3YyDZt}Od;|mgpc{2dv9AHF){kXU%k({ z=Y8JidEayHTkG@twPZ|U3_^%3ct-OgLSiFAqDN!|tbCX@c@?4P`2x*TMK!+Q4b?k0 ziW7!!KF6dPWcF<%I|iznM~`QJ_V7sHGV_D`dhgpA9Vd@&X}ErK+j~_rdv;Bp?OA@a zFXOk7eWOJe5NcK;6h$FaM&7JxNc#-@QTwzW6x#d_zmQNkz5) zPI;kh;3d;5UCJU+9a(cOxX(|edWoOiAEdGU#kPJ&xnc2||3vDbuhBCkj-pb0as$Zl z5;}4n=**n6(1g`JEtSy;SG6X;#-F~Oz3lESG2b5`j@wAwY4Yp<=4Xeb>iH=6aicF?DxD&q{`!&}ct zBI)aycwuobQAf&678Uf+Mmh-@9RUhyH~>?w0dixO0#jZjEc9R^=5NZw=|a(kcB?9^ zfnTiEFXp-q#B;Tn>(O%$A*ud^Rg&eVH6Y_5Y%!E39RR&s?XpG`gKwU!6FE1 z7X)DC7)*(5g}lh`4`{i~DZcWupZI`K)_4P)VE{@gc7@Xsd^86zl~_mOYH?I4!aGeX z^E(_=L6?PgveDQ+r%P@UISEXrkn`LHJZ##+!-anV>6h)IkKp;E@p8+3&(5%kS2)ld*J*rJccZM0iyaAx7+F~GW1UWFK&3X$PE1^}NH zgAG9ck5K!{07OwU@j@Do>TbH=CDEo#4m0cEyAuXy_<&jlzJVcKweSJ5 z&=q~iIn18$w8yb=rmEmHxVEUA^?RwnB?6Qlp1os8@*dWTGL2bhzZ!s*xqScR?EPL` zo(JwNdKUUYy7GtvZ3asXm)cgFvCx9EmAi;|w=a0iGiv%%VYKh`P0Wma4y`Xyx|T~( zAmfGbgbEEC7)j8b@WA@+5W3a61HJXC1dX@6_T|Czk0I0zBk%tnW~()VWITGI!`$c< gARL?UBrYYkwoDw4eo*CrzXGTrZ@;GF>596)00d&n@&Et; literal 0 HcmV?d00001 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..1318f71657 --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml @@ -0,0 +1,56 @@ + + + + + Multi Selection + + + + CommitButtonText + Enable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp new file mode 100644 index 0000000000..5ca511bf8f --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp @@ -0,0 +1,186 @@ +#include "pch.h" +#include "MainWindow.xaml.h" +#if __has_include("MainWindow.g.cpp") +#include "MainWindow.g.cpp" +#endif +#include +#include +#include +#include + +using namespace winrt; +using namespace Microsoft::UI::Xaml; +//using namespace Windows::Foundation; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + + + +namespace winrt::PickerUsageApp::implementation +{ + + Windows::Storage::Pickers::PickerViewMode Convert(Microsoft::Storage::Pickers::PickerViewMode viewMode) { + switch (viewMode) + { + case winrt::Microsoft::Storage::Pickers::PickerViewMode::List: + return Windows::Storage::Pickers::PickerViewMode::List; + case winrt::Microsoft::Storage::Pickers::PickerViewMode::Thumbnail: + return Windows::Storage::Pickers::PickerViewMode::Thumbnail; + default: + return Windows::Storage::Pickers::PickerViewMode::List; + } + } + + Windows::Foundation::IAsyncAction MainWindow::OpenFileUWPClick(IInspectable const&, RoutedEventArgs const&) + { + hstring error_mesasge{}; + try { + labelBlock().Text(L""); + auto windowNative = this->m_inner.as(); + HWND hWnd = nullptr; + check_hresult(windowNative->get_WindowHandle(&hWnd)); + + winrt::Windows::Storage::Pickers::FileOpenPicker picker{}; + + picker.as<::IInitializeWithWindow>()->Initialize(hWnd); + SetPickerOptions(picker); + //SetPickerOptions(picker); + picker.ViewMode(Convert(m_ViewMode)); + + if (!m_MultipleSelect) { + auto& file = co_await picker.PickSingleFileAsync(); + if (file != nullptr) { + labelBlock().Text(file.Path()); + } + } + else { + auto& files = co_await picker.PickMultipleFilesAsync(); + winrt::hstring names = L""; + for (auto& file : files) + { + names = names + file.Path() + L"\n"; + } + labelBlock().Text(names); + } + + co_return; + } + catch (winrt::hresult_error const& ex_) + { + error_mesasge = ex_.message(); + } + if (!error_mesasge.empty()) + { + winrt::Windows::UI::Popups::MessageDialog dialog(error_mesasge); + co_await dialog.ShowAsync(); + } + } + + Windows::Foundation::IAsyncAction MainWindow::OpenFileSDKClick(IInspectable const&, RoutedEventArgs const&) + { + hstring error_mesasge{}; + try { + labelBlock().Text(L""); + auto id = AppWindow().Id(); + winrt::Microsoft::Storage::Pickers::FileOpenPicker picker{ id }; + + SetPickerOptions(picker); + //SetPickerOptions(picker); + picker.ViewMode(m_ViewMode); + if (!m_MultipleSelect) { + auto& file = co_await picker.PickSingleFileAsync(); + if (file != nullptr) { + labelBlock().Text(file.Path()); + } + } + else { + auto& files = co_await picker.PickMultipleFilesAsync(); + winrt::hstring names = L""; + for (auto& file : files) + { + names = names + file.Path() + L"\n"; + } + labelBlock().Text(names); + } + co_return; + } + catch (winrt::hresult_error const& ex_) + { + error_mesasge = ex_.message(); + } + if (!error_mesasge.empty()) + { + winrt::Windows::UI::Popups::MessageDialog dialog(error_mesasge); + co_await dialog.ShowAsync(); + } + } +} + + +void winrt::PickerUsageApp::implementation::MainWindow::UIFronzenTestClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) +{ + counterBlock().Text(std::to_wstring(count)); + count++; +} + + +void winrt::PickerUsageApp::implementation::MainWindow::toggleCustomLableClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) +{ + m_isUseCustomLabel = !m_isUseCustomLabel; + if (m_isUseCustomLabel) + { + useCustomLabelToggle().Content(box_value(L"Disable")); + customLabelBox().Visibility(Visibility::Visible); + } + else + { + useCustomLabelToggle().Content(box_value(L"Enable")); + customLabelBox().Visibility(Visibility::Collapsed); + } +} + + +void winrt::PickerUsageApp::implementation::MainWindow::ViewModeSelectionChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e) +{ + auto radioButtons = sender.as(); + auto selectedIndex = radioButtons.SelectedIndex(); + switch (selectedIndex) + { + case 0: + m_ViewMode = Microsoft::Storage::Pickers::PickerViewMode::List; + break; + case 1: + m_ViewMode = Microsoft::Storage::Pickers::PickerViewMode::Thumbnail; + break; + default: + break; + } +} + + +void winrt::PickerUsageApp::implementation::MainWindow::FilterTypeSelectionChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e) +{ + auto radioButtons = sender.as(); + + m_FilterTypeIndex = radioButtons.SelectedIndex(); +} + + +void winrt::PickerUsageApp::implementation::MainWindow::SettingsIdentifierChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e) +{ + auto radioButtons = sender.as(); + m_SettingsIdentifierIndex = radioButtons.SelectedIndex(); +} + +void winrt::PickerUsageApp::implementation::MainWindow::PickerLocationIdChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e) +{ + auto radioButtons = sender.as(); + m_PickerLocationIdIndex = radioButtons.SelectedIndex(); +} + + +void winrt::PickerUsageApp::implementation::MainWindow::MultiSelectToggled(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) +{ + m_MultipleSelect = sender.as().IsOn(); +} diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h new file mode 100644 index 0000000000..f3c1321111 --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h @@ -0,0 +1,93 @@ +#pragma once + +#include "MainWindow.g.h" +#include + +namespace winrt::PickerUsageApp::implementation +{ + struct MainWindow : MainWindowT + { + int count{ 0 }; + + MainWindow() + { + // Xaml objects should not call InitializeComponent during construction. + // See https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent + } + + winrt::Windows::Foundation::IAsyncAction OpenFileSDKClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); + winrt::Windows::Foundation::IAsyncAction OpenFileUWPClick(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); + 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 }; + bool m_MultipleSelect{ false }; + + + // using this template approach helps us ensure use same logic on compatible user facing API + template void SetPickerOptions(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_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; + } + switch (m_PickerLocationIdIndex) + { + case 1: + picker.SuggestedStartLocation(TPickerLocationId::DocumentsLibrary); + break; + case 2: + picker.SuggestedStartLocation(TPickerLocationId::Desktop); + break; + default: + break; + } + + + } + + }; +} + +namespace winrt::PickerUsageApp::factory_implementation +{ + struct MainWindow : MainWindowT + { + }; +} diff --git a/prototype-workingdir/PickerUsageApp/Package.appxmanifest b/prototype-workingdir/PickerUsageApp/Package.appxmanifest new file mode 100644 index 0000000000..a9df97a30d --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/Package.appxmanifest @@ -0,0 +1,51 @@ + + + + + + + + + + PickerUsageApp + xianghong + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/prototype-workingdir/PickerUsageApp/PickerUsageApp.vcxproj b/prototype-workingdir/PickerUsageApp/PickerUsageApp.vcxproj new file mode 100644 index 0000000000..705335bb5e --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/PickerUsageApp.vcxproj @@ -0,0 +1,199 @@ + + + + + + + true + true + true + {c0c88f67-8c6c-49f8-827e-86c0e1669f09} + PickerUsageApp + PickerUsageApp + + $(RootNamespace) + en-US + 16.0 + false + true + Windows Store + 10.0 + 10.0 + 10.0.17763.0 + true + true + + + + + Debug + Win32 + + + Debug + x64 + + + Debug + ARM64 + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + Application + v143 + Unicode + true + + + true + true + + + false + true + false + + + + + + + + + + + Use + pch.h + $(IntDir)pch.pch + Level4 + %(AdditionalOptions) /bigobj + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + NDEBUG;%(PreprocessorDefinitions) + + + true + true + + + + + Designer + + + + + + + + + App.xaml + + + MainWindow.xaml + + + + + + + + + Create + + + App.xaml + + + MainWindow.xaml + + + + + + Code + MainWindow.xaml + + + + + false + + + + + + + + + + + + + + + + + + + + + {349e64cf-cb0c-4202-b1b5-7f543cc6e886} + + + + + true + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + \ No newline at end of file diff --git a/prototype-workingdir/PickerUsageApp/PickerUsageApp.vcxproj.filters b/prototype-workingdir/PickerUsageApp/PickerUsageApp.vcxproj.filters new file mode 100644 index 0000000000..897732b290 --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/PickerUsageApp.vcxproj.filters @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + + + {c0c88f67-8c6c-49f8-827e-86c0e1669f09} + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/prototype-workingdir/PickerUsageApp/app.manifest b/prototype-workingdir/PickerUsageApp/app.manifest new file mode 100644 index 0000000000..978e572078 --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/app.manifest @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + PerMonitorV2 + + + \ No newline at end of file diff --git a/prototype-workingdir/PickerUsageApp/packages.config b/prototype-workingdir/PickerUsageApp/packages.config new file mode 100644 index 0000000000..6e553cc88c --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/prototype-workingdir/PickerUsageApp/pch.cpp b/prototype-workingdir/PickerUsageApp/pch.cpp new file mode 100644 index 0000000000..ce9b73991b --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/pch.cpp @@ -0,0 +1,2 @@ +#include "pch.h" + diff --git a/prototype-workingdir/PickerUsageApp/pch.h b/prototype-workingdir/PickerUsageApp/pch.h new file mode 100644 index 0000000000..fe1ff28578 --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/pch.h @@ -0,0 +1,32 @@ +#pragma once +#include +#include +#include +#include + +// Undefine GetCurrentTime macro to prevent +// conflict with Storyboard::GetCurrentTime +#undef GetCurrentTime + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "winrt/Microsoft.Storage.Pickers.h" +#include "winrt/Windows.Storage.Pickers.h" +#include "winrt/Windows.Storage.h" +#include +#include +#include + +#include diff --git a/prototype-workingdir/PickerUsageApp/readme.txt b/prototype-workingdir/PickerUsageApp/readme.txt new file mode 100644 index 0000000000..0241fd41ef --- /dev/null +++ b/prototype-workingdir/PickerUsageApp/readme.txt @@ -0,0 +1,27 @@ +======================================================================== + PickerUsageApp Project Overview +======================================================================== + +This project demonstrates how to get started writing WinUI3 apps directly +with standard C++, using the Windows App SDK and C++/WinRT packages and +XAML compiler support to generate implementation headers from interface +(IDL) files. These headers can then be used to implement the local +Windows Runtime classes referenced in the app's XAML pages. + +Steps: +1. Create an interface (IDL) file to define any local Windows Runtime + classes referenced in the app's XAML pages. +2. Build the project once to generate implementation templates under + the "Generated Files" folder, as well as skeleton class definitions + under "Generated Files\sources". +3. Use the skeleton class definitions for reference to implement your + Windows Runtime classes. + +======================================================================== +Learn more about Windows App SDK here: +https://docs.microsoft.com/windows/apps/windows-app-sdk/ +Learn more about WinUI3 here: +https://docs.microsoft.com/windows/apps/winui/winui3/ +Learn more about C++/WinRT here: +http://aka.ms/cppwinrt/ +======================================================================== diff --git a/prototype-workingdir/PickersPrototype.sln b/prototype-workingdir/PickersPrototype.sln new file mode 100644 index 0000000000..66bdb66599 --- /dev/null +++ b/prototype-workingdir/PickersPrototype.sln @@ -0,0 +1,57 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35431.28 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Storage.Pickers", "Microsoft.Storage.Pickers\Microsoft.Storage.Pickers.vcxproj", "{349E64CF-CB0C-4202-B1B5-7F543CC6E886}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PickerUsageApp", "PickerUsageApp\PickerUsageApp.vcxproj", "{C0C88F67-8C6C-49F8-827E-86C0E1669F09}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Debug|ARM64.Build.0 = Debug|ARM64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Debug|x64.ActiveCfg = Debug|x64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Debug|x64.Build.0 = Debug|x64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Debug|x86.ActiveCfg = Debug|Win32 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Debug|x86.Build.0 = Debug|Win32 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Release|ARM64.ActiveCfg = Release|ARM64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Release|ARM64.Build.0 = Release|ARM64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Release|x64.ActiveCfg = Release|x64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Release|x64.Build.0 = Release|x64 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Release|x86.ActiveCfg = Release|Win32 + {349E64CF-CB0C-4202-B1B5-7F543CC6E886}.Release|x86.Build.0 = Release|Win32 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|ARM64.Build.0 = Debug|ARM64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|x64.ActiveCfg = Debug|x64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|x64.Build.0 = Debug|x64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|x64.Deploy.0 = Debug|x64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|x86.ActiveCfg = Debug|Win32 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|x86.Build.0 = Debug|Win32 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Debug|x86.Deploy.0 = Debug|Win32 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|ARM64.ActiveCfg = Release|ARM64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|ARM64.Build.0 = Release|ARM64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|ARM64.Deploy.0 = Release|ARM64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|x64.ActiveCfg = Release|x64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|x64.Build.0 = Release|x64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|x64.Deploy.0 = Release|x64 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|x86.ActiveCfg = Release|Win32 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|x86.Build.0 = Release|Win32 + {C0C88F67-8C6C-49F8-827E-86C0E1669F09}.Release|x86.Deploy.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4C5161F0-084E-45BA-B6B8-9A15B5EB5725} + EndGlobalSection +EndGlobal diff --git a/prototype-workingdir/environment.props b/prototype-workingdir/environment.props new file mode 100644 index 0000000000..6dc4195c32 --- /dev/null +++ b/prototype-workingdir/environment.props @@ -0,0 +1 @@ + \ No newline at end of file From fc9a03af48cf4522a67a2cce717548270cfa8942 Mon Sep 17 00:00:00 2001 From: Xiang Hong Date: Sat, 7 Dec 2024 12:06:47 +0800 Subject: [PATCH 02/13] feature: add folder functionalities to demo test app --- .../PickerUsageApp/MainWindow.xaml | 13 +- .../PickerUsageApp/MainWindow.xaml.cpp | 348 +++++++++++------- .../PickerUsageApp/MainWindow.xaml.h | 157 ++++---- 3 files changed, 314 insertions(+), 204 deletions(-) diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.xaml b/prototype-workingdir/PickerUsageApp/MainWindow.xaml index 1318f71657..b7428cfd75 100644 --- a/prototype-workingdir/PickerUsageApp/MainWindow.xaml +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml @@ -9,8 +9,15 @@ mc:Ignorable="d" Title="PickerUsageApp"> + + + + + + + - Multi Selection + Multi Selection @@ -46,8 +53,8 @@ - - + + diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp index 5ca511bf8f..a98fa3471f 100644 --- a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp @@ -19,168 +19,260 @@ using namespace Microsoft::UI::Xaml; 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; + } + } - 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; - } - } - - Windows::Foundation::IAsyncAction MainWindow::OpenFileUWPClick(IInspectable const&, RoutedEventArgs const&) - { - hstring error_mesasge{}; - try { - labelBlock().Text(L""); - auto windowNative = this->m_inner.as(); - HWND hWnd = nullptr; - check_hresult(windowNative->get_WindowHandle(&hWnd)); - - winrt::Windows::Storage::Pickers::FileOpenPicker picker{}; - - picker.as<::IInitializeWithWindow>()->Initialize(hWnd); - SetPickerOptions(picker); - //SetPickerOptions(picker); - picker.ViewMode(Convert(m_ViewMode)); - - if (!m_MultipleSelect) { - auto& file = co_await picker.PickSingleFileAsync(); - if (file != nullptr) { - labelBlock().Text(file.Path()); - } - } - else { - auto& files = co_await picker.PickMultipleFilesAsync(); - winrt::hstring names = L""; - for (auto& file : files) - { - names = names + file.Path() + L"\n"; - } - labelBlock().Text(names); - } - - co_return; - } - catch (winrt::hresult_error const& ex_) - { - error_mesasge = ex_.message(); - } - if (!error_mesasge.empty()) - { - winrt::Windows::UI::Popups::MessageDialog dialog(error_mesasge); - co_await dialog.ShowAsync(); - } - } - - Windows::Foundation::IAsyncAction MainWindow::OpenFileSDKClick(IInspectable const&, RoutedEventArgs const&) - { - hstring error_mesasge{}; - try { - labelBlock().Text(L""); - auto id = AppWindow().Id(); - winrt::Microsoft::Storage::Pickers::FileOpenPicker picker{ id }; - - SetPickerOptions(picker); - //SetPickerOptions(picker); - picker.ViewMode(m_ViewMode); - if (!m_MultipleSelect) { - auto& file = co_await picker.PickSingleFileAsync(); - if (file != nullptr) { - labelBlock().Text(file.Path()); - } - } - else { - auto& files = co_await picker.PickMultipleFilesAsync(); - winrt::hstring names = L""; - for (auto& file : files) - { - names = names + file.Path() + L"\n"; - } - labelBlock().Text(names); - } - co_return; - } - catch (winrt::hresult_error const& ex_) - { - error_mesasge = ex_.message(); - } - if (!error_mesasge.empty()) - { - winrt::Windows::UI::Popups::MessageDialog dialog(error_mesasge); - co_await dialog.ShowAsync(); - } - } + 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 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 2: + message = co_await OpenFolderUWPClick(); + break; + + default: + message = L"Unsupported Picker Type"; + break; + } + } + catch (winrt::hresult_error const& ex_) + { + message = ex_.message(); + } + labelBlock().Text(message); + } + + + Windows::Foundation::IAsyncOperation MainWindow::OpenFileUWPClick(IInspectable const&, RoutedEventArgs const&) + { + auto windowNative = this->m_inner.as(); + HWND hWnd = nullptr; + check_hresult(windowNative->get_WindowHandle(&hWnd)); + + winrt::Windows::Storage::Pickers::FileOpenPicker picker{}; + + picker.as<::IInitializeWithWindow>()->Initialize(hWnd); + SetPickerOptions(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"; + } + + winrt::Windows::Foundation::IAsyncOperation MainWindow::OpenFolderUWPClick() + { + auto windowNative = this->m_inner.as(); + HWND hWnd = nullptr; + check_hresult(windowNative->get_WindowHandle(&hWnd)); + + winrt::Windows::Storage::Pickers::FolderPicker picker{}; + + picker.as<::IInitializeWithWindow>()->Initialize(hWnd); + SetPickerOptions(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 multi selection is not support"; + } + co_return L"no selection"; + + throw hresult_not_implemented(); + } + + Windows::Foundation::IAsyncOperation MainWindow::OpenFileSDKClick(IInspectable const&, RoutedEventArgs const&) + { + auto id = AppWindow().Id(); + winrt::Microsoft::Storage::Pickers::FileOpenPicker picker{ id }; + + SetPickerOptions(picker); + //SetPickerOptions(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"; + } + + winrt::Windows::Foundation::IAsyncOperation MainWindow::OpenFolderSDKClick() + { + auto id = AppWindow().Id(); + winrt::Microsoft::Storage::Pickers::FolderPicker picker{ id }; + + SetPickerOptions(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++; + 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); - } + m_isUseCustomLabel = !m_isUseCustomLabel; + if (m_isUseCustomLabel) + { + useCustomLabelToggle().Content(box_value(L"Disable")); + customLabelBox().Visibility(Visibility::Visible); + } + else + { + useCustomLabelToggle().Content(box_value(L"Enable")); + customLabelBox().Visibility(Visibility::Collapsed); + } } void winrt::PickerUsageApp::implementation::MainWindow::ViewModeSelectionChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e) { - auto radioButtons = sender.as(); - auto selectedIndex = radioButtons.SelectedIndex(); - switch (selectedIndex) - { - case 0: - m_ViewMode = Microsoft::Storage::Pickers::PickerViewMode::List; - break; - case 1: - m_ViewMode = Microsoft::Storage::Pickers::PickerViewMode::Thumbnail; - break; - default: - break; - } + auto radioButtons = sender.as(); + auto selectedIndex = radioButtons.SelectedIndex(); + switch (selectedIndex) + { + case 0: + m_ViewMode = Microsoft::Storage::Pickers::PickerViewMode::List; + break; + case 1: + m_ViewMode = Microsoft::Storage::Pickers::PickerViewMode::Thumbnail; + break; + default: + break; + } + + } void winrt::PickerUsageApp::implementation::MainWindow::FilterTypeSelectionChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e) { - auto radioButtons = sender.as(); + auto radioButtons = sender.as(); - m_FilterTypeIndex = radioButtons.SelectedIndex(); + m_FilterTypeIndex = radioButtons.SelectedIndex(); } void winrt::PickerUsageApp::implementation::MainWindow::SettingsIdentifierChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e) { - auto radioButtons = sender.as(); - m_SettingsIdentifierIndex = radioButtons.SelectedIndex(); + auto radioButtons = sender.as(); + m_SettingsIdentifierIndex = radioButtons.SelectedIndex(); } void winrt::PickerUsageApp::implementation::MainWindow::PickerLocationIdChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e) { - auto radioButtons = sender.as(); - m_PickerLocationIdIndex = radioButtons.SelectedIndex(); + auto radioButtons = sender.as(); + m_PickerLocationIdIndex = radioButtons.SelectedIndex(); } void winrt::PickerUsageApp::implementation::MainWindow::MultiSelectToggled(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) { - m_MultipleSelect = sender.as().IsOn(); + m_MultipleSelect = sender.as().IsOn(); } + +void winrt::PickerUsageApp::implementation::MainWindow::PickerTypeChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) +{ + m_PickerTypeIndex = sender.as().SelectedIndex(); +} + + diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h index f3c1321111..189e6ca994 100644 --- a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h @@ -5,89 +5,100 @@ namespace winrt::PickerUsageApp::implementation { - struct MainWindow : MainWindowT - { - int count{ 0 }; + struct MainWindow : MainWindowT + { + int count{ 0 }; - MainWindow() - { - // Xaml objects should not call InitializeComponent during construction. - // See https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent - } + MainWindow() + { + // Xaml objects should not call InitializeComponent during construction. + // See https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent + } - winrt::Windows::Foundation::IAsyncAction OpenFileSDKClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); - winrt::Windows::Foundation::IAsyncAction OpenFileUWPClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); + winrt::Windows::Foundation::IAsyncOperation OpenFileSDKClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); + winrt::Windows::Foundation::IAsyncOperation OpenFileUWPClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); - 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); - 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 }; - bool m_MultipleSelect{ false }; + winrt::Windows::Foundation::IAsyncOperation OpenFolderSDKClick(); + winrt::Windows::Foundation::IAsyncOperation OpenFolderUWPClick(); - // using this template approach helps us ensure use same logic on compatible user facing API - template void SetPickerOptions(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_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; - } - switch (m_PickerLocationIdIndex) - { - case 1: - picker.SuggestedStartLocation(TPickerLocationId::DocumentsLibrary); - break; - case 2: - picker.SuggestedStartLocation(TPickerLocationId::Desktop); - break; - default: - break; - } + winrt::Windows::Foundation::IAsyncAction SDKClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); + winrt::Windows::Foundation::IAsyncAction UWPClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); + void UIFronzenTestClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); + void toggleCustomLableClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); + void ViewModeSelectionChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e); + void FilterTypeSelectionChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e); + void SettingsIdentifierChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e); + void PickerLocationIdChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e); + void MultiSelectToggled(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); + void PickerTypeChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); - } + private: + bool m_isUseCustomLabel{ false }; + winrt::Microsoft::Storage::Pickers::PickerViewMode m_ViewMode{ Microsoft::Storage::Pickers::PickerViewMode::List }; + int m_FilterTypeIndex{ 0 }; + int m_SettingsIdentifierIndex{ 0 }; + int m_PickerLocationIdIndex{ 0 }; + int m_PickerTypeIndex{ 0 }; + bool m_MultipleSelect{ false }; - }; + + // using this template approach helps us ensure use same logic on compatible user facing API + template void SetPickerOptions(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_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; + } + switch (m_PickerLocationIdIndex) + { + case 1: + picker.SuggestedStartLocation(TPickerLocationId::DocumentsLibrary); + break; + case 2: + picker.SuggestedStartLocation(TPickerLocationId::Desktop); + break; + default: + break; + } + + + } + + }; } namespace winrt::PickerUsageApp::factory_implementation { - struct MainWindow : MainWindowT - { - }; + struct MainWindow : MainWindowT + { + }; } From 37a5a75bc883f67e662e96b04c74a3ed25ce44f6 Mon Sep 17 00:00:00 2001 From: Xiang Hong Date: Sat, 7 Dec 2024 17:13:55 +0800 Subject: [PATCH 03/13] add save file dialog usage in demo app --- .../PickerUsageApp/MainWindow.xaml.cpp | 69 ++++++++++++++++--- .../PickerUsageApp/MainWindow.xaml.h | 31 +++++---- 2 files changed, 77 insertions(+), 23 deletions(-) diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp index a98fa3471f..00e0330a10 100644 --- a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp @@ -43,6 +43,9 @@ namespace winrt::PickerUsageApp::implementation case 0: message = co_await OpenFileSDKClick(sender, args); break; + case 1: + message = co_await SaveFileSDKClick(); + break; case 2: message = co_await OpenFolderSDKClick(); break; @@ -69,6 +72,9 @@ namespace winrt::PickerUsageApp::implementation case 0: message = co_await OpenFileUWPClick(sender, args); break; + case 1: + message = co_await SaveFileUWPClick(); + break; case 2: message = co_await OpenFolderUWPClick(); break; @@ -95,7 +101,7 @@ namespace winrt::PickerUsageApp::implementation winrt::Windows::Storage::Pickers::FileOpenPicker picker{}; picker.as<::IInitializeWithWindow>()->Initialize(hWnd); - SetPickerOptions(picker); + SetOpenPickerOptions(picker); picker.ViewMode(Convert(m_ViewMode)); if (!m_MultipleSelect) @@ -119,6 +125,33 @@ namespace winrt::PickerUsageApp::implementation co_return L"no selection"; } + Windows::Foundation::IAsyncOperation MainWindow::SaveFileUWPClick() + { + auto windowNative = this->m_inner.as(); + HWND hWnd = nullptr; + check_hresult(windowNative->get_WindowHandle(&hWnd)); + + winrt::Windows::Storage::Pickers::FileSavePicker picker{}; + picker.FileTypeChoices().Insert(L"Plain Text", winrt::single_threaded_vector({ L".txt" })); + + picker.as<::IInitializeWithWindow>()->Initialize(hWnd); + SetPickerOptions(picker); + + if (!m_MultipleSelect) + { + auto& file = co_await picker.PickSaveFileAsync(); + if (file != nullptr) + { + co_return file.Path(); + } + } + else + { + co_return L"File Save Picker does not support multi selection"; + } + co_return L"no selection"; + } + winrt::Windows::Foundation::IAsyncOperation MainWindow::OpenFolderUWPClick() { auto windowNative = this->m_inner.as(); @@ -128,7 +161,7 @@ namespace winrt::PickerUsageApp::implementation winrt::Windows::Storage::Pickers::FolderPicker picker{}; picker.as<::IInitializeWithWindow>()->Initialize(hWnd); - SetPickerOptions(picker); + SetOpenPickerOptions(picker); picker.ViewMode(Convert(m_ViewMode)); if (!m_MultipleSelect) @@ -141,7 +174,7 @@ namespace winrt::PickerUsageApp::implementation } else { - co_return L"Folder multi selection is not support"; + co_return L"Folder Picker does not support multi selection"; } co_return L"no selection"; @@ -153,8 +186,7 @@ namespace winrt::PickerUsageApp::implementation auto id = AppWindow().Id(); winrt::Microsoft::Storage::Pickers::FileOpenPicker picker{ id }; - SetPickerOptions(picker); - //SetPickerOptions(picker); + SetOpenPickerOptions(picker); picker.ViewMode(m_ViewMode); if (!m_MultipleSelect) { @@ -177,12 +209,33 @@ namespace winrt::PickerUsageApp::implementation co_return L"no selection"; } + Windows::Foundation::IAsyncOperation MainWindow::SaveFileSDKClick() + { + auto id = AppWindow().Id(); + winrt::Microsoft::Storage::Pickers::FileSavePicker picker{ id }; + + SetPickerOptions(picker); + if (!m_MultipleSelect) + { + auto& file = co_await picker.PickSaveFileAsync(); + if (file != nullptr) + { + co_return file.Path(); + } + } + else + { + co_return L"FileSavePicker does not support multi selection"; + } + co_return L"no selection"; + } + winrt::Windows::Foundation::IAsyncOperation MainWindow::OpenFolderSDKClick() { auto id = AppWindow().Id(); winrt::Microsoft::Storage::Pickers::FolderPicker picker{ id }; - SetPickerOptions(picker); + SetOpenPickerOptions(picker); picker.ViewMode(m_ViewMode); if (!m_MultipleSelect) { @@ -239,8 +292,6 @@ void winrt::PickerUsageApp::implementation::MainWindow::ViewModeSelectionChanged default: break; } - - } @@ -274,5 +325,3 @@ void winrt::PickerUsageApp::implementation::MainWindow::PickerTypeChanged(winrt: { m_PickerTypeIndex = sender.as().SelectedIndex(); } - - diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h index 189e6ca994..ddb29909fc 100644 --- a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h @@ -18,6 +18,9 @@ namespace winrt::PickerUsageApp::implementation winrt::Windows::Foundation::IAsyncOperation OpenFileSDKClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); winrt::Windows::Foundation::IAsyncOperation OpenFileUWPClick(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); + winrt::Windows::Foundation::IAsyncOperation SaveFileUWPClick(); + winrt::Windows::Foundation::IAsyncOperation SaveFileSDKClick(); + winrt::Windows::Foundation::IAsyncOperation OpenFolderSDKClick(); winrt::Windows::Foundation::IAsyncOperation OpenFolderUWPClick(); @@ -63,36 +66,38 @@ namespace winrt::PickerUsageApp::implementation picker.SettingsIdentifier({}); break; } - switch (m_FilterTypeIndex) + switch (m_PickerLocationIdIndex) { case 1: - picker.FileTypeFilter().Append(L".jpg"); - picker.FileTypeFilter().Append(L".png"); + picker.SuggestedStartLocation(TPickerLocationId::DocumentsLibrary); break; case 2: - picker.FileTypeFilter().Append(L".jpg"); - picker.FileTypeFilter().Append(L".png"); - picker.FileTypeFilter().Append(L".json"); + picker.SuggestedStartLocation(TPickerLocationId::Desktop); break; default: - picker.FileTypeFilter().Append(L"*"); break; } - switch (m_PickerLocationIdIndex) + } + + template void SetOpenPickerOptions(TPicker picker) + { + SetPickerOptions(picker); + switch (m_FilterTypeIndex) { case 1: - picker.SuggestedStartLocation(TPickerLocationId::DocumentsLibrary); + picker.FileTypeFilter().Append(L".jpg"); + picker.FileTypeFilter().Append(L".png"); break; case 2: - picker.SuggestedStartLocation(TPickerLocationId::Desktop); + picker.FileTypeFilter().Append(L".jpg"); + picker.FileTypeFilter().Append(L".png"); + picker.FileTypeFilter().Append(L".json"); break; default: + picker.FileTypeFilter().Append(L"*"); break; } - - } - }; } From 8dea72ab4a2e80ee8f8e6ddd01eb3d8c76bbf5d4 Mon Sep 17 00:00:00 2001 From: "Xiang Hong (from Dev Box)" Date: Sat, 7 Dec 2024 19:46:45 +0800 Subject: [PATCH 04/13] feature: add COM FileSavePicker basic implementation --- .../FileSavePicker.cpp | 173 +++++++++++------- .../PickerCommon.cpp | 2 +- .../Microsoft.Storage.Pickers/PickerCommon.h | 4 +- .../PickerUsageApp/MainWindow.xaml | 1 + .../PickerUsageApp/MainWindow.xaml.cpp | 4 - 5 files changed, 109 insertions(+), 75 deletions(-) diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp index 302ca462bd..ca596812cb 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp @@ -16,76 +16,113 @@ 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_PickerLocationId; - } - void FileSavePicker::SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value) - { - m_PickerLocationId = value; - } - hstring FileSavePicker::CommitButtonText() - { - return m_commitButtonText; - } - void FileSavePicker::CommitButtonText(hstring const& value) - { - m_commitButtonText = value; - } - winrt::Windows::Foundation::Collections::IMap> FileSavePicker::FileTypeChoices() - { - return m_fileTypeChoices; - } - hstring FileSavePicker::DefaultFileExtension() - { - return m_defaultFileExtension; - } - void FileSavePicker::DefaultFileExtension(hstring const& value) - { - m_defaultFileExtension = value; - } - winrt::Windows::Storage::StorageFile FileSavePicker::SuggestedSaveFile() - { - return m_suggestedSaveFile; - } - void FileSavePicker::SuggestedSaveFile(winrt::Windows::Storage::StorageFile const& value) - { - m_suggestedSaveFile = value; - } - hstring FileSavePicker::SuggestedFileName() - { - return m_suggestedFileName; - } - void FileSavePicker::SuggestedFileName(hstring const& value) - { - m_suggestedFileName = value; - } + 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_PickerLocationId; + } + void FileSavePicker::SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value) + { + m_PickerLocationId = value; + } + hstring FileSavePicker::CommitButtonText() + { + return m_commitButtonText; + } + void FileSavePicker::CommitButtonText(hstring const& value) + { + m_commitButtonText = value; + } + winrt::Windows::Foundation::Collections::IMap> FileSavePicker::FileTypeChoices() + { + return m_fileTypeChoices; + } + hstring FileSavePicker::DefaultFileExtension() + { + return m_defaultFileExtension; + } + void FileSavePicker::DefaultFileExtension(hstring const& value) + { + m_defaultFileExtension = value; + } + winrt::Windows::Storage::StorageFile FileSavePicker::SuggestedSaveFile() + { + return m_suggestedSaveFile; + } + void FileSavePicker::SuggestedSaveFile(winrt::Windows::Storage::StorageFile const& value) + { + m_suggestedSaveFile = value; + } + hstring FileSavePicker::SuggestedFileName() + { + return m_suggestedFileName; + } + void FileSavePicker::SuggestedFileName(hstring const& value) + { + m_suggestedFileName = value; + } - struct FileOpenPickerParameters { - HWND HWnd; - winrt::hstring CommitButtonText; - winrt::hstring SettingsIdentifierId; - PickerLocationId PickerLocationId; + struct FileSavePickerParameters { + HWND HWnd; + winrt::hstring CommitButtonText; + winrt::hstring SettingsIdentifierId; + PickerLocationId PickerLocationId; - void ConfigureDialog(winrt::com_ptr dialog) { - PickerCommon::ConfigureDialogCommon(dialog, CommitButtonText, SettingsIdentifierId, PickerLocationId); + void ConfigureDialog(winrt::com_ptr dialog) + { + PickerCommon::ConfigureDialogCommon(dialog, CommitButtonText, SettingsIdentifierId, PickerLocationId); + } + }; + + winrt::Windows::Foundation::IAsyncOperation FileSavePicker::PickSaveFileAsync() + { + FileSavePickerParameters parameters{}; + + co_await winrt::resume_background(); + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return nullptr; } - }; - winrt::Windows::Foundation::IAsyncOperation FileSavePicker::PickSaveFileAsync() - { - throw hresult_not_implemented(); - } + auto dialog = create_instance(CLSID_FileSaveDialog, CONTEXT_ALL); + + parameters.ConfigureDialog(dialog); + + // TODO: set filter typse + COMDLG_FILTERSPEC save_filter[1]; + save_filter[0].pszName = L"All files"; + save_filter[0].pszSpec = L"*.*"; + check_hresult(dialog->SetFileTypes(1, save_filter)); + + { + auto hr = dialog->Show(parameters.HWnd); + if (FAILED(hr)) + { + co_return nullptr; + } + } + + winrt::com_ptr shellItem{}; + check_hresult(dialog->GetResult(shellItem.put())); + + auto& file = co_await PickerCommon::CreateStorageFileFromShellItem(shellItem); + if (cancellationToken()) + { + co_return nullptr; + } + + co_return file; + } } diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp index f9d207621b..1a08ef8956 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp +++ b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp @@ -96,7 +96,7 @@ namespace PickerCommon { using namespace winrt; void ConfigureDialogCommon( - winrt::com_ptr dialog, + winrt::com_ptr dialog, winrt::hstring commitButtonText, winrt::hstring settingIdentifierId, winrt::Microsoft::Storage::Pickers::PickerLocationId pickerLocationId diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h index f7c4443d31..13a7b43308 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h +++ b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h @@ -8,7 +8,7 @@ namespace PickerCommon { void ConfigureDialogCommon( - winrt::com_ptr dialog, + winrt::com_ptr dialog, winrt::hstring commitButtonText, winrt::hstring settingIdentifierId, winrt::Microsoft::Storage::Pickers::PickerLocationId pickerLocationId @@ -16,4 +16,4 @@ namespace PickerCommon { winrt::Windows::Foundation::IAsyncOperation CreateStorageFileFromShellItem(winrt::com_ptr shellItem); winrt::Windows::Foundation::IAsyncOperation CreateStorageFolderFromShellItem(winrt::com_ptr shellItem); -} \ No newline at end of file +} diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.xaml b/prototype-workingdir/PickerUsageApp/MainWindow.xaml index b7428cfd75..adc4847337 100644 --- a/prototype-workingdir/PickerUsageApp/MainWindow.xaml +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml @@ -52,6 +52,7 @@ + !!! WARN !!! Save picker will overwrite Context in selected file with test data diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp index 00e0330a10..0aaccef52f 100644 --- a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp @@ -15,8 +15,6 @@ 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 { Windows::Storage::Pickers::PickerViewMode Convert(Microsoft::Storage::Pickers::PickerViewMode viewMode) @@ -177,8 +175,6 @@ namespace winrt::PickerUsageApp::implementation co_return L"Folder Picker does not support multi selection"; } co_return L"no selection"; - - throw hresult_not_implemented(); } Windows::Foundation::IAsyncOperation MainWindow::OpenFileSDKClick(IInspectable const&, RoutedEventArgs const&) From 756bafa151e319ef1a40f2a25411f04b364c96c5 Mon Sep 17 00:00:00 2001 From: "Xiang Hong (from Dev Box)" Date: Sat, 7 Dec 2024 22:02:55 +0800 Subject: [PATCH 05/13] fix: fix file type filter issues and refactor to use PickParameters --- .../FileOpenPicker.cpp | 296 ++++++++-------- .../FileOpenPicker.h | 55 ++- .../FileSavePicker.cpp | 40 +-- .../FileSavePicker.h | 3 +- .../FolderPicker.cpp | 33 +- .../Microsoft.Storage.Pickers/FolderPicker.h | 5 +- .../PickerCommon.cpp | 315 +++++++++++------- .../Microsoft.Storage.Pickers/PickerCommon.h | 23 +- .../PickerUsageApp/MainWindow.xaml.cpp | 5 +- .../PickerUsageApp/MainWindow.xaml.h | 10 +- 10 files changed, 408 insertions(+), 377 deletions(-) diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp index a423868fbb..38e0ed0c3b 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp @@ -9,162 +9,144 @@ 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_PickerLocationId; - } - void FileOpenPicker::SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value) - { - m_PickerLocationId = value; - } - winrt::hstring FileOpenPicker::CommitButtonText() - { - return m_commitButtonText; - } - void FileOpenPicker::CommitButtonText(winrt::hstring const& value) - { - m_commitButtonText = value; - } - winrt::Windows::Foundation::Collections::IVector FileOpenPicker::FileTypeFilter() - { - return m_fileTypeFilter; - } - - struct FileOpenPickerParameters { - winrt::hstring CommitButtonText; - winrt::hstring SettingsIdentifierId; - PickerLocationId PickerLocationId; - std::vector FileTypeFilterData{}; - std::vector FileTypeFilterPara{}; - HWND HWnd; - - void ConfigureDialog(winrt::com_ptr dialog) { - PickerCommon::ConfigureDialogCommon(dialog, CommitButtonText, SettingsIdentifierId, PickerLocationId); - check_hresult(dialog->SetFileTypes(FileTypeFilterPara.size(), FileTypeFilterPara.data())); - } - }; - - void FileOpenPicker::CaptureParameters(FileOpenPickerParameters& parameters) { - parameters.CommitButtonText = m_commitButtonText; - parameters.SettingsIdentifierId = m_SettingsIdentifier; - parameters.PickerLocationId = m_PickerLocationId; - for (size_t i = 0; i < m_fileTypeFilter.Size(); i++) - { - parameters.FileTypeFilterData.push_back(m_fileTypeFilter.GetAt(i)); - parameters.FileTypeFilterPara.push_back({ L"", parameters.FileTypeFilterData[i].c_str() }); - } - parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); - } - - winrt::Windows::Foundation::IAsyncOperation FileOpenPicker::PickSingleFileAsync() - { - FileOpenPickerParameters parameters{}; - - CaptureParameters(parameters); - - co_await winrt::resume_background(); - - auto cancellationToken = co_await winrt::get_cancellation_token(); - if (cancellationToken()) - { - co_return nullptr; - } - - // TODO: should we initialize COM? - // wil::com_initialize_ex initializeCom{ COINIT_APARTMENTTHREADED }; - - auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL); - - parameters.ConfigureDialog(dialog); - - auto hr = dialog->Show(parameters.HWnd); - if (FAILED(hr) || cancellationToken()) - { - co_return nullptr; - } - - winrt::com_ptr shellItem{}; - check_hresult(dialog->GetResult(shellItem.put())); - - auto& file = co_await PickerCommon::CreateStorageFileFromShellItem(shellItem); - if (cancellationToken()) - { - co_return nullptr; - } - - co_return file; - } - - winrt::Windows::Foundation::IAsyncOperation> FileOpenPicker::PickMultipleFilesAsync() - { - FileOpenPickerParameters parameters{}; - - CaptureParameters(parameters); - - co_await winrt::resume_background(); - - winrt::Windows::Foundation::Collections::IVector results{ winrt::single_threaded_vector() }; - - auto cancellationToken = co_await winrt::get_cancellation_token(); - if (cancellationToken()) - { - co_return results.GetView(); - } - - auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL); - - parameters.ConfigureDialog(dialog); - - auto pickerOptions = FOS_ALLOWMULTISELECT; - check_hresult(dialog->SetOptions(pickerOptions)); - - auto hr = dialog->Show(parameters.HWnd); - if (FAILED(hr) || cancellationToken()) - { - co_return results.GetView(); - } - - winrt::com_ptr shellItems{}; - check_hresult(dialog->GetResults(shellItems.put())); - - DWORD itemCount = 0; - check_hresult(shellItems->GetCount(&itemCount)); + 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_PickerLocationId; + } + void FileOpenPicker::SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value) + { + m_PickerLocationId = value; + } + winrt::hstring FileOpenPicker::CommitButtonText() + { + return m_commitButtonText; + } + void FileOpenPicker::CommitButtonText(winrt::hstring const& value) + { + m_commitButtonText = value; + } + winrt::Windows::Foundation::Collections::IVector FileOpenPicker::FileTypeFilter() + { + return m_fileTypeFilter; + } + + void FileOpenPicker::CaptureParameters(PickerCommon::PickerParameters& parameters) + { + parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); + parameters.CommitButtonText = m_commitButtonText; + parameters.SettingsIdentifierId = m_SettingsIdentifier; + parameters.PickerLocationId = m_PickerLocationId; + parameters.FileTypeFilterPara = PickerCommon::CaptureFilterSpec(parameters.FileTypeFilterData, m_fileTypeFilter.GetView()); + } + + winrt::Windows::Foundation::IAsyncOperation FileOpenPicker::PickSingleFileAsync() + { + PickerCommon::PickerParameters parameters{}; + + CaptureParameters(parameters); + + co_await winrt::resume_background(); + + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return nullptr; + } + + // TODO: should we initialize COM? + // wil::com_initialize_ex initializeCom{ COINIT_APARTMENTTHREADED }; + + auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL); + + parameters.ConfigureDialog(dialog); + + auto hr = dialog->Show(parameters.HWnd); + if (FAILED(hr) || cancellationToken()) + { + co_return nullptr; + } + + winrt::com_ptr shellItem{}; + check_hresult(dialog->GetResult(shellItem.put())); + + auto file = co_await PickerCommon::CreateStorageFileFromShellItem(shellItem); + if (cancellationToken()) + { + co_return nullptr; + } + + co_return file; + } + + winrt::Windows::Foundation::IAsyncOperation> FileOpenPicker::PickMultipleFilesAsync() + { + PickerCommon::PickerParameters parameters{}; + + CaptureParameters(parameters); + + co_await winrt::resume_background(); + + winrt::Windows::Foundation::Collections::IVector results{ winrt::single_threaded_vector() }; + + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return results.GetView(); + } + + auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL); + + parameters.ConfigureDialog(dialog); + + check_hresult(dialog->SetOptions(FOS_ALLOWMULTISELECT)); + + auto hr = dialog->Show(parameters.HWnd); + if (FAILED(hr) || cancellationToken()) + { + co_return results.GetView(); + } + + winrt::com_ptr shellItems{}; + check_hresult(dialog->GetResults(shellItems.put())); + + DWORD itemCount = 0; + check_hresult(shellItems->GetCount(&itemCount)); + + winrt::com_ptr shellItem{}; + for (DWORD i = 0; i < itemCount; i++) + { + check_hresult(shellItems->GetItemAt(i, shellItem.put())); + auto file = co_await PickerCommon::CreateStorageFileFromShellItem(shellItem); + results.Append(file); + } + + if (cancellationToken()) + { + results.Clear(); + co_return results.GetView(); + } - winrt::com_ptr shellItem{}; - for (auto 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(); - } + co_return results.GetView(); + } } diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.h b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.h index 36fa417263..b4cd94c8dc 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.h +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.h @@ -1,44 +1,43 @@ #pragma once #include "FileOpenPicker.g.h" +#include "PickerCommon.h" namespace winrt::Microsoft::Storage::Pickers::implementation { - struct FileOpenPickerParameters; + struct FileOpenPicker : FileOpenPickerT + { + FileOpenPicker(winrt::Microsoft::UI::WindowId const& windowId); - struct FileOpenPicker : FileOpenPickerT - { - FileOpenPicker(winrt::Microsoft::UI::WindowId const& windowId); + winrt::Microsoft::Storage::Pickers::PickerViewMode ViewMode(); + void ViewMode(winrt::Microsoft::Storage::Pickers::PickerViewMode const& value); + hstring SettingsIdentifier(); + void SettingsIdentifier(hstring const& value); + winrt::Microsoft::Storage::Pickers::PickerLocationId SuggestedStartLocation(); + void SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value); + winrt::hstring CommitButtonText(); + void CommitButtonText(winrt::hstring const& value); - winrt::Microsoft::Storage::Pickers::PickerViewMode ViewMode(); - void ViewMode(winrt::Microsoft::Storage::Pickers::PickerViewMode const& value); - hstring SettingsIdentifier(); - void SettingsIdentifier(hstring const& value); - winrt::Microsoft::Storage::Pickers::PickerLocationId SuggestedStartLocation(); - void SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value); - winrt::hstring CommitButtonText(); - void CommitButtonText(winrt::hstring const& value); + winrt::Windows::Foundation::Collections::IVector FileTypeFilter(); - winrt::Windows::Foundation::Collections::IVector FileTypeFilter(); + winrt::Windows::Foundation::IAsyncOperation PickSingleFileAsync(); + winrt::Windows::Foundation::IAsyncOperation> PickMultipleFilesAsync(); - winrt::Windows::Foundation::IAsyncOperation PickSingleFileAsync(); - winrt::Windows::Foundation::IAsyncOperation> PickMultipleFilesAsync(); + private: + winrt::Microsoft::UI::WindowId m_windowId{}; + winrt::hstring m_SettingsIdentifier{}; + PickerLocationId m_PickerLocationId{ PickerLocationId::Unspecified }; + winrt::hstring m_commitButtonText{}; - private: - winrt::Microsoft::UI::WindowId m_windowId{}; - winrt::hstring m_SettingsIdentifier{}; - PickerLocationId m_PickerLocationId{ PickerLocationId::Unspecified }; - winrt::hstring m_commitButtonText{}; + PickerViewMode m_ViewMode{ PickerViewMode::List }; - PickerViewMode m_ViewMode{ PickerViewMode::List }; + winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ winrt::single_threaded_vector() }; - winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ winrt::single_threaded_vector() }; - - void CaptureParameters(FileOpenPickerParameters& parameters); - }; + void CaptureParameters(PickerCommon::PickerParameters& parameters); + }; } namespace winrt::Microsoft::Storage::Pickers::factory_implementation { - struct FileOpenPicker : FileOpenPickerT - { - }; + struct FileOpenPicker : FileOpenPickerT + { + }; } diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp index ca596812cb..65afef1d92 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp @@ -73,39 +73,31 @@ namespace winrt::Microsoft::Storage::Pickers::implementation m_suggestedFileName = value; } - struct FileSavePickerParameters { - HWND HWnd; - winrt::hstring CommitButtonText; - winrt::hstring SettingsIdentifierId; - PickerLocationId PickerLocationId; - void ConfigureDialog(winrt::com_ptr dialog) - { - PickerCommon::ConfigureDialogCommon(dialog, CommitButtonText, SettingsIdentifierId, PickerLocationId); - } - }; + 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_PickerLocationId; + parameters.FileTypeFilterPara = PickerCommon::CaptureFilterSpec(parameters.FileTypeFilterData, m_fileTypeChoices.GetView()); + } winrt::Windows::Foundation::IAsyncOperation FileSavePicker::PickSaveFileAsync() { - FileSavePickerParameters parameters{}; + PickerCommon::PickerParameters parameters{}; + CaptureParameters(parameters); co_await winrt::resume_background(); - auto cancellationToken = co_await winrt::get_cancellation_token(); - if (cancellationToken()) - { - co_return nullptr; - } + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return nullptr; + } auto dialog = create_instance(CLSID_FileSaveDialog, CONTEXT_ALL); - parameters.ConfigureDialog(dialog); - // TODO: set filter typse - COMDLG_FILTERSPEC save_filter[1]; - save_filter[0].pszName = L"All files"; - save_filter[0].pszSpec = L"*.*"; - check_hresult(dialog->SetFileTypes(1, save_filter)); - { auto hr = dialog->Show(parameters.HWnd); if (FAILED(hr)) @@ -117,7 +109,7 @@ namespace winrt::Microsoft::Storage::Pickers::implementation winrt::com_ptr shellItem{}; check_hresult(dialog->GetResult(shellItem.put())); - auto& file = co_await PickerCommon::CreateStorageFileFromShellItem(shellItem); + auto file = co_await PickerCommon::CreateStorageFileFromShellItem(shellItem); if (cancellationToken()) { co_return nullptr; diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h index b0ab42ddcd..da7218dec1 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h @@ -1,5 +1,6 @@ #pragma once #include "FileSavePicker.g.h" +#include "PickerCommon.h" namespace winrt::Microsoft::Storage::Pickers::implementation { @@ -33,7 +34,7 @@ namespace winrt::Microsoft::Storage::Pickers::implementation hstring m_suggestedFileName{}; winrt::Windows::Foundation::Collections::IMap> m_fileTypeChoices{ winrt::single_threaded_map>() }; - void CaptureParameters(FileSavePickerParameters& parameters); + void CaptureParameters(PickerCommon::PickerParameters& parameters); }; } namespace winrt::Microsoft::Storage::Pickers::factory_implementation diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp index 7827f53fc3..b650361dda 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp @@ -47,40 +47,20 @@ namespace winrt::Microsoft::Storage::Pickers::implementation winrt::Windows::Foundation::Collections::IVector FolderPicker::FileTypeFilter() { return m_fileTypeFilter; - } - struct FolderPickerParameters { - winrt::hstring CommitButtonText; - winrt::hstring SettingsIdentifierId; - PickerLocationId PickerLocationId; - std::vector FileTypeFilterData{}; - std::vector FileTypeFilterPara{}; - HWND HWnd; - - void ConfigureDialog(winrt::com_ptr dialog) { - PickerCommon::ConfigureDialogCommon(dialog, CommitButtonText, SettingsIdentifierId, PickerLocationId); - check_hresult(dialog->SetFileTypes(FileTypeFilterPara.size(), FileTypeFilterPara.data())); - } - }; - - void FolderPicker::CaptureParameters(FolderPickerParameters& parameters) { + 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_PickerLocationId; - for (size_t i = 0; i < m_fileTypeFilter.Size(); i++) - { - parameters.FileTypeFilterData.push_back(m_fileTypeFilter.GetAt(i)); - parameters.FileTypeFilterPara.push_back({ L"", parameters.FileTypeFilterData[i].c_str() }); - } - parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); + parameters.FileTypeFilterPara = PickerCommon::CaptureFilterSpec(parameters.FileTypeFilterData, m_fileTypeFilter.GetView()); } winrt::Windows::Foundation::IAsyncOperation FolderPicker::PickSingleFolderAsync() { - FolderPickerParameters parameters{}; - + PickerCommon::PickerParameters parameters{}; CaptureParameters(parameters); co_await winrt::resume_background(); @@ -91,9 +71,6 @@ namespace winrt::Microsoft::Storage::Pickers::implementation co_return nullptr; } - // TODO: should we initialize COM? - // wil::com_initialize_ex initializeCom{ COINIT_APARTMENTTHREADED }; - auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL); parameters.ConfigureDialog(dialog); @@ -108,7 +85,7 @@ namespace winrt::Microsoft::Storage::Pickers::implementation winrt::com_ptr shellItem{}; check_hresult(dialog->GetResult(shellItem.put())); - auto& folder = co_await PickerCommon::CreateStorageFolderFromShellItem(shellItem); + auto folder = co_await PickerCommon::CreateStorageFolderFromShellItem(shellItem); if (cancellationToken()) { co_return nullptr; diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h index ffaae2105c..1b599ae0f3 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h @@ -1,10 +1,9 @@ #pragma once #include "FolderPicker.g.h" +#include "PickerCommon.h" namespace winrt::Microsoft::Storage::Pickers::implementation { - struct FolderPickerParameters; - struct FolderPicker : FolderPickerT { FolderPicker(winrt::Microsoft::UI::WindowId const& windowId); @@ -29,7 +28,7 @@ namespace winrt::Microsoft::Storage::Pickers::implementation winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ winrt::single_threaded_vector() }; - void CaptureParameters(FolderPickerParameters& parameters); + void CaptureParameters(PickerCommon::PickerParameters& parameters); }; } namespace winrt::Microsoft::Storage::Pickers::factory_implementation diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp index 1a08ef8956..577c3d6378 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp +++ b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp @@ -7,132 +7,201 @@ #include namespace { - bool IsHStringNullOrEmpty(winrt::hstring value) { - // TODO: proper handling of null string reference? - return value.empty(); - } - - // TODO: rewrite use WinRT APIs https://learn.microsoft.com/en-us/uwp/api/windows.security.cryptography.core.hashalgorithmprovider?view=winrt-26100 - GUID HashHStringToGuid(winrt::hstring const& input) - { - // Convert the hstring to bytes (UTF-16LE encoding) - const BYTE* data = reinterpret_cast(input.data()); - DWORD dataSize = static_cast(input.size() * sizeof(wchar_t)); - - // Acquire a cryptographic provider context - wil::unique_hcryptprov cryptProv; - THROW_IF_WIN32_BOOL_FALSE(CryptAcquireContextW(&cryptProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)); - - // Create an MD5 hash object - wil::unique_hcrypthash hash; - THROW_IF_WIN32_BOOL_FALSE(CryptCreateHash(cryptProv.get(), CALG_MD5, 0, 0, &hash)); - - // Hash the data - THROW_IF_WIN32_BOOL_FALSE(CryptHashData(hash.get(), data, dataSize, 0)); - - // Get the hash value - BYTE hashValue[16]; // MD5 hash is 16 bytes - DWORD hashSize = sizeof(hashValue); - THROW_IF_WIN32_BOOL_FALSE(CryptGetHashParam(hash.get(), HP_HASHVAL, hashValue, &hashSize, 0)); - - // Copy the hash into a GUID - GUID guid; - memcpy(&guid, hashValue, sizeof(GUID)); - - // TODO: Need to modify genreated bit patterns to fit GUID specification - // like need to specify some bits to make it a valid GUID (maybe v3 or v5) - return guid; - } - - // TODO: use better winrt implementations? - // Challenge: currently winrt based Storage.KnownFolder APIs does not provide all location id we need - winrt::com_ptr GetKnownFolderFromId(winrt::Microsoft::Storage::Pickers::PickerLocationId pickerLocationId) { - KNOWNFOLDERID knownFolderId; - switch (pickerLocationId) - { - case winrt::Microsoft::Storage::Pickers::PickerLocationId::DocumentsLibrary: - knownFolderId = FOLDERID_Documents; - break; - case winrt::Microsoft::Storage::Pickers::PickerLocationId::ComputerFolder: - knownFolderId = FOLDERID_ComputerFolder; - break; - case winrt::Microsoft::Storage::Pickers::PickerLocationId::Desktop: - knownFolderId = FOLDERID_Desktop; - break; - case winrt::Microsoft::Storage::Pickers::PickerLocationId::Downloads: - knownFolderId = FOLDERID_Downloads; - break; - case winrt::Microsoft::Storage::Pickers::PickerLocationId::HomeGroup: - knownFolderId = FOLDERID_HomeGroup; - break; - case winrt::Microsoft::Storage::Pickers::PickerLocationId::MusicLibrary: - knownFolderId = FOLDERID_MusicLibrary; - break; - case winrt::Microsoft::Storage::Pickers::PickerLocationId::PicturesLibrary: - knownFolderId = FOLDERID_PicturesLibrary; - break; - case winrt::Microsoft::Storage::Pickers::PickerLocationId::VideosLibrary: - knownFolderId = FOLDERID_VideosLibrary; - break; - case winrt::Microsoft::Storage::Pickers::PickerLocationId::Objects3D: - knownFolderId = FOLDERID_Objects3D; - break; - default: - return nullptr; - } - - auto knownFolderManager = winrt::create_instance(CLSID_KnownFolderManager); - winrt::com_ptr knownFolder; - winrt::check_hresult(knownFolderManager->GetFolder(knownFolderId, knownFolder.put())); - winrt::com_ptr defaultFolder; - winrt::check_hresult(knownFolder->GetShellItem(0, IID_PPV_ARGS(defaultFolder.put()))); - return defaultFolder; - } + bool IsHStringNullOrEmpty(winrt::hstring value) + { + // TODO: proper handling of null string reference? + return value.empty(); + } + + // TODO: rewrite use WinRT APIs https://learn.microsoft.com/en-us/uwp/api/windows.security.cryptography.core.hashalgorithmprovider?view=winrt-26100 + GUID HashHStringToGuid(winrt::hstring const& input) + { + // Convert the hstring to bytes (UTF-16LE encoding) + const BYTE* data = reinterpret_cast(input.data()); + DWORD dataSize = static_cast(input.size() * sizeof(wchar_t)); + + // Acquire a cryptographic provider context + wil::unique_hcryptprov cryptProv; + THROW_IF_WIN32_BOOL_FALSE(CryptAcquireContextW(&cryptProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)); + + // Create an MD5 hash object + wil::unique_hcrypthash hash; + THROW_IF_WIN32_BOOL_FALSE(CryptCreateHash(cryptProv.get(), CALG_MD5, 0, 0, &hash)); + + // Hash the data + THROW_IF_WIN32_BOOL_FALSE(CryptHashData(hash.get(), data, dataSize, 0)); + + // Get the hash value + BYTE hashValue[16]; // MD5 hash is 16 bytes + DWORD hashSize = sizeof(hashValue); + THROW_IF_WIN32_BOOL_FALSE(CryptGetHashParam(hash.get(), HP_HASHVAL, hashValue, &hashSize, 0)); + + // Copy the hash into a GUID + GUID guid; + memcpy(&guid, hashValue, sizeof(GUID)); + + // TODO: Need to modify genreated bit patterns to fit GUID specification + // like need to specify some bits to make it a valid GUID (maybe v3 or v5) + return guid; + } + + // TODO: use better winrt implementations? + // Challenge: currently winrt based Storage.KnownFolder APIs does not provide all location id we need + winrt::com_ptr GetKnownFolderFromId(winrt::Microsoft::Storage::Pickers::PickerLocationId pickerLocationId) + { + KNOWNFOLDERID knownFolderId; + switch (pickerLocationId) + { + case winrt::Microsoft::Storage::Pickers::PickerLocationId::DocumentsLibrary: + knownFolderId = FOLDERID_Documents; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::ComputerFolder: + knownFolderId = FOLDERID_ComputerFolder; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::Desktop: + knownFolderId = FOLDERID_Desktop; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::Downloads: + knownFolderId = FOLDERID_Downloads; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::HomeGroup: + knownFolderId = FOLDERID_HomeGroup; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::MusicLibrary: + knownFolderId = FOLDERID_MusicLibrary; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::PicturesLibrary: + knownFolderId = FOLDERID_PicturesLibrary; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::VideosLibrary: + knownFolderId = FOLDERID_VideosLibrary; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::Objects3D: + knownFolderId = FOLDERID_Objects3D; + break; + default: + return nullptr; + } + + auto knownFolderManager = winrt::create_instance(CLSID_KnownFolderManager); + winrt::com_ptr knownFolder; + winrt::check_hresult(knownFolderManager->GetFolder(knownFolderId, knownFolder.put())); + winrt::com_ptr defaultFolder; + winrt::check_hresult(knownFolder->GetShellItem(0, IID_PPV_ARGS(defaultFolder.put()))); + return defaultFolder; + } + + + winrt::hstring FormatExtensionWithWildcard(winrt::hstring extension) + { + if (!extension.empty() && extension[0] == L'*') + { + return extension; + } + else + { + return L"*" + extension; + } + } + + winrt::hstring JoinExtensions(winrt::Windows::Foundation::Collections::IVectorView extensions) + { + winrt::hstring result; + bool first = true; + for (const auto& ext : extensions) + { + if (first) + { + result = FormatExtensionWithWildcard(ext); + first = false; + } + else + { + result = result + L";" + FormatExtensionWithWildcard(ext); + } + } + return result; + } + } namespace PickerCommon { - using namespace winrt; - - void ConfigureDialogCommon( - winrt::com_ptr dialog, - winrt::hstring commitButtonText, - winrt::hstring settingIdentifierId, - winrt::Microsoft::Storage::Pickers::PickerLocationId pickerLocationId - ) { - if (!IsHStringNullOrEmpty(commitButtonText)) - { - check_hresult(dialog->SetOkButtonLabel(commitButtonText.c_str())); - } - - if (!IsHStringNullOrEmpty(settingIdentifierId)) { - auto guid = HashHStringToGuid(settingIdentifierId); - check_hresult(dialog->SetClientGuid(guid)); - } - - - auto defaultFolder = GetKnownFolderFromId(pickerLocationId); - if (defaultFolder != nullptr) { - check_hresult(dialog->SetFolder(defaultFolder.get())); - check_hresult(dialog->SetDefaultFolder(defaultFolder.get())); - } - } - - // TODO: better way to convert ShellItem a StorageFile without relying on path?. - winrt::Windows::Foundation::IAsyncOperation CreateStorageFileFromShellItem(winrt::com_ptr shellItem) - { - wil::unique_cotaskmem_string filePath; - check_hresult(shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath)); - auto& result = co_await winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(filePath.get()); - co_return result; - } - - winrt::Windows::Foundation::IAsyncOperation CreateStorageFolderFromShellItem(winrt::com_ptr shellItem) - { - wil::unique_cotaskmem_string filePath; - check_hresult(shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath)); - auto& result = co_await winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(filePath.get()); - co_return result; - } + using namespace winrt; + + // TODO: better way to convert ShellItem a StorageFile without relying on path?. + winrt::Windows::Foundation::IAsyncOperation CreateStorageFileFromShellItem(winrt::com_ptr shellItem) + { + wil::unique_cotaskmem_string filePath; + check_hresult(shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath)); + co_return co_await winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(filePath.get()); + } + + winrt::Windows::Foundation::IAsyncOperation CreateStorageFolderFromShellItem(winrt::com_ptr shellItem) + { + wil::unique_cotaskmem_string filePath; + check_hresult(shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath)); + co_return co_await winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(filePath.get()); + } + + std::vector CaptureFilterSpec(std::vector& buffer, winrt::Windows::Foundation::Collections::IVectorView filters) + { + std::vector result(filters.Size()); + buffer.clear(); + buffer.reserve(filters.Size() * (size_t)2); + for (auto filter : filters) + { + auto ext = FormatExtensionWithWildcard(filter); + buffer.push_back(filter); + buffer.push_back(ext); + } + for (size_t i = 0; i < filters.Size(); i++) + { + result.at(i) = { buffer.at(i * 2).c_str(), buffer.at(i * 2 + 1).c_str() }; + } + return result; + } + + std::vector CaptureFilterSpec(std::vector& buffer, winrt::Windows::Foundation::Collections::IMapView> filters) + { + std::vector result(filters.Size()); + buffer.clear(); + buffer.reserve(filters.Size() * (size_t)2); + + for (const auto& filter : filters) + { + buffer.push_back(filter.Key()); + auto extensionList = JoinExtensions(filter.Value().GetView()); + buffer.push_back(extensionList); + } + for (size_t i = 0; i < filters.Size(); i++) + { + result.at(i) = { buffer.at(i * 2).c_str(), buffer.at(i * 2 + 1).c_str() }; + } + return result; + } + + void PickerParameters::ConfigureDialog(winrt::com_ptr dialog) + { + if (!IsHStringNullOrEmpty(CommitButtonText)) + { + check_hresult(dialog->SetOkButtonLabel(CommitButtonText.c_str())); + } + + if (!IsHStringNullOrEmpty(SettingsIdentifierId)) + { + auto guid = HashHStringToGuid(SettingsIdentifierId); + check_hresult(dialog->SetClientGuid(guid)); + } + + + auto defaultFolder = GetKnownFolderFromId(PickerLocationId); + if (defaultFolder != nullptr) + { + check_hresult(dialog->SetFolder(defaultFolder.get())); + check_hresult(dialog->SetDefaultFolder(defaultFolder.get())); + } + check_hresult(dialog->SetFileTypes(static_cast(FileTypeFilterPara.size()), FileTypeFilterPara.data())); + } } diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h index 13a7b43308..038ba12b81 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h +++ b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h @@ -7,13 +7,20 @@ #pragma once namespace PickerCommon { - void ConfigureDialogCommon( - winrt::com_ptr dialog, - winrt::hstring commitButtonText, - winrt::hstring settingIdentifierId, - winrt::Microsoft::Storage::Pickers::PickerLocationId pickerLocationId - ); + winrt::Windows::Foundation::IAsyncOperation CreateStorageFileFromShellItem(winrt::com_ptr shellItem); + winrt::Windows::Foundation::IAsyncOperation CreateStorageFolderFromShellItem(winrt::com_ptr shellItem); - winrt::Windows::Foundation::IAsyncOperation CreateStorageFileFromShellItem(winrt::com_ptr shellItem); - winrt::Windows::Foundation::IAsyncOperation CreateStorageFolderFromShellItem(winrt::com_ptr shellItem); + std::vector CaptureFilterSpec(std::vector& buffer, winrt::Windows::Foundation::Collections::IVectorView filters); + std::vector CaptureFilterSpec(std::vector& buffer, winrt::Windows::Foundation::Collections::IMapView> filters); + + struct PickerParameters { + HWND HWnd; + winrt::hstring CommitButtonText; + winrt::hstring SettingsIdentifierId; + winrt::Microsoft::Storage::Pickers::PickerLocationId PickerLocationId; + std::vector FileTypeFilterData{}; + std::vector FileTypeFilterPara{}; + + void ConfigureDialog(winrt::com_ptr dialog); + }; } diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp index 0aaccef52f..054d68e36b 100644 --- a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.cpp @@ -130,10 +130,9 @@ namespace winrt::PickerUsageApp::implementation check_hresult(windowNative->get_WindowHandle(&hWnd)); winrt::Windows::Storage::Pickers::FileSavePicker picker{}; - picker.FileTypeChoices().Insert(L"Plain Text", winrt::single_threaded_vector({ L".txt" })); picker.as<::IInitializeWithWindow>()->Initialize(hWnd); - SetPickerOptions(picker); + SetSavePickerOptions(picker); if (!m_MultipleSelect) { @@ -210,7 +209,7 @@ namespace winrt::PickerUsageApp::implementation auto id = AppWindow().Id(); winrt::Microsoft::Storage::Pickers::FileSavePicker picker{ id }; - SetPickerOptions(picker); + SetSavePickerOptions(picker); if (!m_MultipleSelect) { auto& file = co_await picker.PickSaveFileAsync(); diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h index ddb29909fc..53dee22f4f 100644 --- a/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml.h @@ -48,7 +48,7 @@ namespace winrt::PickerUsageApp::implementation // using this template approach helps us ensure use same logic on compatible user facing API - template void SetPickerOptions(TPicker picker) + template void SetCommonPickerOptions(TPicker picker) { if (m_isUseCustomLabel) { @@ -81,7 +81,7 @@ namespace winrt::PickerUsageApp::implementation template void SetOpenPickerOptions(TPicker picker) { - SetPickerOptions(picker); + SetCommonPickerOptions(picker); switch (m_FilterTypeIndex) { case 1: @@ -98,6 +98,12 @@ namespace winrt::PickerUsageApp::implementation break; } } + + template void SetSavePickerOptions(TPicker picker) + { + SetCommonPickerOptions(picker); + picker.FileTypeChoices().Insert(L"Plain Text", winrt::single_threaded_vector({ L".txt" })); + } }; } From 9fcc249c6a584c04e29fbc015a140b21b894f4be Mon Sep 17 00:00:00 2001 From: "Xiang Hong (from Dev Box)" Date: Sat, 7 Dec 2024 22:22:21 +0800 Subject: [PATCH 06/13] refactor: use WinRT MD5 hash string to Guid --- .../PickerCommon.cpp | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp index 577c3d6378..e56b14dbdb 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp +++ b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp @@ -5,6 +5,9 @@ #include #include "winrt/Microsoft.Storage.Pickers.h" #include +#include +#include +#include namespace { bool IsHStringNullOrEmpty(winrt::hstring value) @@ -13,35 +16,28 @@ namespace { return value.empty(); } - // TODO: rewrite use WinRT APIs https://learn.microsoft.com/en-us/uwp/api/windows.security.cryptography.core.hashalgorithmprovider?view=winrt-26100 GUID HashHStringToGuid(winrt::hstring const& input) { - // Convert the hstring to bytes (UTF-16LE encoding) - const BYTE* data = reinterpret_cast(input.data()); - DWORD dataSize = static_cast(input.size() * sizeof(wchar_t)); + auto algorithmProvider = winrt::Windows::Security::Cryptography::Core::HashAlgorithmProvider::OpenAlgorithm(winrt::Windows::Security::Cryptography::Core::HashAlgorithmNames::Md5()); - // Acquire a cryptographic provider context - wil::unique_hcryptprov cryptProv; - THROW_IF_WIN32_BOOL_FALSE(CryptAcquireContextW(&cryptProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)); + auto buffer = winrt::Windows::Security::Cryptography::CryptographicBuffer::ConvertStringToBinary(input, winrt::Windows::Security::Cryptography::BinaryStringEncoding::Utf16LE); - // Create an MD5 hash object - wil::unique_hcrypthash hash; - THROW_IF_WIN32_BOOL_FALSE(CryptCreateHash(cryptProv.get(), CALG_MD5, 0, 0, &hash)); + auto hash = algorithmProvider.HashData(buffer); - // Hash the data - THROW_IF_WIN32_BOOL_FALSE(CryptHashData(hash.get(), data, dataSize, 0)); + if (hash.Length() != 16) + { + throw winrt::hresult_error(E_FAIL, L"Invalid hash length"); + } - // Get the hash value - BYTE hashValue[16]; // MD5 hash is 16 bytes - DWORD hashSize = sizeof(hashValue); - THROW_IF_WIN32_BOOL_FALSE(CryptGetHashParam(hash.get(), HP_HASHVAL, hashValue, &hashSize, 0)); + winrt::com_array resultBuffer{}; + winrt::Windows::Security::Cryptography::CryptographicBuffer::CopyToByteArray(hash, resultBuffer); + GUID guid = *(reinterpret_cast(resultBuffer.data())); - // Copy the hash into a GUID - GUID guid; - memcpy(&guid, hashValue, sizeof(GUID)); + // 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 - // TODO: Need to modify genreated bit patterns to fit GUID specification - // like need to specify some bits to make it a valid GUID (maybe v3 or v5) return guid; } From 3be9dc1194ab01acb78d020b638d6cc2dd5c87b3 Mon Sep 17 00:00:00 2001 From: "Xiang Hong (from Dev Box)" Date: Sun, 8 Dec 2024 10:35:59 +0800 Subject: [PATCH 07/13] clean: code clean on naming styles etc --- .../FileOpenPicker.cpp | 36 +++-- .../FileOpenPicker.h | 11 +- .../FileSavePicker.cpp | 15 +- .../FileSavePicker.h | 16 +- .../FolderPicker.cpp | 150 +++++++++--------- .../Microsoft.Storage.Pickers/FolderPicker.h | 12 +- .../PickerCommon.cpp | 13 +- .../Microsoft.Storage.Pickers/PickerCommon.h | 2 - .../Microsoft.Storage.Pickers/pch.h | 20 ++- 9 files changed, 145 insertions(+), 130 deletions(-) diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp index 38e0ed0c3b..d3d42329d3 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp @@ -16,27 +16,27 @@ namespace winrt::Microsoft::Storage::Pickers::implementation winrt::Microsoft::Storage::Pickers::PickerViewMode FileOpenPicker::ViewMode() { - return m_ViewMode; + return m_viewMode; } void FileOpenPicker::ViewMode(winrt::Microsoft::Storage::Pickers::PickerViewMode const& value) { - m_ViewMode = value; + m_viewMode = value; } hstring FileOpenPicker::SettingsIdentifier() { - return m_SettingsIdentifier; + return m_settingsIdentifier; } void FileOpenPicker::SettingsIdentifier(hstring const& value) { - m_SettingsIdentifier = value; + m_settingsIdentifier = value; } winrt::Microsoft::Storage::Pickers::PickerLocationId FileOpenPicker::SuggestedStartLocation() { - return m_PickerLocationId; + return m_suggestedStartLocation; } void FileOpenPicker::SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value) { - m_PickerLocationId = value; + m_suggestedStartLocation = value; } winrt::hstring FileOpenPicker::CommitButtonText() { @@ -55,8 +55,8 @@ namespace winrt::Microsoft::Storage::Pickers::implementation { parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); parameters.CommitButtonText = m_commitButtonText; - parameters.SettingsIdentifierId = m_SettingsIdentifier; - parameters.PickerLocationId = m_PickerLocationId; + parameters.SettingsIdentifierId = m_settingsIdentifier; + parameters.PickerLocationId = m_suggestedStartLocation; parameters.FileTypeFilterPara = PickerCommon::CaptureFilterSpec(parameters.FileTypeFilterData, m_fileTypeFilter.GetView()); } @@ -81,21 +81,22 @@ namespace winrt::Microsoft::Storage::Pickers::implementation parameters.ConfigureDialog(dialog); - auto hr = dialog->Show(parameters.HWnd); - if (FAILED(hr) || cancellationToken()) { - co_return nullptr; + auto hr = dialog->Show(parameters.HWnd); + if (FAILED(hr) || cancellationToken()) + { + co_return nullptr; + } } winrt::com_ptr shellItem{}; check_hresult(dialog->GetResult(shellItem.put())); - auto file = co_await PickerCommon::CreateStorageFileFromShellItem(shellItem); + if (cancellationToken()) { co_return nullptr; } - co_return file; } @@ -121,10 +122,12 @@ namespace winrt::Microsoft::Storage::Pickers::implementation check_hresult(dialog->SetOptions(FOS_ALLOWMULTISELECT)); - auto hr = dialog->Show(parameters.HWnd); - if (FAILED(hr) || cancellationToken()) { - co_return results.GetView(); + auto hr = dialog->Show(parameters.HWnd); + if (FAILED(hr) || cancellationToken()) + { + co_return results.GetView(); + } } winrt::com_ptr shellItems{}; @@ -146,7 +149,6 @@ namespace winrt::Microsoft::Storage::Pickers::implementation 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 index b4cd94c8dc..fb68a34d2b 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.h +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.h @@ -10,10 +10,13 @@ namespace winrt::Microsoft::Storage::Pickers::implementation 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); @@ -24,12 +27,10 @@ namespace winrt::Microsoft::Storage::Pickers::implementation private: winrt::Microsoft::UI::WindowId m_windowId{}; - winrt::hstring m_SettingsIdentifier{}; - PickerLocationId m_PickerLocationId{ PickerLocationId::Unspecified }; + PickerViewMode m_viewMode{ PickerViewMode::List }; + winrt::hstring m_settingsIdentifier{}; + PickerLocationId m_suggestedStartLocation{ PickerLocationId::Unspecified }; winrt::hstring m_commitButtonText{}; - - PickerViewMode m_ViewMode{ PickerViewMode::List }; - winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ winrt::single_threaded_vector() }; void CaptureParameters(PickerCommon::PickerParameters& parameters); diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp index 65afef1d92..4ddde4b1f2 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp @@ -22,19 +22,19 @@ namespace winrt::Microsoft::Storage::Pickers::implementation } hstring FileSavePicker::SettingsIdentifier() { - return m_SettingsIdentifier; + return m_settingsIdentifier; } void FileSavePicker::SettingsIdentifier(hstring const& value) { - m_SettingsIdentifier = value; + m_settingsIdentifier = value; } winrt::Microsoft::Storage::Pickers::PickerLocationId FileSavePicker::SuggestedStartLocation() { - return m_PickerLocationId; + return m_suggestedStartLocation; } void FileSavePicker::SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value) { - m_PickerLocationId = value; + m_suggestedStartLocation = value; } hstring FileSavePicker::CommitButtonText() { @@ -78,8 +78,8 @@ namespace winrt::Microsoft::Storage::Pickers::implementation { parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); parameters.CommitButtonText = m_commitButtonText; - parameters.SettingsIdentifierId = m_SettingsIdentifier; - parameters.PickerLocationId = m_PickerLocationId; + parameters.SettingsIdentifierId = m_settingsIdentifier; + parameters.PickerLocationId = m_suggestedStartLocation; parameters.FileTypeFilterPara = PickerCommon::CaptureFilterSpec(parameters.FileTypeFilterData, m_fileTypeChoices.GetView()); } @@ -108,13 +108,12 @@ namespace winrt::Microsoft::Storage::Pickers::implementation winrt::com_ptr shellItem{}; check_hresult(dialog->GetResult(shellItem.put())); - auto file = co_await PickerCommon::CreateStorageFileFromShellItem(shellItem); + if (cancellationToken()) { co_return nullptr; } - co_return file; } } diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h index da7218dec1..2144f51292 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h @@ -9,30 +9,38 @@ namespace winrt::Microsoft::Storage::Pickers::implementation struct FileSavePicker : FileSavePickerT { FileSavePicker(winrt::Microsoft::UI::WindowId const& windowId); + hstring SettingsIdentifier(); void SettingsIdentifier(hstring const& value); + winrt::Microsoft::Storage::Pickers::PickerLocationId SuggestedStartLocation(); void SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value); + hstring CommitButtonText(); void CommitButtonText(hstring const& value); + winrt::Windows::Foundation::Collections::IMap> FileTypeChoices(); + hstring DefaultFileExtension(); void DefaultFileExtension(hstring const& value); + winrt::Windows::Storage::StorageFile SuggestedSaveFile(); void SuggestedSaveFile(winrt::Windows::Storage::StorageFile const& value); + hstring SuggestedFileName(); void SuggestedFileName(hstring const& value); + winrt::Windows::Foundation::IAsyncOperation PickSaveFileAsync(); + private: winrt::Microsoft::UI::WindowId m_windowId{}; - - hstring m_SettingsIdentifier{}; - PickerLocationId m_PickerLocationId{ PickerLocationId::Unspecified }; + hstring m_settingsIdentifier{}; + PickerLocationId m_suggestedStartLocation{ PickerLocationId::Unspecified }; hstring m_commitButtonText{}; + winrt::Windows::Foundation::Collections::IMap> m_fileTypeChoices{ winrt::single_threaded_map>() }; hstring m_defaultFileExtension{}; winrt::Windows::Storage::StorageFile m_suggestedSaveFile{ nullptr }; hstring m_suggestedFileName{}; - winrt::Windows::Foundation::Collections::IMap> m_fileTypeChoices{ winrt::single_threaded_map>() }; void CaptureParameters(PickerCommon::PickerParameters& parameters); }; diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp index b650361dda..6e7c62d0be 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp @@ -8,89 +8,91 @@ 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_PickerLocationId; - } - void FolderPicker::SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value) - { - m_PickerLocationId = value; - } - hstring FolderPicker::CommitButtonText() - { - return m_commitButtonText; - } - void FolderPicker::CommitButtonText(hstring const& value) - { - m_commitButtonText = value; - } - winrt::Windows::Foundation::Collections::IVector FolderPicker::FileTypeFilter() - { - return m_fileTypeFilter; - } + FolderPicker::FolderPicker(winrt::Microsoft::UI::WindowId const& windowId) + : m_windowId(windowId) + { + } + winrt::Microsoft::Storage::Pickers::PickerViewMode FolderPicker::ViewMode() + { + return m_viewMode; + } + void FolderPicker::ViewMode(winrt::Microsoft::Storage::Pickers::PickerViewMode const& value) + { + m_viewMode = value; + } + hstring FolderPicker::SettingsIdentifier() + { + return m_settingsIdentifier; + } + void FolderPicker::SettingsIdentifier(hstring const& value) + { + m_settingsIdentifier = value; + } + winrt::Microsoft::Storage::Pickers::PickerLocationId FolderPicker::SuggestedStartLocation() + { + return m_suggestedStartLocation; + } + void FolderPicker::SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value) + { + m_suggestedStartLocation = value; + } + hstring FolderPicker::CommitButtonText() + { + return m_commitButtonText; + } + void FolderPicker::CommitButtonText(hstring const& value) + { + m_commitButtonText = value; + } + winrt::Windows::Foundation::Collections::IVector FolderPicker::FileTypeFilter() + { + return m_fileTypeFilter; + } - void FolderPicker::CaptureParameters(PickerCommon::PickerParameters& parameters) { - parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); - parameters.CommitButtonText = m_commitButtonText; - parameters.SettingsIdentifierId = m_SettingsIdentifier; - parameters.PickerLocationId = m_PickerLocationId; + void FolderPicker::CaptureParameters(PickerCommon::PickerParameters& parameters) + { + parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); + parameters.CommitButtonText = m_commitButtonText; + parameters.SettingsIdentifierId = m_settingsIdentifier; + parameters.PickerLocationId = m_suggestedStartLocation; parameters.FileTypeFilterPara = PickerCommon::CaptureFilterSpec(parameters.FileTypeFilterData, m_fileTypeFilter.GetView()); - } + } - winrt::Windows::Foundation::IAsyncOperation FolderPicker::PickSingleFolderAsync() - { - PickerCommon::PickerParameters parameters{}; - CaptureParameters(parameters); + winrt::Windows::Foundation::IAsyncOperation FolderPicker::PickSingleFolderAsync() + { + PickerCommon::PickerParameters parameters{}; + CaptureParameters(parameters); - co_await winrt::resume_background(); + co_await winrt::resume_background(); - auto cancellationToken = co_await winrt::get_cancellation_token(); - if (cancellationToken()) - { - co_return nullptr; - } + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return nullptr; + } - auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL); + auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL); - parameters.ConfigureDialog(dialog); - dialog->SetOptions(FOS_PICKFOLDERS); + parameters.ConfigureDialog(dialog); + dialog->SetOptions(FOS_PICKFOLDERS); - auto hr = dialog->Show(parameters.HWnd); - if (FAILED(hr) || cancellationToken()) - { - co_return nullptr; - } + { + auto hr = dialog->Show(parameters.HWnd); + if (FAILED(hr) || cancellationToken()) + { + co_return nullptr; + } + } - winrt::com_ptr shellItem{}; - check_hresult(dialog->GetResult(shellItem.put())); + winrt::com_ptr shellItem{}; + check_hresult(dialog->GetResult(shellItem.put())); + auto folder = co_await PickerCommon::CreateStorageFolderFromShellItem(shellItem); - auto folder = co_await PickerCommon::CreateStorageFolderFromShellItem(shellItem); - if (cancellationToken()) - { - co_return nullptr; - } - - co_return folder; - } + 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 index 1b599ae0f3..56af65cb19 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h @@ -7,23 +7,29 @@ namespace winrt::Microsoft::Storage::Pickers::implementation struct FolderPicker : FolderPickerT { FolderPicker(winrt::Microsoft::UI::WindowId const& windowId); + winrt::Microsoft::Storage::Pickers::PickerViewMode ViewMode(); void ViewMode(winrt::Microsoft::Storage::Pickers::PickerViewMode const& value); + hstring SettingsIdentifier(); void SettingsIdentifier(hstring const& value); + winrt::Microsoft::Storage::Pickers::PickerLocationId SuggestedStartLocation(); void SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value); + hstring CommitButtonText(); void CommitButtonText(hstring const& value); + winrt::Windows::Foundation::Collections::IVector FileTypeFilter(); + winrt::Windows::Foundation::IAsyncOperation PickSingleFolderAsync(); private: winrt::Microsoft::UI::WindowId m_windowId{}; - PickerViewMode m_ViewMode{ PickerViewMode::List }; - hstring m_SettingsIdentifier{}; - PickerLocationId m_PickerLocationId{ PickerLocationId::Unspecified }; + PickerViewMode m_viewMode{ PickerViewMode::List }; + hstring m_settingsIdentifier{}; + PickerLocationId m_suggestedStartLocation{ PickerLocationId::Unspecified }; hstring m_commitButtonText{}; winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ winrt::single_threaded_vector() }; diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp index e56b14dbdb..297e4de096 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp +++ b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp @@ -2,12 +2,7 @@ #include "PickerCommon.h" #include #include "ShObjIdl.h" -#include -#include "winrt/Microsoft.Storage.Pickers.h" #include -#include -#include -#include namespace { bool IsHStringNullOrEmpty(winrt::hstring value) @@ -80,9 +75,9 @@ namespace { } auto knownFolderManager = winrt::create_instance(CLSID_KnownFolderManager); - winrt::com_ptr knownFolder; + winrt::com_ptr knownFolder{}; winrt::check_hresult(knownFolderManager->GetFolder(knownFolderId, knownFolder.put())); - winrt::com_ptr defaultFolder; + winrt::com_ptr defaultFolder{}; winrt::check_hresult(knownFolder->GetShellItem(0, IID_PPV_ARGS(defaultFolder.put()))); return defaultFolder; } @@ -191,13 +186,13 @@ namespace PickerCommon { 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(static_cast(FileTypeFilterPara.size()), FileTypeFilterPara.data())); + + 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 index 038ba12b81..0dd945f5ce 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h +++ b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h @@ -4,8 +4,6 @@ #include "ShObjIdl.h" #include "winrt/Microsoft.Storage.Pickers.h" -#pragma once - namespace PickerCommon { winrt::Windows::Foundation::IAsyncOperation CreateStorageFileFromShellItem(winrt::com_ptr shellItem); winrt::Windows::Foundation::IAsyncOperation CreateStorageFolderFromShellItem(winrt::com_ptr shellItem); diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/pch.h b/prototype-workingdir/Microsoft.Storage.Pickers/pch.h index a70ce5f978..21563b73b3 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/pch.h +++ b/prototype-workingdir/Microsoft.Storage.Pickers/pch.h @@ -8,11 +8,12 @@ // conflict with Storyboard::GetCurrentTime #undef GetCurrentTime -#include -#include -#include -#include + +#include "winrt/Microsoft.Storage.Pickers.h" +#include #include +#include +#include #include #include #include @@ -22,8 +23,11 @@ #include #include #include -#include -#include -#include +#include +#include +#include +#include +#include #include -#include +#include +#include From c17750f2fd2f4282b3b3228a97cb0df8394e6b3b Mon Sep 17 00:00:00 2001 From: "Xiang Hong (from Dev Box)" Date: Sun, 8 Dec 2024 11:27:04 +0800 Subject: [PATCH 08/13] feature: add basic implementations for SavePickers FileExtension/SuggestedSaveFile/Name functionalities --- .../FileSavePicker.cpp | 19 +++++++++++++++++++ .../Microsoft.Storage.Pickers.vcxproj | 3 +++ .../Microsoft.Storage.Pickers.vcxproj.filters | 3 --- .../PickerCommon.cpp | 12 +++++++----- .../Microsoft.Storage.Pickers/PickerCommon.h | 3 +++ 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp index 4ddde4b1f2..052135bf98 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp @@ -81,12 +81,16 @@ namespace winrt::Microsoft::Storage::Pickers::implementation parameters.SettingsIdentifierId = m_settingsIdentifier; parameters.PickerLocationId = m_suggestedStartLocation; parameters.FileTypeFilterPara = PickerCommon::CaptureFilterSpec(parameters.FileTypeFilterData, m_fileTypeChoices.GetView()); + } winrt::Windows::Foundation::IAsyncOperation FileSavePicker::PickSaveFileAsync() { PickerCommon::PickerParameters parameters{}; CaptureParameters(parameters); + auto defaultFileExtension = m_defaultFileExtension; + auto suggestedSaveFile = m_suggestedSaveFile; + auto suggestedFileName = m_suggestedFileName; co_await winrt::resume_background(); auto cancellationToken = co_await winrt::get_cancellation_token(); @@ -98,6 +102,21 @@ namespace winrt::Microsoft::Storage::Pickers::implementation auto dialog = create_instance(CLSID_FileSaveDialog, CONTEXT_ALL); parameters.ConfigureDialog(dialog); + if (!PickerCommon::IsHStringNullOrEmpty(defaultFileExtension)) + { + check_hresult(dialog->SetDefaultExtension(defaultFileExtension.c_str())); + } + if (!PickerCommon::IsHStringNullOrEmpty(suggestedFileName)) + { + check_hresult(dialog->SetFileName(suggestedFileName.c_str())); + } + if (suggestedSaveFile != nullptr) + { + winrt::com_ptr shellItem; + check_hresult(SHCreateItemFromParsingName(suggestedSaveFile.Path().c_str(), nullptr, IID_PPV_ARGS(shellItem.put()))); + check_hresult(dialog->SetSaveAsItem(shellItem.get())); + } + { auto hr = dialog->Show(parameters.HWnd); if (FAILED(hr)) diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj index f5d1f51ae8..9a03b1c73b 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj +++ b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj @@ -93,6 +93,9 @@ _DEBUG;%(PreprocessorDefinitions) + + $(CoreLibraryDependencies);%(AdditionalDependencies);shell32.lib + diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj.filters b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj.filters index 71954b81d9..af63f3cf8e 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj.filters +++ b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj.filters @@ -34,7 +34,4 @@ - - - \ No newline at end of file diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp index 297e4de096..63e29b7ebf 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp +++ b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp @@ -5,11 +5,6 @@ #include namespace { - bool IsHStringNullOrEmpty(winrt::hstring value) - { - // TODO: proper handling of null string reference? - return value.empty(); - } GUID HashHStringToGuid(winrt::hstring const& input) { @@ -121,6 +116,13 @@ namespace PickerCommon { using namespace winrt; + bool IsHStringNullOrEmpty(winrt::hstring value) + { + // TODO: proper handling of null string reference? + return value.empty(); + } + + // TODO: better way to convert ShellItem a StorageFile without relying on path?. winrt::Windows::Foundation::IAsyncOperation CreateStorageFileFromShellItem(winrt::com_ptr shellItem) { diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h index 0dd945f5ce..de7db7ac54 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h +++ b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h @@ -11,6 +11,9 @@ namespace PickerCommon { std::vector CaptureFilterSpec(std::vector& buffer, winrt::Windows::Foundation::Collections::IVectorView filters); std::vector CaptureFilterSpec(std::vector& buffer, winrt::Windows::Foundation::Collections::IMapView> filters); + // TODO: remove this if we know proper and null safe empty test for string + bool IsHStringNullOrEmpty(winrt::hstring value); + struct PickerParameters { HWND HWnd; winrt::hstring CommitButtonText; From c6966f34805ce56b85f6d14d35e8fe29304fc4a9 Mon Sep 17 00:00:00 2001 From: "Xiang Hong (from Dev Box)" Date: Sun, 8 Dec 2024 20:08:46 +0800 Subject: [PATCH 09/13] add a simple READEME --- prototype-workingdir/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 prototype-workingdir/README.md diff --git a/prototype-workingdir/README.md b/prototype-workingdir/README.md new file mode 100644 index 0000000000..5166eb1ec6 --- /dev/null +++ b/prototype-workingdir/README.md @@ -0,0 +1,24 @@ +# 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. + +## Current State + +- Basic implementation of most core functionalities was added. +- A basic demo app for testing and comparing purpose was added. + +### 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? + + + From e11c8e60e993ea9712970da4cc2ba5ca9c27013b Mon Sep 17 00:00:00 2001 From: "Xiang Hong (from Dev Box)" Date: Sun, 8 Dec 2024 20:54:23 +0800 Subject: [PATCH 10/13] update readme for folder description --- prototype-workingdir/PickerUsageApp/MainWindow.xaml | 2 +- prototype-workingdir/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/prototype-workingdir/PickerUsageApp/MainWindow.xaml b/prototype-workingdir/PickerUsageApp/MainWindow.xaml index adc4847337..d1d606df21 100644 --- a/prototype-workingdir/PickerUsageApp/MainWindow.xaml +++ b/prototype-workingdir/PickerUsageApp/MainWindow.xaml @@ -52,7 +52,7 @@ - !!! WARN !!! Save picker will overwrite Context in selected file with test data + diff --git a/prototype-workingdir/README.md b/prototype-workingdir/README.md index 5166eb1ec6..aa7ecaa38b 100644 --- a/prototype-workingdir/README.md +++ b/prototype-workingdir/README.md @@ -4,8 +4,8 @@ This folder contains prototype implementations for adding types in `Storage.Pick ## Current State -- Basic implementation of most core functionalities was added. -- A basic demo app for testing and comparing purpose was added. +- 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. From ff3f2a8aa226a9d2435c99b113c11fad722f090d Mon Sep 17 00:00:00 2001 From: Xiang Hong Date: Mon, 9 Dec 2024 18:14:16 +0800 Subject: [PATCH 11/13] fix: fix project configuration and add certificate notes to README.md --- .../Microsoft.Storage.Pickers.vcxproj | 3 ++- prototype-workingdir/README.md | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj index 9a03b1c73b..b1b1eaf438 100644 --- a/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj +++ b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj @@ -94,7 +94,7 @@ _DEBUG;%(PreprocessorDefinitions) - $(CoreLibraryDependencies);%(AdditionalDependencies);shell32.lib + $(CoreLibraryDependencies);%(AdditionalDependencies);shell32.lib @@ -104,6 +104,7 @@ true true + $(CoreLibraryDependencies);%(AdditionalDependencies);shell32.lib diff --git a/prototype-workingdir/README.md b/prototype-workingdir/README.md index aa7ecaa38b..3d9d6793a6 100644 --- a/prototype-workingdir/README.md +++ b/prototype-workingdir/README.md @@ -2,6 +2,8 @@ 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/`. From bbf72f8edecc9a4b74bf61bfb5ab5f8c72b0956f Mon Sep 17 00:00:00 2001 From: Dinah Gao <116714259+DinahK-2SO@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:01:23 +0800 Subject: [PATCH 12/13] Microsoft.Windows.Storage.Pickers.FileOpenPicker.PickSingleFileAsync (#4945) Creating new API Microsoft.Windows.Storage.Pickers.FileOpenPicker.PickSingleFileAsync --- WindowsAppRuntime.sln | 19 ++++++ build/CopyFilesToStagingDir.ps1 | 4 ++ build/NuSpecs/AppxManifest.xml | 3 + .../WindowsAppSDK-Nuget-Native.WinRt.props | 6 ++ .../WindowsAppSDK-Nuget-Native.targets | 8 +++ dev/Interop/StoragePicker/FileOpenPicker.cpp | 58 +++++++++++++++++++ dev/Interop/StoragePicker/FileOpenPicker.h | 19 ++++++ dev/Interop/StoragePicker/FileOpenPicker.idl | 13 +++++ .../StoragePicker/StoragePicker.vcxitems | 25 ++++++++ ....Windows.Storage.Pickers.Projection.csproj | 58 +++++++++++++++++++ .../WindowsAppRuntime_DLL.vcxproj | 1 + 11 files changed, 214 insertions(+) create mode 100644 dev/Interop/StoragePicker/FileOpenPicker.cpp create mode 100644 dev/Interop/StoragePicker/FileOpenPicker.h create mode 100644 dev/Interop/StoragePicker/FileOpenPicker.idl create mode 100644 dev/Interop/StoragePicker/StoragePicker.vcxitems create mode 100644 dev/Projections/CS/Microsoft.Windows.Storage.Pickers.Projection/Microsoft.Windows.Storage.Pickers.Projection.csproj diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln index 266ae49a34..2e644489bd 100644 --- a/WindowsAppRuntime.sln +++ b/WindowsAppRuntime.sln @@ -566,6 +566,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IXP", "IXP", "{7B323048-439 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IXP.TransportPackage.PackageReference", "eng\PackageReference\IXP\IXP.TransportPackage.PackageReference.csproj", "{A949149D-29CA-4AA7-B1ED-0E571B4AD9BB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Windows.Storage.Pickers.Projection", "dev\Projections\CS\Microsoft.Windows.Storage.Pickers.Projection\Microsoft.Windows.Storage.Pickers.Projection.csproj", "{8E01AA4F-A16A-4E3F-A59F-6D49422B4410}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -2002,6 +2004,22 @@ Global {A949149D-29CA-4AA7-B1ED-0E571B4AD9BB}.Release|x64.Build.0 = Release|x64 {A949149D-29CA-4AA7-B1ED-0E571B4AD9BB}.Release|x86.ActiveCfg = Release|x86 {A949149D-29CA-4AA7-B1ED-0E571B4AD9BB}.Release|x86.Build.0 = Release|x86 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|Any CPU.ActiveCfg = Debug|x64 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|Any CPU.Build.0 = Debug|x64 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|ARM64.ActiveCfg = Debug|arm64 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|ARM64.Build.0 = Debug|arm64 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|x64.ActiveCfg = Debug|x64 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|x64.Build.0 = Debug|x64 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|x86.ActiveCfg = Debug|x86 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Debug|x86.Build.0 = Debug|x86 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|Any CPU.ActiveCfg = Release|x64 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|Any CPU.Build.0 = Release|x64 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|ARM64.ActiveCfg = Release|arm64 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|ARM64.Build.0 = Release|arm64 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|x64.ActiveCfg = Release|x64 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|x64.Build.0 = Release|x64 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|x86.ActiveCfg = Release|x86 + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2181,6 +2199,7 @@ Global {D5958784-4518-44F1-A518-80514B380ED5} = {E24C263A-DE3E-4844-BA50-842DA5AD7A49} {7B323048-439F-47E9-A3D4-7342C5ADE2A5} = {5C88AE1D-AC20-4A41-9299-1EEA15B80724} {A949149D-29CA-4AA7-B1ED-0E571B4AD9BB} = {7B323048-439F-47E9-A3D4-7342C5ADE2A5} + {8E01AA4F-A16A-4E3F-A59F-6D49422B4410} = {716C26A0-E6B0-4981-8412-D14A4D410531} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4B3D7591-CFEC-4762-9A07-ABE99938FB77} diff --git a/build/CopyFilesToStagingDir.ps1 b/build/CopyFilesToStagingDir.ps1 index 3c261aaac2..656d6e5e88 100644 --- a/build/CopyFilesToStagingDir.ps1 +++ b/build/CopyFilesToStagingDir.ps1 @@ -55,6 +55,7 @@ PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windo PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.AppNotifications.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\ PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Management.Deployment.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\ PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Media.Capture.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\ +PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Storage.Pickers.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\ PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.PushNotifications.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\ PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Security.AccessControl.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\ PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Security.Authentication.OAuth.winmd $FullPublishDir\Microsoft.WindowsAppRuntime\ @@ -126,6 +127,8 @@ PublishFile $FullBuildOutput\Microsoft.Windows.Management.Deployment.Projection\ PublishFile $FullBuildOutput\Microsoft.Windows.Management.Deployment.Projection\Microsoft.Windows.Management.Deployment.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0 PublishFile $FullBuildOutput\Microsoft.Windows.Media.Capture.Projection\Microsoft.Windows.Media.Capture.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0 PublishFile $FullBuildOutput\Microsoft.Windows.Media.Capture.Projection\Microsoft.Windows.Media.Capture.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0 +PublishFile $FullBuildOutput\Microsoft.Windows.Storage.Pickers.Projection\Microsoft.Windows.Storage.Pickers.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0 +PublishFile $FullBuildOutput\Microsoft.Windows.Storage.Pickers.Projection\Microsoft.Windows.Storage.Pickers.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0 PublishFile $FullBuildOutput\Microsoft.Windows.PushNotifications.Projection\Microsoft.Windows.PushNotifications.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0 PublishFile $FullBuildOutput\Microsoft.Windows.PushNotifications.Projection\Microsoft.Windows.PushNotifications.Projection.pdb $NugetDir\lib\net6.0-windows10.0.17763.0 PublishFile $FullBuildOutput\Microsoft.Windows.Security.AccessControl.Projection\Microsoft.Windows.Security.AccessControl.Projection.dll $NugetDir\lib\net6.0-windows10.0.17763.0 @@ -202,6 +205,7 @@ PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windo PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.AppNotifications.winmd $NugetDir\lib\uap10.0 PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Management.Deployment.winmd $NugetDir\lib\uap10.0 PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Media.Capture.winmd $NugetDir\lib\uap10.0 +PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Storage.Pickers.winmd $NugetDir\lib\uap10.0 PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.PushNotifications.winmd $NugetDir\lib\uap10.0 PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Security.AccessControl.winmd $NugetDir\lib\uap10.0 PublishFile $FullBuildOutput\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Security.Authentication.OAuth.winmd $NugetDir\lib\uap10.0 diff --git a/build/NuSpecs/AppxManifest.xml b/build/NuSpecs/AppxManifest.xml index e079468216..2ee96bb190 100644 --- a/build/NuSpecs/AppxManifest.xml +++ b/build/NuSpecs/AppxManifest.xml @@ -111,6 +111,9 @@ + + + diff --git a/build/NuSpecs/WindowsAppSDK-Nuget-Native.WinRt.props b/build/NuSpecs/WindowsAppSDK-Nuget-Native.WinRt.props index 88fede76fd..02b59d588d 100644 --- a/build/NuSpecs/WindowsAppSDK-Nuget-Native.WinRt.props +++ b/build/NuSpecs/WindowsAppSDK-Nuget-Native.WinRt.props @@ -75,6 +75,12 @@ $(MSBuildThisFileDirectory)..\..\runtimes\win10-$(_WindowsAppSDKFoundationPlatform)\native\Microsoft.WindowsAppRuntime.dll true + + $(MSBuildThisFileDirectory)..\..\lib\uap10.0\Microsoft.Windows.Storage.Pickers.winmd + $(MSBuildThisFileDirectory)..\..\runtimes\win10-$(_WindowsAppSDKFoundationPlatform)\native\Microsoft.WindowsAppRuntime.dll + true + diff --git a/build/NuSpecs/WindowsAppSDK-Nuget-Native.targets b/build/NuSpecs/WindowsAppSDK-Nuget-Native.targets index c18bdb650a..7057bff1ae 100644 --- a/build/NuSpecs/WindowsAppSDK-Nuget-Native.targets +++ b/build/NuSpecs/WindowsAppSDK-Nuget-Native.targets @@ -135,6 +135,14 @@ + + + false + Microsoft.WindowsAppRuntime.dll + + + diff --git a/dev/Interop/StoragePicker/FileOpenPicker.cpp b/dev/Interop/StoragePicker/FileOpenPicker.cpp new file mode 100644 index 0000000000..08b869f9e8 --- /dev/null +++ b/dev/Interop/StoragePicker/FileOpenPicker.cpp @@ -0,0 +1,58 @@ +// 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 +#include +#include +#include +#include + +namespace winrt::Microsoft::Windows::Storage::Pickers::implementation +{ + winrt::Windows::Foundation::IAsyncOperation FileOpenPicker::PickSingleFileAsync() + { + winrt::apartment_context ui_thread; + + co_await winrt::resume_background(); + + // Handle cancellation. + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return nullptr; + } + + // TODO: should we initialize COM? + //wil::com_initialize_ex initializeCom{ COINIT_APARTMENTTHREADED }; + + wil::com_ptr fileOpenDialog; + THROW_IF_FAILED(CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&fileOpenDialog))); + + HRESULT hr = fileOpenDialog->Show(nullptr); + if (FAILED(hr) || cancellationToken()) + { + co_return nullptr; + } + + wil::com_ptr shellItem; + THROW_IF_FAILED(fileOpenDialog->GetResult(shellItem.put())); + + wil::unique_cotaskmem_string filePath; + THROW_IF_FAILED(shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath)); + + // Convert the file path to a StorageFile. + auto const& file = co_await winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(filePath.get()); + if (cancellationToken()) { + co_return nullptr; + } + + co_await ui_thread; + if (cancellationToken()) { + co_return nullptr; + } + + co_return file; + } +} diff --git a/dev/Interop/StoragePicker/FileOpenPicker.h b/dev/Interop/StoragePicker/FileOpenPicker.h new file mode 100644 index 0000000000..1a9665cb71 --- /dev/null +++ b/dev/Interop/StoragePicker/FileOpenPicker.h @@ -0,0 +1,19 @@ +// 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" + +namespace winrt::Microsoft::Windows::Storage::Pickers::implementation +{ + struct FileOpenPicker : FileOpenPickerT + { + FileOpenPicker() = default; + winrt::Windows::Foundation::IAsyncOperation PickSingleFileAsync(); + }; +} +namespace winrt::Microsoft::Windows::Storage::Pickers::factory_implementation +{ + struct FileOpenPicker : FileOpenPickerT + { + }; +} diff --git a/dev/Interop/StoragePicker/FileOpenPicker.idl b/dev/Interop/StoragePicker/FileOpenPicker.idl new file mode 100644 index 0000000000..0af9f685ef --- /dev/null +++ b/dev/Interop/StoragePicker/FileOpenPicker.idl @@ -0,0 +1,13 @@ +namespace Microsoft.Windows.Storage.Pickers +{ + [contractversion(1)] + apicontract FileOpenPickerContract {}; + + [contract(FileOpenPickerContract, 1)] + runtimeclass FileOpenPicker + { + FileOpenPicker(); + + Windows.Foundation.IAsyncOperation PickSingleFileAsync(); + }; +} diff --git a/dev/Interop/StoragePicker/StoragePicker.vcxitems b/dev/Interop/StoragePicker/StoragePicker.vcxitems new file mode 100644 index 0000000000..f49e671656 --- /dev/null +++ b/dev/Interop/StoragePicker/StoragePicker.vcxitems @@ -0,0 +1,25 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {a39e7b2f-5f67-47dd-8443-531d095ca7f3} + + + + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dev/Projections/CS/Microsoft.Windows.Storage.Pickers.Projection/Microsoft.Windows.Storage.Pickers.Projection.csproj b/dev/Projections/CS/Microsoft.Windows.Storage.Pickers.Projection/Microsoft.Windows.Storage.Pickers.Projection.csproj new file mode 100644 index 0000000000..a13846ff90 --- /dev/null +++ b/dev/Projections/CS/Microsoft.Windows.Storage.Pickers.Projection/Microsoft.Windows.Storage.Pickers.Projection.csproj @@ -0,0 +1,58 @@ + + + net6.0-windows10.0.17763.0 + 10.0.17763.0 + x64;x86;arm64 + AnyCPU + false + + + + true + true + + + + + 8305 + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + Microsoft.Windows.Storage.Pickers + 10.0.17763.0 + false + + + + + pdbonly + true + + + + + + + + + + + + + $(OutDir)..\WindowsAppRuntime_DLL\StrippedWinMD\Microsoft.Windows.Storage.Pickers.winmd + true + + + diff --git a/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj b/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj index 62e67cef13..75db43c1f0 100644 --- a/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj +++ b/dev/WindowsAppRuntime_DLL/WindowsAppRuntime_DLL.vcxproj @@ -102,6 +102,7 @@ + From 116f56ae98e93762869fbfc8fb7e6691e45aa119 Mon Sep 17 00:00:00 2001 From: Dinah Gao <116714259+DinahK-2SO@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:30:19 +0800 Subject: [PATCH 13/13] add one telemetry (#4954) --- dev/Interop/StoragePicker/FileOpenPicker.cpp | 5 ++++ dev/Interop/StoragePicker/FileOpenPicker.h | 5 ++++ .../StoragePicker/StoragePickersTelemetry.h | 29 +++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 dev/Interop/StoragePicker/StoragePickersTelemetry.h diff --git a/dev/Interop/StoragePicker/FileOpenPicker.cpp b/dev/Interop/StoragePicker/FileOpenPicker.cpp index 08b869f9e8..9684ff2f98 100644 --- a/dev/Interop/StoragePicker/FileOpenPicker.cpp +++ b/dev/Interop/StoragePicker/FileOpenPicker.cpp @@ -3,6 +3,7 @@ #include "pch.h" #include "FileOpenPicker.h" #include "Microsoft.Windows.Storage.Pickers.FileOpenPicker.g.cpp" +#include "StoragePickersTelemetry.h" #include #include #include @@ -13,6 +14,10 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation { winrt::Windows::Foundation::IAsyncOperation FileOpenPicker::PickSingleFileAsync() { + bool isAppPackaged = m_telemetryHelper.IsPackagedApp(); + PCWSTR appName = m_telemetryHelper.GetAppName().c_str(); + auto logCaptureOperation{ StoragePickersTelemetry::StoragePickersOperation::Start(isAppPackaged, appName) }; + winrt::apartment_context ui_thread; co_await winrt::resume_background(); diff --git a/dev/Interop/StoragePicker/FileOpenPicker.h b/dev/Interop/StoragePicker/FileOpenPicker.h index 1a9665cb71..c97752674f 100644 --- a/dev/Interop/StoragePicker/FileOpenPicker.h +++ b/dev/Interop/StoragePicker/FileOpenPicker.h @@ -2,6 +2,7 @@ // 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 { @@ -9,8 +10,12 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation { FileOpenPicker() = default; winrt::Windows::Foundation::IAsyncOperation PickSingleFileAsync(); + + private: + TelemetryHelper m_telemetryHelper; }; } + namespace winrt::Microsoft::Windows::Storage::Pickers::factory_implementation { struct FileOpenPicker : FileOpenPickerT diff --git a/dev/Interop/StoragePicker/StoragePickersTelemetry.h b/dev/Interop/StoragePicker/StoragePickersTelemetry.h new file mode 100644 index 0000000000..beff1e2a22 --- /dev/null +++ b/dev/Interop/StoragePicker/StoragePickersTelemetry.h @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once +#include "..\WindowsAppRuntime_Insights\WindowsAppRuntimeInsights.h" +#include + +DECLARE_TRACELOGGING_CLASS(StoragePickersTelemetryProvider, + "Microsoft.WindowsAppSDK.StoragePickersTelemetry", + // {3be0d45f-3a9d-46be-a1cf-b08465473cc4} + (0x3be0d45f, 0x3a9d, 0x46be, 0xa1, 0xcf, 0xb0, 0x84, 0x65, 0x47, 0x3c, 0xc4)); + +class StoragePickersTelemetry : public wil::TraceLoggingProvider +{ + IMPLEMENT_TELEMETRY_CLASS(StoragePickersTelemetry, StoragePickersTelemetryProvider); + +public: + BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(StoragePickersOperation, PDT_ProductAndServicePerformance); + DEFINE_ACTIVITY_START(bool isAppPackaged, PCWSTR appName) noexcept try + { + TraceLoggingClassWriteStart( + StoragePickersOperation, + _GENERIC_PARTB_FIELDS_ENABLED, + TraceLoggingBool(isAppPackaged, "IsAppPackaged"), + TraceLoggingWideString(appName, "AppName")); + } + CATCH_LOG() + END_ACTIVITY_CLASS(); +}; \ No newline at end of file