Skip to content

Commit

Permalink
fix: 修复管理员身份运行时导入/导出闪退
Browse files Browse the repository at this point in the history
FileOpenPicker/FileSavePicker 不支持管理员身份,见 microsoft/WindowsAppSDK#2504
改为使用 IFileDialog
  • Loading branch information
Blinue committed Oct 19, 2022
1 parent a31244a commit d01ee48
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 65 deletions.
3 changes: 0 additions & 3 deletions src/Magpie.UI/AppSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,9 +383,6 @@ void AppSettings::Theme(uint32_t value) {
return;
}

static constexpr const char* SETTINGS[] = { "浅色","深色","系统" };
Logger::Get().Info(StrUtils::Concat("主题已更改为:", SETTINGS[value]));

_theme = value;
_themeChangedEvent(value);
}
Expand Down
2 changes: 0 additions & 2 deletions src/Magpie.UI/MainPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,6 @@ void MainPage::_UpdateTheme(bool updateIcons) {
if (updateIcons && IsLoaded()) {
_UpdateIcons(true);
}

Logger::Get().Info(StrUtils::Concat("当前主题:", isDarkTheme ? "深色" : "浅色"));
}

fire_and_forget MainPage::_LoadIcon(MUXC::NavigationViewItem const& item, const ScalingProfile& profile) {
Expand Down
160 changes: 103 additions & 57 deletions src/Magpie.UI/ScalingModesViewModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,10 @@
#include "EffectHelper.h"
#include "Logger.h"
#include "StrUtils.h"
#include <winrt/Windows.Storage.Pickers.h>
#include "Win32Utils.h"

using namespace ::Magpie::Core;
using namespace winrt;
using namespace Windows::Storage;
using namespace Windows::Storage::Pickers;


namespace winrt::Magpie::UI::implementation {
Expand Down Expand Up @@ -74,18 +71,58 @@ ScalingModesViewModel::ScalingModesViewModel() {
auto_revoke, { this, &ScalingModesViewModel::_ScalingModesService_Removed });
}

fire_and_forget ScalingModesViewModel::Export() const noexcept {
FileSavePicker savePicker;
savePicker.as<IInitializeWithWindow>()->Initialize(
(HWND)Application::Current().as<App>().HwndMain());
static std::optional<std::wstring> OpenFileDialog(IFileDialog* fileDialog) {
const COMDLG_FILTERSPEC fileType{ L"JSON", L"*.json" };
fileDialog->SetFileTypes(1, &fileType);
fileDialog->SetDefaultExtension(L"json");

savePicker.FileTypeChoices().Insert(L"JSON",
single_threaded_vector(std::vector{ hstring(L".json") }));
savePicker.SuggestedFileName(L"ScalingModes");
FILEOPENDIALOGOPTIONS options;
fileDialog->GetOptions(&options);
fileDialog->SetOptions(options | FOS_STRICTFILETYPES | FOS_FORCEFILESYSTEM);

StorageFile file = co_await savePicker.PickSaveFileAsync();
if (!file) {
co_return;
if (fileDialog->Show((HWND)Application::Current().as<App>().HwndMain()) != S_OK) {
// 被用户取消
return std::wstring();
}

com_ptr<IShellItem> file;
HRESULT hr = fileDialog->GetResult(file.put());
if (FAILED(hr)) {
Logger::Get().ComError("IFileSaveDialog::GetResult 失败", hr);
return std::nullopt;
}

wchar_t* fileName = nullptr;
hr = file->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &fileName);
if (FAILED(hr)) {
Logger::Get().ComError("IShellItem::GetDisplayName 失败", hr);
return std::nullopt;
}

std::wstring result(fileName);
CoTaskMemFree(fileName);
return std::move(result);
}

void ScalingModesViewModel::Export() const noexcept {
com_ptr<IFileSaveDialog> fileDialog;
HRESULT hr = CoCreateInstance(
CLSID_FileSaveDialog,
nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&fileDialog)
);
if (FAILED(hr)) {
Logger::Get().ComError("创建 IFileSaveDialog 失败", hr);
return;
}

fileDialog->SetFileName(L"ScalingModes");
fileDialog->SetTitle(L"导出缩放模式");

std::optional<std::wstring> fileName = OpenFileDialog(fileDialog.get());
if (!fileName.has_value() || fileName.value().empty()) {
return;
}

rapidjson::StringBuffer json;
Expand All @@ -94,10 +131,62 @@ fire_and_forget ScalingModesViewModel::Export() const noexcept {
ScalingModesService::Get().Export(writer);
writer.EndObject();

Win32Utils::WriteTextFile(file.Path().c_str(), { json.GetString(), json.GetLength() });
Win32Utils::WriteTextFile(fileName.value().c_str(), {json.GetString(), json.GetLength()});
}

static bool ImportImpl(bool legacy) {
com_ptr<IFileOpenDialog> fileDialog;
HRESULT hr = CoCreateInstance(
CLSID_FileOpenDialog,
nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&fileDialog)
);
if (FAILED(hr)) {
Logger::Get().ComError("创建 IFileOpenDialog 失败", hr);
return false;
}

fileDialog->SetTitle(legacy ? L"导入旧版缩放模式" : L"导入缩放模式");

std::optional<std::wstring> fileName = OpenFileDialog(fileDialog.get());
if (!fileName.has_value()) {
return false;
}
if (fileName.value().empty()) {
return true;
}

std::string json;
if (!Win32Utils::ReadTextFile(fileName.value().c_str(), json)) {
return false;
}

rapidjson::Document doc;
// 导入时放宽 json 格式限制
doc.ParseInsitu<rapidjson::kParseCommentsFlag | rapidjson::kParseTrailingCommasFlag>(json.data());
if (doc.HasParseError()) {
Logger::Get().Error(fmt::format("解析缩放模式失败\n\t错误码:{}", (int)doc.GetParseError()));
return false;
}

if (legacy) {
return ScalingModesService::Get().ImportLegacy(doc);
}

if (!doc.IsObject()) {
return false;
}

return ScalingModesService::Get().Import(((const rapidjson::Document&)doc).GetObj());
}

void ScalingModesViewModel::_Import(bool legacy) {
ShowErrorMessage(false);
if (!ImportImpl(legacy)) {
ShowErrorMessage(true);
}
}

void ScalingModesViewModel::DownscalingEffectIndex(int value) {
if (_downscalingEffectIndex == value) {
Expand Down Expand Up @@ -172,47 +261,4 @@ void ScalingModesViewModel::_ScalingModesService_Removed(uint32_t index) {
_scalingModes.RemoveAt(index);
}

static bool ReadScalingModes(const wchar_t* fileName, bool legacy) {
std::string json;
if (!Win32Utils::ReadTextFile(fileName, json)) {
return false;
}

rapidjson::Document doc;
// 导入时放宽 json 格式限制
doc.ParseInsitu<rapidjson::kParseCommentsFlag | rapidjson::kParseTrailingCommasFlag>(json.data());
if (doc.HasParseError()) {
Logger::Get().Error(fmt::format("解析缩放模式失败\n\t错误码:{}", (int)doc.GetParseError()));
return false;
}

if (legacy) {
return ScalingModesService::Get().ImportLegacy(doc);
}

if (!doc.IsObject()) {
return false;
}

return ScalingModesService::Get().Import(((const rapidjson::Document&)doc).GetObj());
}

fire_and_forget ScalingModesViewModel::_Import(bool legacy) {
ShowErrorMessage(false);

FileOpenPicker openPicker;
openPicker.as<IInitializeWithWindow>()->Initialize(
(HWND)Application::Current().as<App>().HwndMain());

openPicker.FileTypeFilter().Append(L".json");
StorageFile file = co_await openPicker.PickSingleFileAsync();
if (!file) {
co_return;
}

if (!ReadScalingModes(file.Path().c_str(), legacy)) {
ShowErrorMessage(true);
}
}

}
4 changes: 2 additions & 2 deletions src/Magpie.UI/ScalingModesViewModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ struct ScalingModesViewModel : ScalingModesViewModelT<ScalingModesViewModel> {
_propertyChangedEvent.remove(token);
}

fire_and_forget Export() const noexcept;
void Export() const noexcept;

void Import() {
_Import(false);
Expand Down Expand Up @@ -91,7 +91,7 @@ struct ScalingModesViewModel : ScalingModesViewModelT<ScalingModesViewModel> {

void _ScalingModesService_Removed(uint32_t index);

fire_and_forget _Import(bool legacy);
void _Import(bool legacy);

event<PropertyChangedEventHandler> _propertyChangedEvent;

Expand Down
3 changes: 2 additions & 1 deletion src/Magpie/XamlApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ bool XamlApp::Initialize(HINSTANCE hInstance, const wchar_t* arguments) {

_InitializeLogger();

Logger::Get().Info(fmt::format("程序启动\n\t版本:{}", MAGPIE_VERSION));
Logger::Get().Info(fmt::format("程序启动\n\t版本:{}\n\t管理员:{}",
MAGPIE_VERSION, Win32Utils::IsProcessElevated() ? "" : ""));

// SetTimer 之前推荐先调用 SetUserObjectInformation
{
Expand Down

0 comments on commit d01ee48

Please sign in to comment.