mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-08 20:27:36 +02:00
Run the Settings process un-elevated when possible
and if not possible run it elevated and let the Settings process deal with it. Add wrappers for GetModuleFileNameW.
This commit is contained in:
committed by
Enrico Giordani
parent
5a3c852b32
commit
fd8fc679be
@@ -266,3 +266,36 @@ std::wstring get_product_version() {
|
|||||||
|
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::wstring get_module_filename(HMODULE mod)
|
||||||
|
{
|
||||||
|
wchar_t buffer[MAX_PATH + 1];
|
||||||
|
DWORD actual_length = GetModuleFileNameW(mod, buffer, MAX_PATH);
|
||||||
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||||
|
{
|
||||||
|
const DWORD long_path_length = 0xFFFF; // should be always enough
|
||||||
|
std::wstring long_filename(long_path_length, L'\0');
|
||||||
|
actual_length = GetModuleFileNameW(mod, long_filename.data(), long_path_length);
|
||||||
|
return long_filename.substr(0, actual_length);
|
||||||
|
}
|
||||||
|
return { buffer, actual_length };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring get_module_folderpath(HMODULE mod)
|
||||||
|
{
|
||||||
|
wchar_t buffer[MAX_PATH + 1];
|
||||||
|
DWORD actual_length = GetModuleFileNameW(mod, buffer, MAX_PATH);
|
||||||
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||||
|
{
|
||||||
|
const DWORD long_path_length = 0xFFFF; // should be always enough
|
||||||
|
std::wstring long_filename(long_path_length, L'\0');
|
||||||
|
actual_length = GetModuleFileNameW(mod, long_filename.data(), long_path_length);
|
||||||
|
PathRemoveFileSpecW(long_filename.data());
|
||||||
|
long_filename.resize(std::wcslen(long_filename.data()));
|
||||||
|
long_filename.shrink_to_fit();
|
||||||
|
return long_filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
PathRemoveFileSpecW(buffer);
|
||||||
|
return { buffer, (UINT)lstrlenW(buffer) };
|
||||||
|
}
|
||||||
|
|||||||
@@ -57,3 +57,6 @@ std::wstring get_process_path(DWORD pid) noexcept;
|
|||||||
std::wstring get_process_path(HWND hwnd) noexcept;
|
std::wstring get_process_path(HWND hwnd) noexcept;
|
||||||
|
|
||||||
std::wstring get_product_version();
|
std::wstring get_product_version();
|
||||||
|
|
||||||
|
std::wstring get_module_filename(HMODULE mod = nullptr);
|
||||||
|
std::wstring get_module_folderpath(HMODULE mod = nullptr);
|
||||||
|
|||||||
@@ -128,87 +128,37 @@ void receive_json_send_to_main_thread(const std::wstring& msg)
|
|||||||
dispatch_run_on_main_ui_thread(dispatch_received_json_callback, copy);
|
dispatch_run_on_main_ui_thread(dispatch_received_json_callback, copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD g_settings_process_id = 0;
|
|
||||||
|
|
||||||
void run_settings_window()
|
// Try to run the Settings process with non-elevated privileges.
|
||||||
|
BOOL run_settings_non_elevated(LPCWSTR executable_path, LPWSTR executable_args, PROCESS_INFORMATION* process_info)
|
||||||
{
|
{
|
||||||
STARTUPINFO startup_info = { sizeof(startup_info) };
|
|
||||||
PROCESS_INFORMATION process_info = { 0 };
|
|
||||||
HANDLE process = NULL;
|
|
||||||
HANDLE hToken = NULL;
|
|
||||||
STARTUPINFOEX siex = { 0 };
|
|
||||||
PPROC_THREAD_ATTRIBUTE_LIST pptal = NULL;
|
|
||||||
WCHAR executable_path[MAX_PATH];
|
|
||||||
GetModuleFileName(NULL, executable_path, MAX_PATH);
|
|
||||||
PathRemoveFileSpec(executable_path);
|
|
||||||
wcscat_s(executable_path, L"\\PowerToysSettings.exe");
|
|
||||||
WCHAR executable_args[MAX_PATH * 3];
|
|
||||||
|
|
||||||
const std::wstring settings_theme_setting{ get_general_settings().GetNamedString(L"theme").c_str() };
|
|
||||||
std::wstring settings_theme;
|
|
||||||
if (settings_theme_setting == L"dark" || (settings_theme_setting == L"system" && WindowsColors::is_dark_mode()))
|
|
||||||
{
|
|
||||||
settings_theme = L" dark"; // Include arg separating space
|
|
||||||
}
|
|
||||||
// Generate unique names for the pipes, if getting a UUID is possible
|
|
||||||
std::wstring powertoys_pipe_name(L"\\\\.\\pipe\\powertoys_runner_");
|
|
||||||
std::wstring settings_pipe_name(L"\\\\.\\pipe\\powertoys_settings_");
|
|
||||||
SIZE_T size = 0;
|
|
||||||
UUID temp_uuid;
|
|
||||||
UuidCreate(&temp_uuid);
|
|
||||||
wchar_t* uuid_chars;
|
|
||||||
UuidToString(&temp_uuid, (RPC_WSTR*)&uuid_chars);
|
|
||||||
if (uuid_chars != NULL)
|
|
||||||
{
|
|
||||||
powertoys_pipe_name += std::wstring(uuid_chars);
|
|
||||||
settings_pipe_name += std::wstring(uuid_chars);
|
|
||||||
RpcStringFree((RPC_WSTR*)&uuid_chars);
|
|
||||||
uuid_chars = NULL;
|
|
||||||
}
|
|
||||||
DWORD powertoys_pid = GetCurrentProcessId();
|
|
||||||
// Arguments for calling the settings executable:
|
|
||||||
// C:\powertoys_path\PowerToysSettings.exe powertoys_pipe settings_pipe powertoys_pid
|
|
||||||
// powertoys_pipe - PowerToys pipe server.
|
|
||||||
// settings_pipe - Settings pipe server.
|
|
||||||
// powertoys_pid - PowerToys process pid.
|
|
||||||
// settings_theme - pass "dark" to start the settings window in dark mode
|
|
||||||
wcscpy_s(executable_args, L"\"");
|
|
||||||
wcscat_s(executable_args, executable_path);
|
|
||||||
wcscat_s(executable_args, L"\"");
|
|
||||||
wcscat_s(executable_args, L" ");
|
|
||||||
wcscat_s(executable_args, powertoys_pipe_name.c_str());
|
|
||||||
wcscat_s(executable_args, L" ");
|
|
||||||
wcscat_s(executable_args, settings_pipe_name.c_str());
|
|
||||||
wcscat_s(executable_args, L" ");
|
|
||||||
wcscat_s(executable_args, std::to_wstring(powertoys_pid).c_str());
|
|
||||||
wcscat_s(executable_args, settings_theme.c_str());
|
|
||||||
|
|
||||||
// Run the Settings process with non-elevated privileges
|
|
||||||
|
|
||||||
HWND hwnd = GetShellWindow();
|
HWND hwnd = GetShellWindow();
|
||||||
if (!hwnd)
|
if (!hwnd)
|
||||||
{
|
{
|
||||||
goto LExit;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD pid;
|
DWORD pid;
|
||||||
GetWindowThreadProcessId(hwnd, &pid);
|
GetWindowThreadProcessId(hwnd, &pid);
|
||||||
|
|
||||||
process = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, pid);
|
winrt::handle process{ OpenProcess(PROCESS_CREATE_PROCESS, FALSE, pid) };
|
||||||
if (!process)
|
if (!process)
|
||||||
{
|
{
|
||||||
goto LExit;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SIZE_T size = 0;
|
||||||
InitializeProcThreadAttributeList(nullptr, 1, 0, &size);
|
InitializeProcThreadAttributeList(nullptr, 1, 0, &size);
|
||||||
pptal = (PPROC_THREAD_ATTRIBUTE_LIST) new char[size];
|
auto pproc_buffer = std::unique_ptr<char[]>{new (std::nothrow)char[size]};
|
||||||
|
auto pptal = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(pproc_buffer.get());
|
||||||
if (!pptal)
|
if (!pptal)
|
||||||
{
|
{
|
||||||
goto LExit;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!InitializeProcThreadAttributeList(pptal, 1, 0, &size))
|
if (!InitializeProcThreadAttributeList(pptal, 1, 0, &size))
|
||||||
{
|
{
|
||||||
goto LExit;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!UpdateProcThreadAttribute(pptal,
|
if (!UpdateProcThreadAttribute(pptal,
|
||||||
@@ -219,30 +169,116 @@ void run_settings_window()
|
|||||||
nullptr,
|
nullptr,
|
||||||
nullptr))
|
nullptr))
|
||||||
{
|
{
|
||||||
goto LExit;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STARTUPINFOEX siex = { 0 };
|
||||||
siex.lpAttributeList = pptal;
|
siex.lpAttributeList = pptal;
|
||||||
siex.StartupInfo.cb = sizeof(siex);
|
siex.StartupInfo.cb = sizeof(siex);
|
||||||
|
|
||||||
if (!CreateProcessW(executable_path,
|
BOOL process_created = CreateProcessW(executable_path,
|
||||||
executable_args,
|
executable_args,
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
FALSE,
|
FALSE,
|
||||||
EXTENDED_STARTUPINFO_PRESENT,
|
EXTENDED_STARTUPINFO_PRESENT,
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
&siex.StartupInfo,
|
&siex.StartupInfo,
|
||||||
&process_info))
|
process_info);
|
||||||
|
|
||||||
|
return process_created;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD g_settings_process_id = 0;
|
||||||
|
|
||||||
|
void run_settings_window()
|
||||||
|
{
|
||||||
|
PROCESS_INFORMATION process_info = { 0 };
|
||||||
|
HANDLE hToken = nullptr;
|
||||||
|
|
||||||
|
// Arguments for calling the settings executable:
|
||||||
|
// "C:\powertoys_path\PowerToysSettings.exe" powertoys_pipe settings_pipe powertoys_pid settings_theme
|
||||||
|
// powertoys_pipe: PowerToys pipe server.
|
||||||
|
// settings_pipe : Settings pipe server.
|
||||||
|
// powertoys_pid : PowerToys process pid.
|
||||||
|
// settings_theme: pass "dark" to start the settings window in dark mode
|
||||||
|
|
||||||
|
// Arg 1: executable path.
|
||||||
|
std::wstring executable_path = get_module_folderpath();
|
||||||
|
executable_path.append(L"\\PowerToysSettings.exe");
|
||||||
|
|
||||||
|
// Arg 2: pipe server. Generate unique names for the pipes, if getting a UUID is possible.
|
||||||
|
std::wstring powertoys_pipe_name(L"\\\\.\\pipe\\powertoys_runner_");
|
||||||
|
std::wstring settings_pipe_name(L"\\\\.\\pipe\\powertoys_settings_");
|
||||||
|
UUID temp_uuid;
|
||||||
|
UuidCreate(&temp_uuid);
|
||||||
|
wchar_t* uuid_chars;
|
||||||
|
UuidToString(&temp_uuid, (RPC_WSTR*)&uuid_chars);
|
||||||
|
if (uuid_chars != nullptr)
|
||||||
{
|
{
|
||||||
goto LExit;
|
powertoys_pipe_name += std::wstring(uuid_chars);
|
||||||
|
settings_pipe_name += std::wstring(uuid_chars);
|
||||||
|
RpcStringFree((RPC_WSTR*)&uuid_chars);
|
||||||
|
uuid_chars = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arg 3: process pid.
|
||||||
|
DWORD powertoys_pid = GetCurrentProcessId();
|
||||||
|
|
||||||
|
// Arg 4: settings theme.
|
||||||
|
const std::wstring settings_theme_setting{ get_general_settings().GetNamedString(L"theme").c_str() };
|
||||||
|
std::wstring settings_theme;
|
||||||
|
if (settings_theme_setting == L"dark" || (settings_theme_setting == L"system" && WindowsColors::is_dark_mode()))
|
||||||
|
{
|
||||||
|
settings_theme = L"dark";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring executable_args = L"\"";
|
||||||
|
executable_args.append(executable_path);
|
||||||
|
executable_args.append(L"\" ");
|
||||||
|
executable_args.append(powertoys_pipe_name);
|
||||||
|
executable_args.append(L" ");
|
||||||
|
executable_args.append(settings_pipe_name);
|
||||||
|
executable_args.append(L" ");
|
||||||
|
executable_args.append(std::to_wstring(powertoys_pid));
|
||||||
|
executable_args.append(L" ");
|
||||||
|
executable_args.append(settings_theme);
|
||||||
|
|
||||||
|
BOOL process_created = false;
|
||||||
|
|
||||||
|
if (is_process_elevated())
|
||||||
|
{
|
||||||
|
process_created = run_settings_non_elevated(executable_path.c_str(), executable_args.data(), &process_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FALSE == process_created)
|
||||||
|
{
|
||||||
|
// The runner is not elevated or we failed to create the process using the
|
||||||
|
// attribute list from Windows Explorer (this happens when PowerToys is executed
|
||||||
|
// as Administrator from a non-Administrator user or an error occur trying).
|
||||||
|
// In the second case the Settings process will run elevated.
|
||||||
|
STARTUPINFO startup_info = { sizeof(startup_info) };
|
||||||
|
if (!CreateProcessW(executable_path.c_str(),
|
||||||
|
executable_args.data(),
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
FALSE,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
&startup_info,
|
||||||
|
&process_info))
|
||||||
|
{
|
||||||
|
goto LExit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
|
||||||
{
|
{
|
||||||
goto LExit;
|
goto LExit;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_settings_ipc = new TwoWayPipeMessageIPC(powertoys_pipe_name, settings_pipe_name, receive_json_send_to_main_thread);
|
current_settings_ipc = new TwoWayPipeMessageIPC(powertoys_pipe_name, settings_pipe_name, receive_json_send_to_main_thread);
|
||||||
current_settings_ipc->start(hToken);
|
current_settings_ipc->start(hToken);
|
||||||
g_settings_process_id = process_info.dwProcessId;
|
g_settings_process_id = process_info.dwProcessId;
|
||||||
@@ -265,21 +301,11 @@ LExit:
|
|||||||
CloseHandle(process_info.hThread);
|
CloseHandle(process_info.hThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pptal)
|
|
||||||
{
|
|
||||||
delete[](char*) pptal;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process)
|
|
||||||
{
|
|
||||||
CloseHandle(process);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current_settings_ipc)
|
if (current_settings_ipc)
|
||||||
{
|
{
|
||||||
current_settings_ipc->end();
|
current_settings_ipc->end();
|
||||||
delete current_settings_ipc;
|
delete current_settings_ipc;
|
||||||
current_settings_ipc = NULL;
|
current_settings_ipc = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hToken)
|
if (hToken)
|
||||||
|
|||||||
Reference in New Issue
Block a user