From e6997b5962f46de7bee95646ccd97114f9fbb4df Mon Sep 17 00:00:00 2001 From: Dinah Gao Date: Thu, 12 Dec 2024 14:41:49 +0800 Subject: [PATCH] Merge codes from branch 'user/xianghong/pickers-prototype' at \prototype-workingdir\Microsoft.Storage.Pickers Squashed commit of the following: commit 4ce840f9aedef32b3312cde280318bd170223c99 Author: Dinah Gao Date: Wed Dec 11 15:00:41 2024 +0800 add one telemetry commit bbf72f8edecc9a4b74bf61bfb5ab5f8c72b0956f Author: Dinah Gao <116714259+DinahK-2SO@users.noreply.github.com> Date: Tue Dec 10 11:01:23 2024 +0800 Microsoft.Windows.Storage.Pickers.FileOpenPicker.PickSingleFileAsync (#4945) Creating new API Microsoft.Windows.Storage.Pickers.FileOpenPicker.PickSingleFileAsync commit ff3f2a8aa226a9d2435c99b113c11fad722f090d Author: Xiang Hong Date: Mon Dec 9 18:14:16 2024 +0800 fix: fix project configuration and add certificate notes to README.md commit e11c8e60e993ea9712970da4cc2ba5ca9c27013b Author: Xiang Hong (from Dev Box) Date: Sun Dec 8 20:54:23 2024 +0800 update readme for folder description commit c6966f34805ce56b85f6d14d35e8fe29304fc4a9 Author: Xiang Hong (from Dev Box) Date: Sun Dec 8 20:08:46 2024 +0800 add a simple READEME commit c17750f2fd2f4282b3b3228a97cb0df8394e6b3b Author: Xiang Hong (from Dev Box) Date: Sun Dec 8 11:27:04 2024 +0800 feature: add basic implementations for SavePickers FileExtension/SuggestedSaveFile/Name functionalities commit 3be9dc1194ab01acb78d020b638d6cc2dd5c87b3 Author: Xiang Hong (from Dev Box) Date: Sun Dec 8 10:35:59 2024 +0800 clean: code clean on naming styles etc commit 9fcc249c6a584c04e29fbc015a140b21b894f4be Author: Xiang Hong (from Dev Box) Date: Sat Dec 7 22:22:21 2024 +0800 refactor: use WinRT MD5 hash string to Guid commit 756bafa151e319ef1a40f2a25411f04b364c96c5 Author: Xiang Hong (from Dev Box) Date: Sat Dec 7 22:02:55 2024 +0800 fix: fix file type filter issues and refactor to use PickParameters commit 8dea72ab4a2e80ee8f8e6ddd01eb3d8c76bbf5d4 Author: Xiang Hong (from Dev Box) Date: Sat Dec 7 19:46:45 2024 +0800 feature: add COM FileSavePicker basic implementation commit 37a5a75bc883f67e662e96b04c74a3ed25ce44f6 Author: Xiang Hong Date: Sat Dec 7 17:13:55 2024 +0800 add save file dialog usage in demo app commit fc9a03af48cf4522a67a2cce717548270cfa8942 Author: Xiang Hong Date: Sat Dec 7 12:06:47 2024 +0800 feature: add folder functionalities to demo test app commit 34556bd7594bf6bd4c2e1493320b10588d049214 Author: Xiang Hong Date: Fri Dec 6 22:51:55 2024 +0800 feature: add COM based picker prototype basic implementation --- .../FileOpenPicker.cpp | 154 ++++++++++++++ .../FileOpenPicker.h | 44 ++++ .../FileSavePicker.cpp | 138 ++++++++++++ .../FileSavePicker.h | 53 +++++ .../FolderPicker.cpp | 98 +++++++++ .../Microsoft.Storage.Pickers/FolderPicker.h | 45 ++++ .../Microsoft.Storage.Pickers.vcxproj | 160 ++++++++++++++ .../Microsoft.Storage.Pickers.vcxproj.filters | 37 ++++ .../Microsoft_Storage_Pickers.def | 3 + .../PickerCommon.cpp | 200 ++++++++++++++++++ .../Microsoft.Storage.Pickers/PickerCommon.h | 27 +++ .../Microsoft.Storage.Pickers/Pickers.idl | 68 ++++++ .../Microsoft.Storage.Pickers/packages.config | 8 + .../Microsoft.Storage.Pickers/pch.cpp | 1 + .../Microsoft.Storage.Pickers/pch.h | 33 +++ .../Microsoft.Storage.Pickers/readme.txt | 27 +++ 16 files changed, 1096 insertions(+) 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 diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp new file mode 100644 index 0000000000..d3d42329d3 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.cpp @@ -0,0 +1,154 @@ +#include "pch.h" +#include "FileOpenPicker.h" +#include "FileOpenPicker.g.cpp" +#include +#include +#include +#include +#include "PickerCommon.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + FileOpenPicker::FileOpenPicker(winrt::Microsoft::UI::WindowId const& windowId) + : m_windowId(windowId) + { + } + + winrt::Microsoft::Storage::Pickers::PickerViewMode FileOpenPicker::ViewMode() + { + return m_viewMode; + } + void FileOpenPicker::ViewMode(winrt::Microsoft::Storage::Pickers::PickerViewMode const& value) + { + m_viewMode = value; + } + hstring FileOpenPicker::SettingsIdentifier() + { + return m_settingsIdentifier; + } + void FileOpenPicker::SettingsIdentifier(hstring const& value) + { + m_settingsIdentifier = value; + } + winrt::Microsoft::Storage::Pickers::PickerLocationId FileOpenPicker::SuggestedStartLocation() + { + return m_suggestedStartLocation; + } + void FileOpenPicker::SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value) + { + m_suggestedStartLocation = value; + } + winrt::hstring FileOpenPicker::CommitButtonText() + { + return m_commitButtonText; + } + void FileOpenPicker::CommitButtonText(winrt::hstring const& value) + { + m_commitButtonText = value; + } + winrt::Windows::Foundation::Collections::IVector FileOpenPicker::FileTypeFilter() + { + return m_fileTypeFilter; + } + + void FileOpenPicker::CaptureParameters(PickerCommon::PickerParameters& parameters) + { + parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); + parameters.CommitButtonText = m_commitButtonText; + parameters.SettingsIdentifierId = m_settingsIdentifier; + parameters.PickerLocationId = m_suggestedStartLocation; + parameters.FileTypeFilterPara = PickerCommon::CaptureFilterSpec(parameters.FileTypeFilterData, m_fileTypeFilter.GetView()); + } + + winrt::Windows::Foundation::IAsyncOperation FileOpenPicker::PickSingleFileAsync() + { + PickerCommon::PickerParameters parameters{}; + + CaptureParameters(parameters); + + co_await winrt::resume_background(); + + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return nullptr; + } + + // TODO: should we initialize COM? + // wil::com_initialize_ex initializeCom{ COINIT_APARTMENTTHREADED }; + + auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL); + + parameters.ConfigureDialog(dialog); + + { + auto hr = dialog->Show(parameters.HWnd); + if (FAILED(hr) || cancellationToken()) + { + co_return nullptr; + } + } + + winrt::com_ptr shellItem{}; + check_hresult(dialog->GetResult(shellItem.put())); + auto file = co_await PickerCommon::CreateStorageFileFromShellItem(shellItem); + + if (cancellationToken()) + { + co_return nullptr; + } + co_return file; + } + + winrt::Windows::Foundation::IAsyncOperation> FileOpenPicker::PickMultipleFilesAsync() + { + PickerCommon::PickerParameters parameters{}; + + CaptureParameters(parameters); + + co_await winrt::resume_background(); + + winrt::Windows::Foundation::Collections::IVector results{ winrt::single_threaded_vector() }; + + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return results.GetView(); + } + + auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL); + + parameters.ConfigureDialog(dialog); + + check_hresult(dialog->SetOptions(FOS_ALLOWMULTISELECT)); + + { + auto hr = dialog->Show(parameters.HWnd); + if (FAILED(hr) || cancellationToken()) + { + co_return results.GetView(); + } + } + + winrt::com_ptr shellItems{}; + check_hresult(dialog->GetResults(shellItems.put())); + + DWORD itemCount = 0; + check_hresult(shellItems->GetCount(&itemCount)); + + winrt::com_ptr shellItem{}; + for (DWORD i = 0; i < itemCount; i++) + { + check_hresult(shellItems->GetItemAt(i, shellItem.put())); + auto file = co_await PickerCommon::CreateStorageFileFromShellItem(shellItem); + results.Append(file); + } + + if (cancellationToken()) + { + results.Clear(); + co_return results.GetView(); + } + co_return results.GetView(); + } +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.h b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.h new file mode 100644 index 0000000000..fb68a34d2b --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileOpenPicker.h @@ -0,0 +1,44 @@ +#pragma once +#include "FileOpenPicker.g.h" +#include "PickerCommon.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + struct FileOpenPicker : FileOpenPickerT + { + FileOpenPicker(winrt::Microsoft::UI::WindowId const& windowId); + + winrt::Microsoft::Storage::Pickers::PickerViewMode ViewMode(); + void ViewMode(winrt::Microsoft::Storage::Pickers::PickerViewMode const& value); + + hstring SettingsIdentifier(); + void SettingsIdentifier(hstring const& value); + + winrt::Microsoft::Storage::Pickers::PickerLocationId SuggestedStartLocation(); + void SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value); + + winrt::hstring CommitButtonText(); + void CommitButtonText(winrt::hstring const& value); + + winrt::Windows::Foundation::Collections::IVector FileTypeFilter(); + + winrt::Windows::Foundation::IAsyncOperation PickSingleFileAsync(); + winrt::Windows::Foundation::IAsyncOperation> PickMultipleFilesAsync(); + + private: + winrt::Microsoft::UI::WindowId m_windowId{}; + PickerViewMode m_viewMode{ PickerViewMode::List }; + winrt::hstring m_settingsIdentifier{}; + PickerLocationId m_suggestedStartLocation{ PickerLocationId::Unspecified }; + winrt::hstring m_commitButtonText{}; + winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ winrt::single_threaded_vector() }; + + void CaptureParameters(PickerCommon::PickerParameters& parameters); + }; +} +namespace winrt::Microsoft::Storage::Pickers::factory_implementation +{ + struct FileOpenPicker : FileOpenPickerT + { + }; +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp new file mode 100644 index 0000000000..052135bf98 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.cpp @@ -0,0 +1,138 @@ +#include "pch.h" +#include "FileSavePicker.h" +#include "FileSavePicker.g.cpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "PickerCommon.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + + FileSavePicker::FileSavePicker(winrt::Microsoft::UI::WindowId const& windowId) + : m_windowId(windowId) + { + } + hstring FileSavePicker::SettingsIdentifier() + { + return m_settingsIdentifier; + } + void FileSavePicker::SettingsIdentifier(hstring const& value) + { + m_settingsIdentifier = value; + } + winrt::Microsoft::Storage::Pickers::PickerLocationId FileSavePicker::SuggestedStartLocation() + { + return m_suggestedStartLocation; + } + void FileSavePicker::SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value) + { + m_suggestedStartLocation = value; + } + hstring FileSavePicker::CommitButtonText() + { + return m_commitButtonText; + } + void FileSavePicker::CommitButtonText(hstring const& value) + { + m_commitButtonText = value; + } + winrt::Windows::Foundation::Collections::IMap> FileSavePicker::FileTypeChoices() + { + return m_fileTypeChoices; + } + hstring FileSavePicker::DefaultFileExtension() + { + return m_defaultFileExtension; + } + void FileSavePicker::DefaultFileExtension(hstring const& value) + { + m_defaultFileExtension = value; + } + winrt::Windows::Storage::StorageFile FileSavePicker::SuggestedSaveFile() + { + return m_suggestedSaveFile; + } + void FileSavePicker::SuggestedSaveFile(winrt::Windows::Storage::StorageFile const& value) + { + m_suggestedSaveFile = value; + } + hstring FileSavePicker::SuggestedFileName() + { + return m_suggestedFileName; + } + void FileSavePicker::SuggestedFileName(hstring const& value) + { + m_suggestedFileName = value; + } + + + void FileSavePicker::CaptureParameters(PickerCommon::PickerParameters& parameters) + { + parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); + parameters.CommitButtonText = m_commitButtonText; + parameters.SettingsIdentifierId = m_settingsIdentifier; + parameters.PickerLocationId = m_suggestedStartLocation; + parameters.FileTypeFilterPara = PickerCommon::CaptureFilterSpec(parameters.FileTypeFilterData, m_fileTypeChoices.GetView()); + + } + + winrt::Windows::Foundation::IAsyncOperation FileSavePicker::PickSaveFileAsync() + { + PickerCommon::PickerParameters parameters{}; + CaptureParameters(parameters); + auto defaultFileExtension = m_defaultFileExtension; + auto suggestedSaveFile = m_suggestedSaveFile; + auto suggestedFileName = m_suggestedFileName; + + co_await winrt::resume_background(); + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return nullptr; + } + + auto dialog = create_instance(CLSID_FileSaveDialog, CONTEXT_ALL); + parameters.ConfigureDialog(dialog); + + if (!PickerCommon::IsHStringNullOrEmpty(defaultFileExtension)) + { + check_hresult(dialog->SetDefaultExtension(defaultFileExtension.c_str())); + } + if (!PickerCommon::IsHStringNullOrEmpty(suggestedFileName)) + { + check_hresult(dialog->SetFileName(suggestedFileName.c_str())); + } + if (suggestedSaveFile != nullptr) + { + winrt::com_ptr shellItem; + check_hresult(SHCreateItemFromParsingName(suggestedSaveFile.Path().c_str(), nullptr, IID_PPV_ARGS(shellItem.put()))); + check_hresult(dialog->SetSaveAsItem(shellItem.get())); + } + + { + auto hr = dialog->Show(parameters.HWnd); + if (FAILED(hr)) + { + co_return nullptr; + } + } + + winrt::com_ptr shellItem{}; + check_hresult(dialog->GetResult(shellItem.put())); + auto file = co_await PickerCommon::CreateStorageFileFromShellItem(shellItem); + + if (cancellationToken()) + { + co_return nullptr; + } + co_return file; + } +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h new file mode 100644 index 0000000000..2144f51292 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FileSavePicker.h @@ -0,0 +1,53 @@ +#pragma once +#include "FileSavePicker.g.h" +#include "PickerCommon.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + struct FileSavePickerParameters; + + struct FileSavePicker : FileSavePickerT + { + FileSavePicker(winrt::Microsoft::UI::WindowId const& windowId); + + hstring SettingsIdentifier(); + void SettingsIdentifier(hstring const& value); + + winrt::Microsoft::Storage::Pickers::PickerLocationId SuggestedStartLocation(); + void SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value); + + hstring CommitButtonText(); + void CommitButtonText(hstring const& value); + + winrt::Windows::Foundation::Collections::IMap> FileTypeChoices(); + + hstring DefaultFileExtension(); + void DefaultFileExtension(hstring const& value); + + winrt::Windows::Storage::StorageFile SuggestedSaveFile(); + void SuggestedSaveFile(winrt::Windows::Storage::StorageFile const& value); + + hstring SuggestedFileName(); + void SuggestedFileName(hstring const& value); + + winrt::Windows::Foundation::IAsyncOperation PickSaveFileAsync(); + + private: + winrt::Microsoft::UI::WindowId m_windowId{}; + hstring m_settingsIdentifier{}; + PickerLocationId m_suggestedStartLocation{ PickerLocationId::Unspecified }; + hstring m_commitButtonText{}; + winrt::Windows::Foundation::Collections::IMap> m_fileTypeChoices{ winrt::single_threaded_map>() }; + hstring m_defaultFileExtension{}; + winrt::Windows::Storage::StorageFile m_suggestedSaveFile{ nullptr }; + hstring m_suggestedFileName{}; + + void CaptureParameters(PickerCommon::PickerParameters& parameters); + }; +} +namespace winrt::Microsoft::Storage::Pickers::factory_implementation +{ + struct FileSavePicker : FileSavePickerT + { + }; +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp new file mode 100644 index 0000000000..6e7c62d0be --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.cpp @@ -0,0 +1,98 @@ +#include "pch.h" +#include "FolderPicker.h" +#include "FolderPicker.g.cpp" +#include +#include +#include +#include "PickerCommon.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + FolderPicker::FolderPicker(winrt::Microsoft::UI::WindowId const& windowId) + : m_windowId(windowId) + { + } + winrt::Microsoft::Storage::Pickers::PickerViewMode FolderPicker::ViewMode() + { + return m_viewMode; + } + void FolderPicker::ViewMode(winrt::Microsoft::Storage::Pickers::PickerViewMode const& value) + { + m_viewMode = value; + } + hstring FolderPicker::SettingsIdentifier() + { + return m_settingsIdentifier; + } + void FolderPicker::SettingsIdentifier(hstring const& value) + { + m_settingsIdentifier = value; + } + winrt::Microsoft::Storage::Pickers::PickerLocationId FolderPicker::SuggestedStartLocation() + { + return m_suggestedStartLocation; + } + void FolderPicker::SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value) + { + m_suggestedStartLocation = value; + } + hstring FolderPicker::CommitButtonText() + { + return m_commitButtonText; + } + void FolderPicker::CommitButtonText(hstring const& value) + { + m_commitButtonText = value; + } + winrt::Windows::Foundation::Collections::IVector FolderPicker::FileTypeFilter() + { + return m_fileTypeFilter; + } + + void FolderPicker::CaptureParameters(PickerCommon::PickerParameters& parameters) + { + parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); + parameters.CommitButtonText = m_commitButtonText; + parameters.SettingsIdentifierId = m_settingsIdentifier; + parameters.PickerLocationId = m_suggestedStartLocation; + parameters.FileTypeFilterPara = PickerCommon::CaptureFilterSpec(parameters.FileTypeFilterData, m_fileTypeFilter.GetView()); + } + + + winrt::Windows::Foundation::IAsyncOperation FolderPicker::PickSingleFolderAsync() + { + PickerCommon::PickerParameters parameters{}; + CaptureParameters(parameters); + + co_await winrt::resume_background(); + + auto cancellationToken = co_await winrt::get_cancellation_token(); + if (cancellationToken()) + { + co_return nullptr; + } + + auto dialog = create_instance(CLSID_FileOpenDialog, CONTEXT_ALL); + + parameters.ConfigureDialog(dialog); + dialog->SetOptions(FOS_PICKFOLDERS); + + { + auto hr = dialog->Show(parameters.HWnd); + if (FAILED(hr) || cancellationToken()) + { + co_return nullptr; + } + } + + winrt::com_ptr shellItem{}; + check_hresult(dialog->GetResult(shellItem.put())); + auto folder = co_await PickerCommon::CreateStorageFolderFromShellItem(shellItem); + + if (cancellationToken()) + { + co_return nullptr; + } + co_return folder; + } +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h new file mode 100644 index 0000000000..56af65cb19 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/FolderPicker.h @@ -0,0 +1,45 @@ +#pragma once +#include "FolderPicker.g.h" +#include "PickerCommon.h" + +namespace winrt::Microsoft::Storage::Pickers::implementation +{ + struct FolderPicker : FolderPickerT + { + FolderPicker(winrt::Microsoft::UI::WindowId const& windowId); + + winrt::Microsoft::Storage::Pickers::PickerViewMode ViewMode(); + void ViewMode(winrt::Microsoft::Storage::Pickers::PickerViewMode const& value); + + hstring SettingsIdentifier(); + void SettingsIdentifier(hstring const& value); + + winrt::Microsoft::Storage::Pickers::PickerLocationId SuggestedStartLocation(); + void SuggestedStartLocation(winrt::Microsoft::Storage::Pickers::PickerLocationId const& value); + + hstring CommitButtonText(); + void CommitButtonText(hstring const& value); + + winrt::Windows::Foundation::Collections::IVector FileTypeFilter(); + + winrt::Windows::Foundation::IAsyncOperation PickSingleFolderAsync(); + + private: + winrt::Microsoft::UI::WindowId m_windowId{}; + + PickerViewMode m_viewMode{ PickerViewMode::List }; + hstring m_settingsIdentifier{}; + PickerLocationId m_suggestedStartLocation{ PickerLocationId::Unspecified }; + hstring m_commitButtonText{}; + + winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ winrt::single_threaded_vector() }; + + void CaptureParameters(PickerCommon::PickerParameters& parameters); + }; +} +namespace winrt::Microsoft::Storage::Pickers::factory_implementation +{ + struct FolderPicker : FolderPickerT + { + }; +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj new file mode 100644 index 0000000000..b1b1eaf438 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj @@ -0,0 +1,160 @@ + + + + + + + true + true + true + {349e64cf-cb0c-4202-b1b5-7f543cc6e886} + Microsoft.Storage.Pickers + Microsoft.Storage.Pickers + en-US + 16.0 + false + Windows Store + 10.0 + 10.0.22621.0 + 10.0.22000.0 + true + true + + + + + Debug + Win32 + + + Debug + x64 + + + Debug + ARM64 + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + DynamicLibrary + v143 + Unicode + false + true + + + true + true + + + false + true + false + + + + + + + + + + + + + + Use + pch.h + $(IntDir)pch.pch + Level4 + %(AdditionalOptions) /bigobj + _WINRT_DLL;%(PreprocessorDefinitions) + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + + + Console + true + Microsoft_Storage_Pickers.def + + + + + _DEBUG;%(PreprocessorDefinitions) + + + $(CoreLibraryDependencies);%(AdditionalDependencies);shell32.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + + + true + true + $(CoreLibraryDependencies);%(AdditionalDependencies);shell32.lib + + + + + + + + + + + + + + + Create + + + + + + + + + + + false + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + \ No newline at end of file diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj.filters b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj.filters new file mode 100644 index 0000000000..af63f3cf8e --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft.Storage.Pickers.vcxproj.filters @@ -0,0 +1,37 @@ + + + + + accd3aa8-1ba0-4223-9bbe-0c431709210b + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms + + + {926ab91d-31b4-48c3-b9a4-e681349f27f0} + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft_Storage_Pickers.def b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft_Storage_Pickers.def new file mode 100644 index 0000000000..24e7c1235c --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/Microsoft_Storage_Pickers.def @@ -0,0 +1,3 @@ +EXPORTS +DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE +DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp new file mode 100644 index 0000000000..63e29b7ebf --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.cpp @@ -0,0 +1,200 @@ +#include "pch.h" +#include "PickerCommon.h" +#include +#include "ShObjIdl.h" +#include + +namespace { + + GUID HashHStringToGuid(winrt::hstring const& input) + { + auto algorithmProvider = winrt::Windows::Security::Cryptography::Core::HashAlgorithmProvider::OpenAlgorithm(winrt::Windows::Security::Cryptography::Core::HashAlgorithmNames::Md5()); + + auto buffer = winrt::Windows::Security::Cryptography::CryptographicBuffer::ConvertStringToBinary(input, winrt::Windows::Security::Cryptography::BinaryStringEncoding::Utf16LE); + + auto hash = algorithmProvider.HashData(buffer); + + if (hash.Length() != 16) + { + throw winrt::hresult_error(E_FAIL, L"Invalid hash length"); + } + + winrt::com_array resultBuffer{}; + winrt::Windows::Security::Cryptography::CryptographicBuffer::CopyToByteArray(hash, resultBuffer); + GUID guid = *(reinterpret_cast(resultBuffer.data())); + + // TODO: verify bit pattern code from copilot is correct to fit spec + // Adjust the GUID to conform to version 3 UUID (MD5-based) + guid.Data3 = (guid.Data3 & 0x0FFF) | 0x3000; // Set the version to 3 + guid.Data4[0] = (guid.Data4[0] & 0x3F) | 0x80; // Set variant to RFC 4122 + + return guid; + } + + // TODO: use better winrt implementations? + // Challenge: currently winrt based Storage.KnownFolder APIs does not provide all location id we need + winrt::com_ptr GetKnownFolderFromId(winrt::Microsoft::Storage::Pickers::PickerLocationId pickerLocationId) + { + KNOWNFOLDERID knownFolderId; + switch (pickerLocationId) + { + case winrt::Microsoft::Storage::Pickers::PickerLocationId::DocumentsLibrary: + knownFolderId = FOLDERID_Documents; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::ComputerFolder: + knownFolderId = FOLDERID_ComputerFolder; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::Desktop: + knownFolderId = FOLDERID_Desktop; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::Downloads: + knownFolderId = FOLDERID_Downloads; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::HomeGroup: + knownFolderId = FOLDERID_HomeGroup; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::MusicLibrary: + knownFolderId = FOLDERID_MusicLibrary; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::PicturesLibrary: + knownFolderId = FOLDERID_PicturesLibrary; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::VideosLibrary: + knownFolderId = FOLDERID_VideosLibrary; + break; + case winrt::Microsoft::Storage::Pickers::PickerLocationId::Objects3D: + knownFolderId = FOLDERID_Objects3D; + break; + default: + return nullptr; + } + + auto knownFolderManager = winrt::create_instance(CLSID_KnownFolderManager); + winrt::com_ptr knownFolder{}; + winrt::check_hresult(knownFolderManager->GetFolder(knownFolderId, knownFolder.put())); + winrt::com_ptr defaultFolder{}; + winrt::check_hresult(knownFolder->GetShellItem(0, IID_PPV_ARGS(defaultFolder.put()))); + return defaultFolder; + } + + + winrt::hstring FormatExtensionWithWildcard(winrt::hstring extension) + { + if (!extension.empty() && extension[0] == L'*') + { + return extension; + } + else + { + return L"*" + extension; + } + } + + winrt::hstring JoinExtensions(winrt::Windows::Foundation::Collections::IVectorView extensions) + { + winrt::hstring result; + bool first = true; + for (const auto& ext : extensions) + { + if (first) + { + result = FormatExtensionWithWildcard(ext); + first = false; + } + else + { + result = result + L";" + FormatExtensionWithWildcard(ext); + } + } + return result; + } + +} + + +namespace PickerCommon { + + using namespace winrt; + + bool IsHStringNullOrEmpty(winrt::hstring value) + { + // TODO: proper handling of null string reference? + return value.empty(); + } + + + // TODO: better way to convert ShellItem a StorageFile without relying on path?. + winrt::Windows::Foundation::IAsyncOperation CreateStorageFileFromShellItem(winrt::com_ptr shellItem) + { + wil::unique_cotaskmem_string filePath; + check_hresult(shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath)); + co_return co_await winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(filePath.get()); + } + + winrt::Windows::Foundation::IAsyncOperation CreateStorageFolderFromShellItem(winrt::com_ptr shellItem) + { + wil::unique_cotaskmem_string filePath; + check_hresult(shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath)); + co_return co_await winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(filePath.get()); + } + + std::vector CaptureFilterSpec(std::vector& buffer, winrt::Windows::Foundation::Collections::IVectorView filters) + { + std::vector result(filters.Size()); + buffer.clear(); + buffer.reserve(filters.Size() * (size_t)2); + for (auto filter : filters) + { + auto ext = FormatExtensionWithWildcard(filter); + buffer.push_back(filter); + buffer.push_back(ext); + } + for (size_t i = 0; i < filters.Size(); i++) + { + result.at(i) = { buffer.at(i * 2).c_str(), buffer.at(i * 2 + 1).c_str() }; + } + return result; + } + + std::vector CaptureFilterSpec(std::vector& buffer, winrt::Windows::Foundation::Collections::IMapView> filters) + { + std::vector result(filters.Size()); + buffer.clear(); + buffer.reserve(filters.Size() * (size_t)2); + + for (const auto& filter : filters) + { + buffer.push_back(filter.Key()); + auto extensionList = JoinExtensions(filter.Value().GetView()); + buffer.push_back(extensionList); + } + for (size_t i = 0; i < filters.Size(); i++) + { + result.at(i) = { buffer.at(i * 2).c_str(), buffer.at(i * 2 + 1).c_str() }; + } + return result; + } + + void PickerParameters::ConfigureDialog(winrt::com_ptr dialog) + { + if (!IsHStringNullOrEmpty(CommitButtonText)) + { + check_hresult(dialog->SetOkButtonLabel(CommitButtonText.c_str())); + } + + if (!IsHStringNullOrEmpty(SettingsIdentifierId)) + { + auto guid = HashHStringToGuid(SettingsIdentifierId); + check_hresult(dialog->SetClientGuid(guid)); + } + + auto defaultFolder = GetKnownFolderFromId(PickerLocationId); + if (defaultFolder != nullptr) + { + check_hresult(dialog->SetFolder(defaultFolder.get())); + check_hresult(dialog->SetDefaultFolder(defaultFolder.get())); + } + + check_hresult(dialog->SetFileTypes(FileTypeFilterPara.size(), FileTypeFilterPara.data())); + } +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h new file mode 100644 index 0000000000..de7db7ac54 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/PickerCommon.h @@ -0,0 +1,27 @@ +// TODO: use better namespace, maybe anonymous namespace? +#pragma once +#include "pch.h" +#include "ShObjIdl.h" +#include "winrt/Microsoft.Storage.Pickers.h" + +namespace PickerCommon { + winrt::Windows::Foundation::IAsyncOperation CreateStorageFileFromShellItem(winrt::com_ptr shellItem); + winrt::Windows::Foundation::IAsyncOperation CreateStorageFolderFromShellItem(winrt::com_ptr shellItem); + + std::vector CaptureFilterSpec(std::vector& buffer, winrt::Windows::Foundation::Collections::IVectorView filters); + std::vector CaptureFilterSpec(std::vector& buffer, winrt::Windows::Foundation::Collections::IMapView> filters); + + // TODO: remove this if we know proper and null safe empty test for string + bool IsHStringNullOrEmpty(winrt::hstring value); + + struct PickerParameters { + HWND HWnd; + winrt::hstring CommitButtonText; + winrt::hstring SettingsIdentifierId; + winrt::Microsoft::Storage::Pickers::PickerLocationId PickerLocationId; + std::vector FileTypeFilterData{}; + std::vector FileTypeFilterPara{}; + + void ConfigureDialog(winrt::com_ptr dialog); + }; +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/Pickers.idl b/prototype-workingdir/Microsoft.Storage.Pickers/Pickers.idl new file mode 100644 index 0000000000..31c4c6c7ea --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/Pickers.idl @@ -0,0 +1,68 @@ +namespace Microsoft.Storage.Pickers +{ + enum PickerViewMode + { + List, + Thumbnail, + }; + + enum PickerLocationId + { + DocumentsLibrary, + ComputerFolder, + Desktop, + Downloads, + HomeGroup, + MusicLibrary, + PicturesLibrary, + VideosLibrary, + Objects3D, + Unspecified, + }; + + + [default_interface] + runtimeclass FileOpenPicker + { + FileOpenPicker(Microsoft.UI.WindowId windowId); + + Microsoft.Storage.Pickers.PickerViewMode ViewMode; + String SettingsIdentifier; + Microsoft.Storage.Pickers.PickerLocationId SuggestedStartLocation; + String CommitButtonText; + Windows.Foundation.Collections.IVector FileTypeFilter{ get; }; + + [remote_sync] Windows.Foundation.IAsyncOperation PickSingleFileAsync(); + [remote_sync] Windows.Foundation.IAsyncOperation > PickMultipleFilesAsync(); + } + + [default_interface] + runtimeclass FileSavePicker + { + FileSavePicker(Microsoft.UI.WindowId windowId); + + String SettingsIdentifier; + Microsoft.Storage.Pickers.PickerLocationId SuggestedStartLocation; + String CommitButtonText; + Windows.Foundation.Collections.IMap > FileTypeChoices{ get; }; + String DefaultFileExtension; + Windows.Storage.StorageFile SuggestedSaveFile; + String SuggestedFileName; + + [remote_sync] Windows.Foundation.IAsyncOperation PickSaveFileAsync(); + } + + [default_interface] + runtimeclass FolderPicker + { + FolderPicker(Microsoft.UI.WindowId windowId); + + Microsoft.Storage.Pickers.PickerViewMode ViewMode; + String SettingsIdentifier; + Microsoft.Storage.Pickers.PickerLocationId SuggestedStartLocation; + String CommitButtonText; + Windows.Foundation.Collections.IVector FileTypeFilter{ get; }; + + [remote_sync] Windows.Foundation.IAsyncOperation PickSingleFolderAsync(); + } +} diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/packages.config b/prototype-workingdir/Microsoft.Storage.Pickers/packages.config new file mode 100644 index 0000000000..6e553cc88c --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/pch.cpp b/prototype-workingdir/Microsoft.Storage.Pickers/pch.cpp new file mode 100644 index 0000000000..1d9f38c57d --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/pch.h b/prototype-workingdir/Microsoft.Storage.Pickers/pch.h new file mode 100644 index 0000000000..21563b73b3 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/pch.h @@ -0,0 +1,33 @@ +#pragma once +#include +#include +#include +#include + +// Undefine GetCurrentTime macro to prevent +// conflict with Storyboard::GetCurrentTime +#undef GetCurrentTime + + +#include "winrt/Microsoft.Storage.Pickers.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/prototype-workingdir/Microsoft.Storage.Pickers/readme.txt b/prototype-workingdir/Microsoft.Storage.Pickers/readme.txt new file mode 100644 index 0000000000..6b46510cd0 --- /dev/null +++ b/prototype-workingdir/Microsoft.Storage.Pickers/readme.txt @@ -0,0 +1,27 @@ +======================================================================== + Microsoft.Storage.Pickers Project Overview +======================================================================== + +This project demonstrates how to get started authoring Windows Runtime +classes directly with standard C++, using the Windows App SDK and +C++/WinRT packages to generate implementation headers from interface +(IDL) files. The generated Windows Runtime component binary and WinMD +files should then be bundled with the app consuming them. + +Steps: +1. Create an interface (IDL) file to define your Windows Runtime class, + its default interface, and any other interfaces it implements. +2. Build the project once to generate module.g.cpp, module.h.cpp, and + implementation templates under the "Generated Files" folder, as + well as skeleton class definitions under "Generated Files\sources". +3. Use the skeleton class definitions for reference to implement your + Windows Runtime classes. + +======================================================================== +Learn more about Windows App SDK here: +https://docs.microsoft.com/windows/apps/windows-app-sdk/ +Learn more about WinUI3 here: +https://docs.microsoft.com/windows/apps/winui/winui3/ +Learn more about C++/WinRT here: +http://aka.ms/cppwinrt/ +========================================================================