Skip to content

Commit 6e23456

Browse files
authored
FileSavePicker.SuggestedSaveFilePath (#5547)
* SuggestedSaveFile * ISuggestedSaveFile FileSavePicker::SuggestedSaveFile * SuggestedSaveFilePath * tests * Add contract * revert unnecessary changes; graceful; * contract 1.8 * remove FolderPicker.FileTypeFilter * a warnming MessageBox when the Folder of SuggestedSaveFilePath doesn't exist * HWnd for MessageBox * TrySetSuggestedSaveFilePath * TrySetSuggestedSaveFile * fix test * graceful * graceful * use std::filesystem::path::parent_path()
1 parent 8c6bc94 commit 6e23456

10 files changed

Lines changed: 222 additions & 37 deletions

File tree

dev/Interop/StoragePickers/FileSavePicker.cpp

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,25 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
6363
{
6464
m_defaultFileExtension = value;
6565
}
66-
winrt::Windows::Storage::StorageFile FileSavePicker::SuggestedSaveFile()
66+
hstring FileSavePicker::SuggestedSaveFilePath()
6767
{
68-
return m_suggestedSaveFile;
68+
return m_suggestedSaveFilePath;
6969
}
70-
void FileSavePicker::SuggestedSaveFile(winrt::Windows::Storage::StorageFile const& value)
70+
71+
bool FileSavePicker::TrySetSuggestedSaveFilePath(hstring const& filePath)
7172
{
72-
m_suggestedSaveFile = value;
73+
auto parseResult = PickerCommon::ParseFolderItemAndFileName(filePath);
74+
winrt::com_ptr<IShellItem> folderItem = parseResult.first;
75+
76+
if (!folderItem)
77+
{
78+
return false;
79+
}
80+
81+
m_suggestedSaveFilePath = filePath;
82+
return true;
7383
}
84+
7485
hstring FileSavePicker::SuggestedFileName()
7586
{
7687
return m_suggestedFileName;
@@ -87,6 +98,8 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
8798
parameters.CommitButtonText = m_commitButtonText;
8899
parameters.SettingsIdentifierId = m_settingsIdentifier;
89100
parameters.PickerLocationId = m_suggestedStartLocation;
101+
parameters.SuggestedFileName = m_suggestedFileName;
102+
parameters.SuggestedSaveFilePath = m_suggestedSaveFilePath;
90103
parameters.CaptureFilterSpec(m_fileTypeChoices.GetView());
91104
}
92105

@@ -103,7 +116,7 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
103116
CaptureParameters(parameters);
104117

105118
auto defaultFileExtension = m_defaultFileExtension;
106-
auto suggestedSaveFile = m_suggestedSaveFile;
119+
auto suggestedSaveFilePath = m_suggestedSaveFilePath;
107120
auto suggestedFileName = m_suggestedFileName;
108121
auto fileTypeChoices = m_fileTypeChoices;
109122

@@ -119,6 +132,7 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
119132

120133
auto dialog = create_instance<IFileSaveDialog>(CLSID_FileSaveDialog, CLSCTX_INPROC_SERVER);
121134
parameters.ConfigureDialog(dialog);
135+
parameters.ConfigureFileSaveDialog(dialog);
122136

123137
if (!PickerCommon::IsHStringNullOrEmpty(defaultFileExtension))
124138
{
@@ -135,18 +149,6 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
135149
check_hresult(dialog->GetOptions(&dialogOptions));
136150
check_hresult(dialog->SetOptions(dialogOptions | FOS_STRICTFILETYPES));
137151

138-
if (!PickerCommon::IsHStringNullOrEmpty(suggestedFileName))
139-
{
140-
check_hresult(dialog->SetFileName(suggestedFileName.c_str()));
141-
}
142-
143-
if (suggestedSaveFile != nullptr)
144-
{
145-
winrt::com_ptr<IShellItem> shellItem;
146-
check_hresult(SHCreateItemFromParsingName(suggestedSaveFile.Path().c_str(), nullptr, IID_PPV_ARGS(shellItem.put())));
147-
check_hresult(dialog->SetSaveAsItem(shellItem.get()));
148-
}
149-
150152
{
151153
auto hr = dialog->Show(parameters.HWnd);
152154
if (FAILED(hr))
@@ -185,4 +187,3 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
185187
co_return result;
186188
}
187189
}
188-

dev/Interop/StoragePickers/FileSavePicker.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
2828
hstring DefaultFileExtension();
2929
void DefaultFileExtension(hstring const& value);
3030

31-
winrt::Windows::Storage::StorageFile SuggestedSaveFile();
32-
void SuggestedSaveFile(winrt::Windows::Storage::StorageFile const& value);
31+
hstring SuggestedSaveFilePath();
32+
bool TrySetSuggestedSaveFilePath(hstring const& filePath);
3333

3434
hstring SuggestedFileName();
3535
void SuggestedFileName(hstring const& value);
@@ -43,7 +43,7 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
4343
hstring m_commitButtonText{};
4444
winrt::Windows::Foundation::Collections::IMap<hstring, winrt::Windows::Foundation::Collections::IVector<hstring>> m_fileTypeChoices{ winrt::single_threaded_map<hstring, winrt::Windows::Foundation::Collections::IVector<hstring>>() };
4545
hstring m_defaultFileExtension{};
46-
winrt::Windows::Storage::StorageFile m_suggestedSaveFile{ nullptr };
46+
hstring m_suggestedSaveFilePath{};
4747
hstring m_suggestedFileName{};
4848
StoragePickersTelemetryHelper m_telemetryHelper{};
4949

dev/Interop/StoragePickers/FolderPicker.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,13 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
5252
{
5353
m_commitButtonText = value;
5454
}
55-
winrt::Windows::Foundation::Collections::IVector<hstring> FolderPicker::FileTypeFilter()
56-
{
57-
return m_fileTypeFilter;
58-
}
5955

6056
void FolderPicker::CaptureParameters(PickerCommon::PickerParameters& parameters)
6157
{
6258
parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId);
6359
parameters.CommitButtonText = m_commitButtonText;
6460
parameters.SettingsIdentifierId = m_settingsIdentifier;
6561
parameters.PickerLocationId = m_suggestedStartLocation;
66-
parameters.CaptureFilterSpec(m_fileTypeFilter.GetView());
6762
}
6863

6964

dev/Interop/StoragePickers/FolderPicker.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
2424
hstring CommitButtonText();
2525
void CommitButtonText(hstring const& value);
2626

27-
winrt::Windows::Foundation::Collections::IVector<hstring> FileTypeFilter();
28-
2927
winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::Windows::Storage::Pickers::PickFolderResult> PickSingleFolderAsync();
3028

3129
private:
@@ -37,8 +35,6 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation
3735
hstring m_commitButtonText{};
3836
StoragePickersTelemetryHelper m_telemetryHelper{};
3937

40-
winrt::Windows::Foundation::Collections::IVector<hstring> m_fileTypeFilter{ winrt::single_threaded_vector<hstring>() };
41-
4238
void CaptureParameters(PickerCommon::PickerParameters& parameters);
4339
};
4440
}

dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@
44
#include <TerminalVelocityFeatures-StoragePickers.h>
55
namespace Microsoft.Windows.Storage.Pickers
66
{
7+
[contractversion(1.8)]
8+
apicontract StoragePickersContract {};
9+
10+
[contract(StoragePickersContract, 1.8)]
711
[feature(Feature_StoragePickers)]
812
enum PickerViewMode
913
{
1014
List,
1115
Thumbnail,
1216
};
1317

18+
[contract(StoragePickersContract, 1.8)]
1419
[feature(Feature_StoragePickers)]
1520
enum PickerLocationId
1621
{
@@ -26,12 +31,14 @@ namespace Microsoft.Windows.Storage.Pickers
2631
Unspecified,
2732
};
2833

34+
[contract(StoragePickersContract, 1.8)]
2935
[feature(Feature_StoragePickers)]
30-
runtimeclass PickFileResult
36+
runtimeclass PickFileResult
3137
{
3238
String Path { get; };
3339
}
3440

41+
[contract(StoragePickersContract, 1.8)]
3542
[feature(Feature_StoragePickers)]
3643
runtimeclass FileOpenPicker
3744
{
@@ -47,6 +54,7 @@ namespace Microsoft.Windows.Storage.Pickers
4754
[remote_sync] Windows.Foundation.IAsyncOperation<Windows.Foundation.Collections.IVectorView<PickFileResult> > PickMultipleFilesAsync();
4855
}
4956

57+
[contract(StoragePickersContract, 1.8)]
5058
[feature(Feature_StoragePickers)]
5159
runtimeclass FileSavePicker
5260
{
@@ -57,18 +65,22 @@ namespace Microsoft.Windows.Storage.Pickers
5765
String CommitButtonText;
5866
Windows.Foundation.Collections.IMap<String, Windows.Foundation.Collections.IVector<String> > FileTypeChoices{ get; };
5967
String DefaultFileExtension;
60-
Windows.Storage.StorageFile SuggestedSaveFile;
6168
String SuggestedFileName;
6269

70+
String SuggestedSaveFilePath{ get; };
71+
Boolean TrySetSuggestedSaveFilePath(String filePath);
72+
6373
[remote_sync] Windows.Foundation.IAsyncOperation<PickFileResult> PickSaveFileAsync();
6474
}
6575

76+
[contract(StoragePickersContract, 1.8)]
6677
[feature(Feature_StoragePickers)]
6778
runtimeclass PickFolderResult
6879
{
6980
String Path { get; };
7081
}
7182

83+
[contract(StoragePickersContract, 1.8)]
7284
[feature(Feature_StoragePickers)]
7385
runtimeclass FolderPicker
7486
{
@@ -78,7 +90,6 @@ namespace Microsoft.Windows.Storage.Pickers
7890
String SettingsIdentifier;
7991
Microsoft.Windows.Storage.Pickers.PickerLocationId SuggestedStartLocation;
8092
String CommitButtonText;
81-
Windows.Foundation.Collections.IVector<String> FileTypeFilter{ get; };
8293

8394
[remote_sync] Windows.Foundation.IAsyncOperation<PickFolderResult> PickSingleFolderAsync();
8495
}

dev/Interop/StoragePickers/PickerCommon.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@
22
// Licensed under the MIT License.
33

44
#include "pch.h"
5+
#include "shellapi.h"
56
#include "PickerCommon.h"
67
#include <wil/resource.h>
78
#include "ShObjIdl.h"
9+
#include "shobjidl_core.h"
810
#include <KnownFolders.h>
11+
#include <filesystem>
12+
#include <format>
13+
#include <utility>
914

1015

1116
namespace {
@@ -110,6 +115,39 @@ namespace PickerCommon {
110115
return winrt::hstring{ filePath.get() };
111116
}
112117

118+
std::pair<winrt::com_ptr<IShellItem>, std::wstring> ParseFolderItemAndFileName(winrt::hstring const& filePath)
119+
{
120+
std::filesystem::path path(filePath.c_str());
121+
if (path.empty())
122+
{
123+
return { nullptr, L"" };
124+
}
125+
126+
auto folderPath = path.parent_path();
127+
if (folderPath.empty())
128+
{
129+
// If the path does not have a parent, we cannot set folder.
130+
return { nullptr, L"" };
131+
}
132+
133+
// If the parent folder does not exist or is not a directory, we cannot set folder.
134+
if (!std::filesystem::exists(folderPath) || !std::filesystem::is_directory(folderPath))
135+
{
136+
return { nullptr, L"" };
137+
}
138+
139+
winrt::com_ptr<IShellItem> shellItem;
140+
HRESULT hr = SHCreateItemFromParsingName(folderPath.c_str(), nullptr, IID_PPV_ARGS(shellItem.put()));
141+
if (SUCCEEDED(hr))
142+
{
143+
auto fileName = path.filename().wstring();
144+
return { shellItem, fileName };
145+
}
146+
147+
// If the shellitem cannot be created, we cannot set the folder.
148+
return { nullptr, L""};
149+
}
150+
113151
winrt::hstring PickerParameters::FormatExtensionWithWildcard(winrt::hstring extension)
114152
{
115153
if (!extension.empty() && extension[0] == L'*')
@@ -249,4 +287,35 @@ namespace PickerCommon {
249287

250288
check_hresult(dialog->SetFileTypes((UINT)FileTypeFilterPara.size(), FileTypeFilterPara.data()));
251289
}
290+
291+
/// <summary>
292+
/// Configure the FileSaveDialog, this is only for FileSavePicker.
293+
/// </summary>
294+
/// <param name="dialog"></param>
295+
void PickerParameters::ConfigureFileSaveDialog(winrt::com_ptr<IFileSaveDialog> dialog)
296+
{
297+
winrt::hstring fileNameToSet;
298+
if (!IsHStringNullOrEmpty(SuggestedFileName))
299+
{
300+
fileNameToSet = SuggestedFileName;
301+
}
302+
303+
if (!PickerCommon::IsHStringNullOrEmpty(SuggestedSaveFilePath))
304+
{
305+
auto result = ParseFolderItemAndFileName(SuggestedSaveFilePath);
306+
winrt::com_ptr<IShellItem> folderItem = result.first;
307+
fileNameToSet = result.second;
308+
if (folderItem)
309+
{
310+
check_hresult(dialog->SetFolder(folderItem.get()));
311+
}
312+
}
313+
314+
// Set the filename (either from SuggestedSaveFilePath or SuggestedFileName)
315+
if (!PickerCommon::IsHStringNullOrEmpty(fileNameToSet))
316+
{
317+
check_hresult(dialog->SetFileName(fileNameToSet.c_str()));
318+
}
319+
320+
}
252321
}

dev/Interop/StoragePickers/PickerCommon.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ namespace PickerCommon {
1515

1616
bool IsHStringNullOrEmpty(winrt::hstring value);
1717

18+
std::pair<winrt::com_ptr<IShellItem>, std::wstring> ParseFolderItemAndFileName(winrt::hstring const& filePath);
19+
1820
struct PickerParameters {
1921
HWND HWnd{};
2022
winrt::hstring CommitButtonText;
@@ -24,12 +26,16 @@ namespace PickerCommon {
2426
std::vector<COMDLG_FILTERSPEC> FileTypeFilterPara{};
2527
winrt::hstring AllFilesText{ L"All Files" }; // initialize to All Files as a default value, will be updated by localization
2628

29+
winrt::hstring SuggestedFileName;
30+
winrt::hstring SuggestedSaveFilePath;
31+
2732
winrt::hstring FormatExtensionWithWildcard(winrt::hstring extension);
2833
winrt::hstring JoinExtensions(winrt::Windows::Foundation::Collections::IVectorView<winrt::hstring> extensions);
2934

3035
void CaptureFilterSpec(winrt::Windows::Foundation::Collections::IVectorView<winrt::hstring> filters);
3136
void CaptureFilterSpec(winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, winrt::Windows::Foundation::Collections::IVector<winrt::hstring>> filters);
3237

3338
void ConfigureDialog(winrt::com_ptr<IFileDialog> dialog);
39+
void ConfigureFileSaveDialog(winrt::com_ptr<IFileSaveDialog> dialog);
3440
};
3541
}

specs/StoragePickers/FolderPicker.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ runtimeclass FolderPicker
1919
FolderPicker(Microsoft.UI.WindowId windowId);
2020

2121
string CommitButtonText;
22-
IVector<string> FileTypeFilter{ get; };
2322

2423
PickerLocationId SuggestedStartLocation;
2524
PickerViewMode ViewMode;

0 commit comments

Comments
 (0)