mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 10:46:33 +02:00
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:
committed by
GitHub
parent
fd8fc679be
commit
619ed234a9
@@ -171,49 +171,49 @@ WindowState get_window_state(HWND hwnd) {
|
||||
return RESTORED;
|
||||
}
|
||||
|
||||
bool is_process_elevated() {
|
||||
HANDLE token = nullptr;
|
||||
bool elevated = false;
|
||||
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
|
||||
TOKEN_ELEVATION elevation;
|
||||
DWORD size;
|
||||
if (GetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation), &size)) {
|
||||
elevated = (elevation.TokenIsElevated != 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (token) {
|
||||
CloseHandle(token);
|
||||
}
|
||||
|
||||
return elevated;
|
||||
}
|
||||
|
||||
bool drop_elevated_privileges() {
|
||||
HANDLE token = nullptr;
|
||||
LPCTSTR lpszPrivilege = SE_SECURITY_NAME;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_DEFAULT | WRITE_OWNER, &token)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PSID medium_sid = NULL;
|
||||
if (!::ConvertStringSidToSid(SDDL_ML_MEDIUM, &medium_sid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TOKEN_MANDATORY_LABEL label = { 0 };
|
||||
label.Label.Attributes = SE_GROUP_INTEGRITY;
|
||||
label.Label.Sid = medium_sid;
|
||||
DWORD size = (DWORD)sizeof(TOKEN_MANDATORY_LABEL) + ::GetLengthSid(medium_sid);
|
||||
|
||||
BOOL result = SetTokenInformation(token, TokenIntegrityLevel, &label, size);
|
||||
LocalFree(medium_sid);
|
||||
CloseHandle(token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_process_elevated() {
|
||||
HANDLE token = nullptr;
|
||||
bool elevated = false;
|
||||
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
|
||||
TOKEN_ELEVATION elevation;
|
||||
DWORD size;
|
||||
if (GetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation), &size)) {
|
||||
elevated = (elevation.TokenIsElevated != 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (token) {
|
||||
CloseHandle(token);
|
||||
}
|
||||
|
||||
return elevated;
|
||||
}
|
||||
|
||||
bool drop_elevated_privileges() {
|
||||
HANDLE token = nullptr;
|
||||
LPCTSTR lpszPrivilege = SE_SECURITY_NAME;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_DEFAULT | WRITE_OWNER, &token)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PSID medium_sid = NULL;
|
||||
if (!::ConvertStringSidToSid(SDDL_ML_MEDIUM, &medium_sid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TOKEN_MANDATORY_LABEL label = { 0 };
|
||||
label.Label.Attributes = SE_GROUP_INTEGRITY;
|
||||
label.Label.Sid = medium_sid;
|
||||
DWORD size = (DWORD)sizeof(TOKEN_MANDATORY_LABEL) + ::GetLengthSid(medium_sid);
|
||||
|
||||
BOOL result = SetTokenInformation(token, TokenIntegrityLevel, &label, size);
|
||||
LocalFree(medium_sid);
|
||||
CloseHandle(token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::wstring get_process_path(DWORD pid) noexcept {
|
||||
auto process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, TRUE, pid);
|
||||
std::wstring name;
|
||||
@@ -225,12 +225,93 @@ std::wstring get_process_path(DWORD pid) noexcept {
|
||||
}
|
||||
name.resize(name_length);
|
||||
CloseHandle(process);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
std::wstring get_process_path(HWND window) noexcept {
|
||||
const static std::wstring app_frame_host = L"ApplicationFrameHost.exe";
|
||||
bool run_elevated(const std::wstring& file, const std::wstring& params) {
|
||||
SHELLEXECUTEINFOW exec_info = { 0 };
|
||||
exec_info.cbSize = sizeof(SHELLEXECUTEINFOW);
|
||||
exec_info.lpVerb = L"runas";
|
||||
exec_info.lpFile = file.c_str();
|
||||
exec_info.lpParameters = params.c_str();
|
||||
exec_info.hwnd = 0;
|
||||
exec_info.fMask = SEE_MASK_NOCLOSEPROCESS;
|
||||
exec_info.lpDirectory = 0;
|
||||
exec_info.hInstApp = 0;
|
||||
|
||||
if (ShellExecuteExW(&exec_info)) {
|
||||
return exec_info.hProcess != nullptr;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool run_non_elevated(const std::wstring& file, const std::wstring& params) {
|
||||
auto executable_args = file;
|
||||
if (!params.empty()) {
|
||||
executable_args += L" " + params;
|
||||
}
|
||||
|
||||
HWND hwnd = GetShellWindow();
|
||||
if (!hwnd) {
|
||||
return false;
|
||||
}
|
||||
DWORD pid;
|
||||
GetWindowThreadProcessId(hwnd, &pid);
|
||||
|
||||
winrt::handle process{ OpenProcess(PROCESS_CREATE_PROCESS, FALSE, pid) };
|
||||
if (!process) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SIZE_T size = 0;
|
||||
|
||||
InitializeProcThreadAttributeList(nullptr, 1, 0, &size);
|
||||
auto pproc_buffer = std::make_unique<char[]>(size);
|
||||
auto pptal = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(pproc_buffer.get());
|
||||
|
||||
if (!InitializeProcThreadAttributeList(pptal, 1, 0, &size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE process_handle = process.get();
|
||||
if (!pptal || !UpdateProcThreadAttribute(pptal,
|
||||
0,
|
||||
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
|
||||
&process_handle,
|
||||
sizeof(process_handle),
|
||||
nullptr,
|
||||
nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
STARTUPINFOEX siex = { 0 };
|
||||
siex.lpAttributeList = pptal;
|
||||
siex.StartupInfo.cb = sizeof(siex);
|
||||
|
||||
PROCESS_INFORMATION process_info = { 0 };
|
||||
auto succedded = CreateProcessW(file.c_str(),
|
||||
const_cast<LPWSTR>(executable_args.c_str()),
|
||||
nullptr,
|
||||
nullptr,
|
||||
FALSE,
|
||||
EXTENDED_STARTUPINFO_PRESENT,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&siex.StartupInfo,
|
||||
&process_info);
|
||||
if (process_info.hProcess) {
|
||||
CloseHandle(process_info.hProcess);
|
||||
}
|
||||
if (process_info.hThread) {
|
||||
CloseHandle(process_info.hThread);
|
||||
}
|
||||
return succedded;
|
||||
}
|
||||
|
||||
std::wstring get_process_path(HWND window) noexcept {
|
||||
const static std::wstring app_frame_host = L"ApplicationFrameHost.exe";
|
||||
DWORD pid{};
|
||||
GetWindowThreadProcessId(window, &pid);
|
||||
auto name = get_process_path(pid);
|
||||
@@ -254,19 +335,29 @@ std::wstring get_process_path(HWND window) noexcept {
|
||||
if (new_pid != pid) {
|
||||
return get_process_path(new_pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
std::wstring get_product_version() {
|
||||
static std::wstring version = std::to_wstring(VERSION_MAJOR) +
|
||||
L"." + std::to_wstring(VERSION_MINOR) +
|
||||
L"." + std::to_wstring(VERSION_REVISION) +
|
||||
L"." + std::to_wstring(VERSION_BUILD);
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
std::wstring get_product_version() {
|
||||
static std::wstring version = std::to_wstring(VERSION_MAJOR) +
|
||||
L"." + std::to_wstring(VERSION_MINOR) +
|
||||
L"." + std::to_wstring(VERSION_REVISION) +
|
||||
L"." + std::to_wstring(VERSION_BUILD);
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
std::wstring get_resource_string(UINT resource_id, HINSTANCE instance, const wchar_t* fallback) {
|
||||
wchar_t* text_ptr;
|
||||
auto length = LoadStringW(instance, resource_id, reinterpret_cast<wchar_t*>(&text_ptr), 0);
|
||||
if (length == 0) {
|
||||
return fallback;
|
||||
} else {
|
||||
return { text_ptr, static_cast<std::size_t>(length) };
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring get_module_filename(HMODULE mod)
|
||||
{
|
||||
wchar_t buffer[MAX_PATH + 1];
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
|
||||
@@ -51,6 +52,12 @@ bool is_process_elevated();
|
||||
// Drops the elevated privilages if present
|
||||
bool drop_elevated_privileges();
|
||||
|
||||
// Run command as elevated user, returns true if succeeded
|
||||
bool run_elevated(const std::wstring& file, const std::wstring& params);
|
||||
|
||||
// Run command as non-elevated user, returns true if succeeded
|
||||
bool run_non_elevated(const std::wstring& file, const std::wstring& params);
|
||||
|
||||
// Get the executable path or module name for modern apps
|
||||
std::wstring get_process_path(DWORD pid) noexcept;
|
||||
// Get the executable path or module name for modern apps
|
||||
@@ -60,3 +67,11 @@ std::wstring get_product_version();
|
||||
|
||||
std::wstring get_module_filename(HMODULE mod = nullptr);
|
||||
std::wstring get_module_folderpath(HMODULE mod = nullptr);
|
||||
|
||||
// Get a string from the resource file
|
||||
std::wstring get_resource_string(UINT resource_id, HINSTANCE instance, const wchar_t* fallback);
|
||||
// Wrapper for getting a string from the resource file. Returns the resource id text when fails.
|
||||
// Requires that
|
||||
// extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
// is added to the .cpp file.
|
||||
#define GET_RESOURCE_STRING(resource_id) get_resource_string(resource_id, reinterpret_cast<HINSTANCE>(&__ImageBase), L#resource_id)
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
37
src/runner/restart_elevated.cpp
Normal file
37
src/runner/restart_elevated.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
5
src/runner/restart_elevated.h
Normal file
5
src/runner/restart_elevated.h
Normal 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.
@@ -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" />
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -29,7 +29,11 @@ export class CustomActionSettingsControl extends BaseSettingsControl {
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<Stack>
|
||||
<Label>{this.state.property_values.display_name}</Label>
|
||||
{
|
||||
this.state.property_values.display_name ?
|
||||
<Label>{this.state.property_values.display_name}</Label>
|
||||
: null
|
||||
}
|
||||
{
|
||||
this.state.property_values.value ?
|
||||
<Text styles ={{
|
||||
|
||||
@@ -3,16 +3,21 @@ import { Stack, Text, PrimaryButton, Label, Link, loadTheme } from 'office-ui-fa
|
||||
import { BoolToggleSettingsControl } from './BoolToggleSettingsControl'
|
||||
import { ChoiceGroupSettingsControl } from './ChoiceGroupSettingsControl'
|
||||
import { Separator } from 'office-ui-fabric-react/lib/Separator';
|
||||
import { CustomActionSettingsControl } from './CustomActionSettingsControl';
|
||||
|
||||
export class GeneralSettings extends React.Component <any, any> {
|
||||
references: any = {};
|
||||
startup_reference: any;
|
||||
elevated_reference: any;
|
||||
restart_reference: any;
|
||||
theme_reference: any;
|
||||
parent_on_change: Function;
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.references={};
|
||||
this.startup_reference=null;
|
||||
this.elevated_reference=null;
|
||||
this.restart_reference=null;
|
||||
this.parent_on_change = props.on_change;
|
||||
this.state = {
|
||||
settings_key: props.settings_key,
|
||||
@@ -38,6 +43,7 @@ export class GeneralSettings extends React.Component <any, any> {
|
||||
let result : any = {};
|
||||
result[this.state.settings_key]= {
|
||||
startup: this.startup_reference.get_value().value,
|
||||
run_elevated: this.elevated_reference.get_value().value,
|
||||
theme: this.theme_reference.get_value().value,
|
||||
enabled: enabled
|
||||
};
|
||||
@@ -120,6 +126,34 @@ export class GeneralSettings extends React.Component <any, any> {
|
||||
on_change={this.parent_on_change}
|
||||
ref={(input) => {this.startup_reference=input;}}
|
||||
/>
|
||||
<BoolToggleSettingsControl
|
||||
setting={{display_name: 'By default, run PowerToys with elevated privileges', value: this.state.settings.general.run_elevated}}
|
||||
on_change={this.parent_on_change}
|
||||
ref={(input) => {this.elevated_reference=input;}}
|
||||
/>
|
||||
<CustomActionSettingsControl
|
||||
setting={{
|
||||
display_name: '',
|
||||
value: this.state.settings.general.is_elevated ?
|
||||
'PowerToys is currently running with elevated privileges. You can restart it to run non-elevated only for this session, without changing the default setting.' :
|
||||
'PowerToys is currently running without elevated privileges. You can restart it to run elevated only for this session, without changing the default setting.',
|
||||
button_text: this.state.settings.general.is_elevated ?
|
||||
'Restart without elevated privileges' :
|
||||
'Restart with elevated privileges'
|
||||
}}
|
||||
action_name={'restart_elevation'}
|
||||
action_callback={(action_name: any, value:any) => {
|
||||
(window as any).output_from_webview(JSON.stringify({
|
||||
action: {
|
||||
general: {
|
||||
action_name,
|
||||
value
|
||||
}
|
||||
}
|
||||
}));
|
||||
}}
|
||||
ref={(input) => {this.restart_reference=input;}}
|
||||
/>
|
||||
<ChoiceGroupSettingsControl
|
||||
setting={{display_name: 'Chose Settings color',
|
||||
value: this.state.settings.general.theme,
|
||||
|
||||
2
src/settings/settings-html/dist/bundle.js
vendored
2
src/settings/settings-html/dist/bundle.js
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user