Do not run elevated by default (#884)

Make the runner not run as elevated by default. Add a setting for
"run PowerToys as elevated" and buttons to restart the process
with the different elevation levels.
This commit is contained in:
Bartosz Sosnowski
2019-12-16 18:36:52 +01:00
committed by GitHub
parent fd8fc679be
commit 619ed234a9
17 changed files with 351 additions and 81 deletions

View File

@@ -6,6 +6,7 @@
#include <common/windows_colors.h>
static std::wstring settings_theme = L"system";
static bool run_as_elevated = false;
json::JsonObject load_general_settings() {
auto loaded = PTSettingsHelper::load_general_settings();
@@ -13,6 +14,7 @@ json::JsonObject load_general_settings() {
if (settings_theme != L"dark" && settings_theme != L"light") {
settings_theme = L"system";
}
run_as_elevated = loaded.GetNamedBoolean(L"run_elevated", false);
return loaded;
}
@@ -27,6 +29,9 @@ json::JsonObject get_general_settings() {
}
result.SetNamedValue(L"enabled", std::move(enabled));
bool is_elevated = is_process_elevated();
result.SetNamedValue(L"is_elevated", json::value(is_elevated));
result.SetNamedValue(L"run_elevated", json::value(run_as_elevated));
result.SetNamedValue(L"theme", json::value(settings_theme));
result.SetNamedValue(L"system_theme", json::value(WindowsColors::is_dark_mode() ? L"dark" : L"light"));
result.SetNamedValue(L"powertoys_version", json::value(get_product_version()));
@@ -68,6 +73,7 @@ void apply_general_settings(const json::JsonObject& general_configs) {
}
}
}
run_as_elevated = general_configs.GetNamedBoolean(L"run_elevated", false);
if (json::has(general_configs, L"theme", json::JsonValueType::String)) {
settings_theme = general_configs.GetNamedString(L"theme");
}

View File

@@ -2,6 +2,7 @@
#include <common/json.h>
json::JsonObject load_general_settings();
json::JsonObject get_general_settings();
void apply_general_settings(const json::JsonObject & general_configs);
void start_initial_powertoys();

View File

@@ -7,6 +7,8 @@
#include "lowlevel_keyboard_event.h"
#include "trace.h"
#include "general_settings.h"
#include "restart_elevated.h"
#include "resource.h"
#include <common/dpi_aware.h>
@@ -14,6 +16,9 @@
#include "unhandled_exception_handler.h"
#endif
extern "C" IMAGE_DOS_HEADER __ImageBase;
void chdir_current_executable() {
// Change current directory to the path of the executable.
WCHAR executable_path[MAX_PATH];
@@ -24,16 +29,7 @@ void chdir_current_executable() {
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WCHAR username[UNLEN + 1];
DWORD username_length = UNLEN + 1;
GetUserNameW(username, &username_length);
auto runner_mutex = CreateMutexW(NULL, TRUE, (std::wstring(L"Local\\PowerToyRunMutex") + username).c_str());
if (runner_mutex == NULL || GetLastError() == ERROR_ALREADY_EXISTS) {
// The app is already running
return 0;
}
int runner() {
DPIAware::EnableDPIAwarenessForThisProcess();
#if _DEBUG && _WIN64
@@ -46,12 +42,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
start_tray_icon();
int result;
try {
// Singletons initialization order needs to be preserved, first events and
// then modules to guarantee the reverse destruction order.
powertoys_events();
modules();
chdir_current_executable();
// Load Powertyos DLLS
// For now only load known DLLs
@@ -76,11 +66,59 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
Trace::EventLaunch(get_product_version());
result = run_message_loop();
} catch (std::runtime_error& err) {
} catch (std::runtime_error & err) {
std::string err_what = err.what();
MessageBoxW(NULL, std::wstring(err_what.begin(),err_what.end()).c_str(), L"Error", MB_OK | MB_ICONERROR);
MessageBoxW(NULL, std::wstring(err_what.begin(), err_what.end()).c_str(), L"Error", MB_OK | MB_ICONERROR);
result = -1;
}
Trace::UnregisterProvider();
return result;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WCHAR username[UNLEN + 1];
DWORD username_length = UNLEN + 1;
GetUserNameW(username, &username_length);
auto runner_mutex = CreateMutexW(NULL, TRUE, (std::wstring(L"Local\\PowerToyRunMutex") + username).c_str());
if (runner_mutex == NULL || GetLastError() == ERROR_ALREADY_EXISTS) {
// The app is already running
return 0;
}
int result = 0;
try {
// Singletons initialization order needs to be preserved, first events and
// then modules to guarantee the reverse destruction order.
SystemMenuHelperInstace();
powertoys_events();
modules();
auto general_settings = load_general_settings();
int rvalue = 0;
if (is_process_elevated() ||
general_settings.GetNamedBoolean(L"run_elevated", false) == false ||
strcmp(lpCmdLine, "--dont-elevate") == 0) {
result = runner();
}
else {
schedule_restart_as_elevated();
result = 0;
}
}
catch (std::runtime_error & err) {
std::string err_what = err.what();
MessageBoxW(NULL, std::wstring(err_what.begin(), err_what.end()).c_str(), GET_RESOURCE_STRING(IDS_ERROR).c_str(), MB_OK | MB_ICONERROR);
result = -1;
}
ReleaseMutex(runner_mutex);
CloseHandle(runner_mutex);
if (is_restart_scheduled()) {
if (restart_if_scheduled() == false) {
auto text = is_process_elevated() ? GET_RESOURCE_STRING(IDS_COULDNOT_RESTART_NONELEVATED) :
GET_RESOURCE_STRING(IDS_COULDNOT_RESTART_ELEVATED);
MessageBoxW(NULL, text.c_str(), GET_RESOURCE_STRING(IDS_ERROR).c_str(), MB_OK | MB_ICONERROR);
result = -1;
}
}
stop_tray_icon();
return result;
}

View File

@@ -1,5 +1,8 @@
#define APPICON 101
#define ID_TRAY_MENU 102
#define IDS_COULDNOT_RESTART_NONELEVATED 103
#define IDS_COULDNOT_RESTART_ELEVATED 104
#define IDS_ERROR 105
#define ID_EXIT_MENU_COMMAND 40001
#define ID_SETTINGS_MENU_COMMAND 40002
#define ID_ABOUT_MENU_COMMAND 40003

View File

@@ -0,0 +1,37 @@
#include "pch.h"
#include "restart_elevated.h"
#include "common/common.h"
enum State {
None,
RestartAsElevated,
RestartAsNonElevated
};
static State state = None;
void schedule_restart_as_elevated() {
state = RestartAsElevated;
}
void schedule_restart_as_non_elevated() {
state = RestartAsNonElevated;
}
bool is_restart_scheduled() {
return state != None;
}
bool restart_if_scheduled() {
// Make sure we have enough room, even for the long (\\?\) paths
constexpr DWORD exe_path_size = 0xFFFF;
auto exe_path = std::make_unique<wchar_t[]>(exe_path_size);
GetModuleFileNameW(nullptr, exe_path.get(), exe_path_size);
switch (state) {
case RestartAsElevated:
return run_elevated(exe_path.get(), {});
case RestartAsNonElevated:
return run_non_elevated(exe_path.get(), L"--dont-elevate");
default:
return false;
}
}

View File

@@ -0,0 +1,5 @@
#pragma once
void schedule_restart_as_elevated();
void schedule_restart_as_non_elevated();
bool is_restart_scheduled();
bool restart_if_scheduled();

Binary file not shown.

View File

@@ -63,7 +63,7 @@
<PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<UACExecutionLevel>HighestAvailable</UACExecutionLevel>
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
<Manifest>
@@ -88,7 +88,7 @@
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<UACExecutionLevel>HighestAvailable</UACExecutionLevel>
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
<Manifest>
@@ -106,6 +106,7 @@
<ClCompile Include="powertoys_events.cpp" />
<ClCompile Include="powertoy_module.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="restart_elevated.cpp" />
<ClCompile Include="settings_window.cpp" />
<ClCompile Include="system_menu_helper.cpp" />
<ClCompile Include="trace.cpp" />
@@ -121,6 +122,7 @@
<ClInclude Include="powertoys_events.h" />
<ClInclude Include="powertoy_module.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="restart_elevated.h" />
<ClInclude Include="settings_window.h" />
<ClInclude Include="system_menu_helper.h" />
<ClInclude Include="trace.h" />

View File

@@ -36,6 +36,9 @@
<ClCompile Include="system_menu_helper.cpp">
<Filter>Utils</Filter>
</ClCompile>
<ClCompile Include="restart_elevated.cpp">
<Filter>Utils</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
@@ -73,6 +76,9 @@
<ClInclude Include="system_menu_helper.h">
<Filter>Utils</Filter>
</ClInclude>
<ClInclude Include="restart_elevated.h">
<Filter>Utils</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Utils">

View File

@@ -10,6 +10,8 @@
#include "tray_icon.h"
#include "general_settings.h"
#include "common/windows_colors.h"
#include "common/common.h"
#include "restart_elevated.h"
#include <common/json.h>
@@ -48,10 +50,25 @@ void dispatch_json_action_to_module(const json::JsonObject& powertoys_configs)
for (const auto& powertoy_element : powertoys_configs)
{
const std::wstring name{ powertoy_element.Key().c_str() };
if (modules().find(name) != modules().end())
// Currently, there is only one custom action in the general settings screen,
// so it has to be the "restart as (non-)elevated" button.
if (name == L"general")
{
if (is_process_elevated())
{
schedule_restart_as_non_elevated();
PostQuitMessage(0);
}
else
{
schedule_restart_as_elevated();
PostQuitMessage(0);
}
}
else if (modules().find(name) != modules().end())
{
const auto element = powertoy_element.Value().Stringify();
modules().at(name).call_custom_action(element.c_str());
modules().at(name).call_custom_action(element.c_str());
}
}
}

View File

@@ -54,7 +54,10 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
}
break;
case WM_DESTROY:
Shell_NotifyIcon(NIM_DELETE, &tray_icon_data);
if (tray_icon_created) {
Shell_NotifyIcon(NIM_DELETE, &tray_icon_data);
tray_icon_created = false;
}
PostQuitMessage(0);
break;
case WM_CLOSE:
@@ -171,3 +174,9 @@ void start_tray_icon() {
tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE;
}
}
void stop_tray_icon() {
if (tray_icon_created) {
SendMessage(tray_icon_hwnd, WM_CLOSE, 0, 0);
}
}

View File

@@ -1,6 +1,8 @@
#pragma once
// Start the Tray Icon
void start_tray_icon();
// Stop the Tray Icon
void stop_tray_icon();
// Open the Settings Window
void open_settings_window();
// Callback type to be called by the tray icon loop