Replace the UWP file export with the shell32 one (#11365)
Just like in #9760, we can't actually use the UWP file picker API, because it will absolutely not work at all when the Terminal is running elevated. That would prevent the picker from appearing at all. So instead, we'll just use the shell32 one manually. This also gets rid of the confirmation dialog, since the team felt we didn't really need that. We could maybe replace it with a Toast (#8592), but _meh_ * [x] closes #11356 * [x] closes #11358 * This is a lot like #9760 * introduced in #11062 * megathread: #9700
This commit is contained in:
parent
6657d2c3e5
commit
85f067403d
|
@ -19,6 +19,9 @@
|
|||
#include "ColorHelper.h"
|
||||
#include "DebugTapConnection.h"
|
||||
#include "SettingsTab.h"
|
||||
#include "..\TerminalSettingsModel\FileUtils.h"
|
||||
|
||||
#include <shlobj.h>
|
||||
|
||||
using namespace winrt;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
|
@ -410,33 +413,45 @@ namespace winrt::TerminalApp::implementation
|
|||
// - tab: tab to export
|
||||
winrt::fire_and_forget TerminalPage::_ExportTab(const TerminalTab& tab)
|
||||
{
|
||||
// This will be used to set up the file picker "filter", to select .txt
|
||||
// files by default.
|
||||
static constexpr COMDLG_FILTERSPEC supportedFileTypes[] = {
|
||||
{ L"Text Files (*.txt)", L"*.txt" },
|
||||
{ L"All Files (*.*)", L"*.*" }
|
||||
};
|
||||
// An arbitrary GUID to associate with all instances of this
|
||||
// dialog, so they all re-open in the same path as they were
|
||||
// open before:
|
||||
static constexpr winrt::guid clientGuidExportFile{ 0xF6AF20BB, 0x0800, 0x48E6, { 0xB0, 0x17, 0xA1, 0x4C, 0xD8, 0x73, 0xDD, 0x58 } };
|
||||
|
||||
try
|
||||
{
|
||||
if (const auto control{ tab.GetActiveTerminalControl() })
|
||||
{
|
||||
const FileSavePicker savePicker;
|
||||
savePicker.as<IInitializeWithWindow>()->Initialize(*_hostingHwnd);
|
||||
savePicker.SuggestedStartLocation(PickerLocationId::Downloads);
|
||||
const auto fileChoices = single_threaded_vector<hstring>({ L".txt" });
|
||||
savePicker.FileTypeChoices().Insert(RS_(L"PlainText"), fileChoices);
|
||||
savePicker.SuggestedFileName(control.Title());
|
||||
// GH#11356 - we can't use the UWP apis for writing the file,
|
||||
// because they don't work elevated (shocker) So just use the
|
||||
// shell32 file picker manually.
|
||||
auto path = co_await SaveFilePicker(*_hostingHwnd, [control](auto&& dialog) {
|
||||
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidExportFile));
|
||||
try
|
||||
{
|
||||
// Default to the Downloads folder
|
||||
auto folderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_Downloads, KF_FLAG_DEFAULT, nullptr) };
|
||||
dialog->SetDefaultFolder(folderShellItem.get());
|
||||
}
|
||||
CATCH_LOG(); // non-fatal
|
||||
THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedFileTypes), supportedFileTypes));
|
||||
THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
|
||||
THROW_IF_FAILED(dialog->SetDefaultExtension(L"txt"));
|
||||
|
||||
const StorageFile file = co_await savePicker.PickSaveFileAsync();
|
||||
if (file != nullptr)
|
||||
// Default to using the tab title as the file name
|
||||
THROW_IF_FAILED(dialog->SetFileName((control.Title() + L".txt").c_str()));
|
||||
});
|
||||
|
||||
if (!path.empty())
|
||||
{
|
||||
const auto buffer = control.ReadEntireBuffer();
|
||||
CachedFileManager::DeferUpdates(file);
|
||||
co_await FileIO::WriteTextAsync(file, buffer);
|
||||
const auto status = co_await CachedFileManager::CompleteUpdatesAsync(file);
|
||||
switch (status)
|
||||
{
|
||||
case FileUpdateStatus::Complete:
|
||||
case FileUpdateStatus::CompleteAndRenamed:
|
||||
_ShowControlNoticeDialog(RS_(L"NoticeInfo"), RS_(L"ExportSuccess"));
|
||||
break;
|
||||
default:
|
||||
_ShowControlNoticeDialog(RS_(L"NoticeError"), RS_(L"ExportFailure"));
|
||||
}
|
||||
CascadiaSettings::ExportFile(path, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
|
@ -7,6 +7,7 @@
|
|||
#include "EnumEntry.h"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
#include "..\WinRTUtils\inc\Utils.h"
|
||||
|
||||
using namespace winrt::Windows::UI::Text;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
|
@ -8,6 +8,7 @@
|
|||
#include "EnumEntry.h"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
#include "..\WinRTUtils\inc\Utils.h"
|
||||
|
||||
using namespace winrt::Windows::UI::Text;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
|
|
|
@ -15,30 +15,6 @@ using namespace winrt::Windows::UI::Xaml;
|
|||
|
||||
UTILS_DEFINE_LIBRARY_RESOURCE_SCOPE(L"Microsoft.Terminal.Settings.Editor/Resources");
|
||||
|
||||
// Function Description:
|
||||
// - Helper that opens a file picker pre-seeded with image file types.
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenImagePicker(HWND parentHwnd)
|
||||
{
|
||||
static constexpr COMDLG_FILTERSPEC supportedImageFileTypes[] = {
|
||||
{ L"All Supported Bitmap Types (*.jpg, *.jpeg, *.png, *.bmp, *.gif, *.tiff, *.ico)", L"*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.tiff;*.ico" },
|
||||
{ L"All Files (*.*)", L"*.*" }
|
||||
};
|
||||
|
||||
static constexpr winrt::guid clientGuidImagePicker{ 0x55675F54, 0x74A1, 0x4552, { 0xA3, 0x9D, 0x94, 0xAE, 0x85, 0xD8, 0xF2, 0x7A } };
|
||||
return OpenFilePicker(parentHwnd, [](auto&& dialog) {
|
||||
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidImagePicker));
|
||||
try
|
||||
{
|
||||
auto pictureFolderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_PicturesLibrary, KF_FLAG_DEFAULT, nullptr) };
|
||||
dialog->SetDefaultFolder(pictureFolderShellItem.get());
|
||||
}
|
||||
CATCH_LOG(); // non-fatal
|
||||
THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedImageFileTypes), supportedImageFileTypes));
|
||||
THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
|
||||
THROW_IF_FAILED(dialog->SetDefaultExtension(L"jpg;jpeg;png;bmp;gif;tiff;ico"));
|
||||
});
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings
|
||||
{
|
||||
hstring GetSelectedItemTag(winrt::Windows::Foundation::IInspectable const& comboBoxAsInspectable)
|
||||
|
|
|
@ -97,42 +97,6 @@ public: \
|
|||
private: \
|
||||
static winrt::Windows::UI::Xaml::DependencyProperty _##name##Property;
|
||||
|
||||
// Function Description:
|
||||
// - This function presents a File Open "common dialog" and returns its selected file asynchronously.
|
||||
// Parameters:
|
||||
// - customize: A lambda that receives an IFileDialog* to customize.
|
||||
// Return value:
|
||||
// (async) path to the selected item.
|
||||
template<typename TLambda>
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenFilePicker(HWND parentHwnd, TLambda&& customize)
|
||||
{
|
||||
auto fileDialog{ winrt::create_instance<IFileDialog>(CLSID_FileOpenDialog) };
|
||||
DWORD flags{};
|
||||
THROW_IF_FAILED(fileDialog->GetOptions(&flags));
|
||||
THROW_IF_FAILED(fileDialog->SetOptions(flags | FOS_FORCEFILESYSTEM | FOS_NOCHANGEDIR | FOS_DONTADDTORECENT)); // filesystem objects only; no recent places
|
||||
customize(fileDialog.get());
|
||||
|
||||
auto hr{ fileDialog->Show(parentHwnd) };
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))
|
||||
{
|
||||
co_return winrt::hstring{};
|
||||
}
|
||||
THROW_HR(hr);
|
||||
}
|
||||
|
||||
winrt::com_ptr<IShellItem> result;
|
||||
THROW_IF_FAILED(fileDialog->GetResult(result.put()));
|
||||
|
||||
wil::unique_cotaskmem_string filePath;
|
||||
THROW_IF_FAILED(result->GetDisplayName(SIGDN_FILESYSPATH, &filePath));
|
||||
|
||||
co_return winrt::hstring{ filePath.get() };
|
||||
}
|
||||
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenImagePicker(HWND parentHwnd);
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings
|
||||
{
|
||||
winrt::hstring GetSelectedItemTag(winrt::Windows::Foundation::IInspectable const& comboBoxAsInspectable);
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "CascadiaSettings.h"
|
||||
#include "CascadiaSettings.g.cpp"
|
||||
|
||||
#include "FileUtils.h"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
|
@ -880,3 +882,12 @@ void CascadiaSettings::CurrentDefaultTerminal(const Model::DefaultTerminal& term
|
|||
{
|
||||
_currentDefaultTerminal = terminal;
|
||||
}
|
||||
|
||||
void CascadiaSettings::ExportFile(winrt::hstring path, winrt::hstring content)
|
||||
{
|
||||
try
|
||||
{
|
||||
winrt::Microsoft::Terminal::Settings::Model::WriteUTF8FileAtomic({ path.c_str() }, til::u16u8(content));
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
static winrt::hstring DefaultSettingsPath();
|
||||
static winrt::hstring ApplicationDisplayName();
|
||||
static winrt::hstring ApplicationVersion();
|
||||
static void ExportFile(winrt::hstring path, winrt::hstring content);
|
||||
|
||||
CascadiaSettings() noexcept = default;
|
||||
CascadiaSettings(const winrt::hstring& userJSON, const winrt::hstring& inboxJSON);
|
||||
|
|
|
@ -19,6 +19,8 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
static String ApplicationDisplayName { get; };
|
||||
static String ApplicationVersion { get; };
|
||||
|
||||
static void ExportFile(String path, String content);
|
||||
|
||||
CascadiaSettings(String userJSON, String inboxJSON);
|
||||
|
||||
CascadiaSettings Copy();
|
||||
|
|
33
src/cascadia/WinRTUtils/Utils.cpp
Normal file
33
src/cascadia/WinRTUtils/Utils.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
#include "Utils.h"
|
||||
|
||||
// Function Description:
|
||||
// - Helper that opens a file picker pre-seeded with image file types.
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenImagePicker(HWND parentHwnd)
|
||||
{
|
||||
static constexpr COMDLG_FILTERSPEC supportedImageFileTypes[] = {
|
||||
{ L"All Supported Bitmap Types (*.jpg, *.jpeg, *.png, *.bmp, *.gif, *.tiff, *.ico)", L"*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.tiff;*.ico" },
|
||||
{ L"All Files (*.*)", L"*.*" }
|
||||
};
|
||||
|
||||
static constexpr winrt::guid clientGuidImagePicker{ 0x55675F54, 0x74A1, 0x4552, { 0xA3, 0x9D, 0x94, 0xAE, 0x85, 0xD8, 0xF2, 0x7A } };
|
||||
return OpenFilePicker(parentHwnd, [](auto&& dialog) {
|
||||
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidImagePicker));
|
||||
try
|
||||
{
|
||||
auto pictureFolderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_PicturesLibrary, KF_FLAG_DEFAULT, nullptr) };
|
||||
dialog->SetDefaultFolder(pictureFolderShellItem.get());
|
||||
}
|
||||
CATCH_LOG(); // non-fatal
|
||||
|
||||
#pragma warning(suppress : 26485) // so we can pass in the supportedImageFileTypes without the analyzer complaining
|
||||
THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedImageFileTypes), supportedImageFileTypes));
|
||||
THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
|
||||
THROW_IF_FAILED(dialog->SetDefaultExtension(L"jpg;jpeg;png;bmp;gif;tiff;ico"));
|
||||
});
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
</ClCompile>
|
||||
<ClCompile Include="LibraryResources.cpp" />
|
||||
<ClCompile Include="ScopedResourceLoader.cpp" />
|
||||
<ClCompile Include="Utils.cpp" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= idl Files ======================== -->
|
||||
<ItemGroup>
|
||||
|
|
|
@ -19,3 +19,51 @@ inline winrt::Windows::Foundation::Rect ScaleRect(winrt::Windows::Foundation::Re
|
|||
rect.Height = base::ClampMul(rect.Height, scaleLocal);
|
||||
return rect;
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - This function presents a File Open "common dialog" and returns its selected file asynchronously.
|
||||
// Parameters:
|
||||
// - customize: A lambda that receives an IFileDialog* to customize.
|
||||
// Return value:
|
||||
// (async) path to the selected item.
|
||||
template<typename TLambda>
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> FilePicker(HWND parentHwnd, bool saveDialog, TLambda&& customize)
|
||||
{
|
||||
auto fileDialog{ saveDialog ? winrt::create_instance<IFileDialog>(CLSID_FileSaveDialog) :
|
||||
winrt::create_instance<IFileDialog>(CLSID_FileOpenDialog) };
|
||||
DWORD flags{};
|
||||
THROW_IF_FAILED(fileDialog->GetOptions(&flags));
|
||||
THROW_IF_FAILED(fileDialog->SetOptions(flags | FOS_FORCEFILESYSTEM | FOS_NOCHANGEDIR | FOS_DONTADDTORECENT)); // filesystem objects only; no recent places
|
||||
customize(fileDialog.get());
|
||||
|
||||
const auto hr{ fileDialog->Show(parentHwnd) };
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))
|
||||
{
|
||||
co_return winrt::hstring{};
|
||||
}
|
||||
THROW_HR(hr);
|
||||
}
|
||||
|
||||
winrt::com_ptr<IShellItem> result;
|
||||
THROW_IF_FAILED(fileDialog->GetResult(result.put()));
|
||||
|
||||
wil::unique_cotaskmem_string filePath;
|
||||
THROW_IF_FAILED(result->GetDisplayName(SIGDN_FILESYSPATH, &filePath));
|
||||
|
||||
co_return winrt::hstring{ filePath.get() };
|
||||
}
|
||||
|
||||
template<typename TLambda>
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenFilePicker(HWND parentHwnd, TLambda&& customize)
|
||||
{
|
||||
return FilePicker(parentHwnd, false, customize);
|
||||
}
|
||||
template<typename TLambda>
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> SaveFilePicker(HWND parentHwnd, TLambda&& customize)
|
||||
{
|
||||
return FilePicker(parentHwnd, true, customize);
|
||||
}
|
||||
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenImagePicker(HWND parentHwnd);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// pch.h
|
||||
|
@ -31,3 +31,6 @@
|
|||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.System.h>
|
||||
|
||||
#include <shlobj.h>
|
||||
#include <shobjidl_core.h>
|
||||
|
|
Loading…
Reference in a new issue