Coding style (runner) (#1013)

This commit is contained in:
Enrico Giordani 2019-12-26 17:26:11 +01:00 committed by GitHub
parent 9708961654
commit 415a0cdf28
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 1414 additions and 1166 deletions

View file

@ -12,16 +12,31 @@
// Helper macros from wix.
// TODO: use "s" and "..." parameters to report errors from these functions.
#define ExitOnFailure(x,s,...) if (FAILED(x)) { goto LExit; }
#define ExitWithLastError(x,s,...) { DWORD Dutil_er = ::GetLastError(); x = HRESULT_FROM_WIN32(Dutil_er); if (!FAILED(x)) { x = E_FAIL; } goto LExit; }
#define ExitFunction() { goto LExit; }
#define ExitOnFailure(x, s, ...) \
if (FAILED(x)) \
{ \
goto LExit; \
}
#define ExitWithLastError(x, s, ...) \
{ \
DWORD Dutil_er = ::GetLastError(); \
x = HRESULT_FROM_WIN32(Dutil_er); \
if (!FAILED(x)) \
{ \
x = E_FAIL; \
} \
goto LExit; \
}
#define ExitFunction() \
{ \
goto LExit; \
}
const DWORD USERNAME_DOMAIN_LEN = DNLEN + UNLEN + 2; // Domain Name + '\' + User Name + '\0'
const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0'
bool enable_auto_start_task_for_this_user() {
bool enable_auto_start_task_for_this_user()
{
HRESULT hr = S_OK;
WCHAR username_domain[USERNAME_DOMAIN_LEN];
@ -39,10 +54,12 @@ bool enable_auto_start_task_for_this_user() {
// ------------------------------------------------------
// Get the Domain/Username for the trigger.
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) {
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN))
{
ExitWithLastError(hr, "Getting username failed: %x", hr);
}
if (!GetEnvironmentVariable(L"USERDOMAIN", username_domain, USERNAME_DOMAIN_LEN)) {
if (!GetEnvironmentVariable(L"USERDOMAIN", username_domain, USERNAME_DOMAIN_LEN))
{
ExitWithLastError(hr, "Getting the user's domain failed: %x", hr);
}
wcscat_s(username_domain, L"\\");
@ -66,20 +83,21 @@ bool enable_auto_start_task_for_this_user() {
ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr);
// Connect to the task service.
hr = pService->Connect(_variant_t(), _variant_t(),
_variant_t(), _variant_t());
hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
// ------------------------------------------------------
// Get the PowerToys task folder. Creates it if it doesn't exist.
hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder);
if (FAILED(hr)) {
if (FAILED(hr))
{
// Folder doesn't exist. Get the Root folder and create the PowerToys subfolder.
ITaskFolder* pRootFolder = NULL;
hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
ExitOnFailure(hr, "Cannot get Root Folder pointer: %x", hr);
hr = pRootFolder->CreateFolder(_bstr_t(L"\\PowerToys"), _variant_t(L""), &pTaskFolder);
if (FAILED(hr)) {
if (FAILED(hr))
{
pRootFolder->Release();
ExitOnFailure(hr, "Cannot create PowerToys task folder: %x", hr);
}
@ -89,11 +107,13 @@ bool enable_auto_start_task_for_this_user() {
{
IRegisteredTask* pExistingRegisteredTask = NULL;
hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask);
if (SUCCEEDED(hr)) {
if (SUCCEEDED(hr))
{
// Task exists, try enabling it.
hr = pExistingRegisteredTask->put_Enabled(VARIANT_TRUE);
pExistingRegisteredTask->Release();
if (SUCCEEDED(hr)) {
if (SUCCEEDED(hr))
{
// Function enable. Sounds like a success.
ExitFunction();
}
@ -198,9 +218,12 @@ bool enable_auto_start_task_for_this_user() {
hr = pPrincipal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN);
// Run the task with the highest available privileges.
if (IsUserAnAdmin()) {
if (IsUserAnAdmin())
{
hr = pPrincipal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_HIGHEST);
} else {
}
else
{
hr = pPrincipal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_LUA);
}
pPrincipal->Release();
@ -220,18 +243,26 @@ bool enable_auto_start_task_for_this_user() {
ExitOnFailure(hr, "Error saving the Task : %x", hr);
LExit:
if (pService) pService->Release();
if (pTaskFolder) pTaskFolder->Release();
if (pTask) pTask->Release();
if (pRegInfo) pRegInfo->Release();
if (pSettings) pSettings->Release();
if (pTriggerCollection) pTriggerCollection->Release();
if (pRegisteredTask) pRegisteredTask->Release();
if (pService)
pService->Release();
if (pTaskFolder)
pTaskFolder->Release();
if (pTask)
pTask->Release();
if (pRegInfo)
pRegInfo->Release();
if (pSettings)
pSettings->Release();
if (pTriggerCollection)
pTriggerCollection->Release();
if (pRegisteredTask)
pRegisteredTask->Release();
return (SUCCEEDED(hr));
}
bool disable_auto_start_task_for_this_user() {
bool disable_auto_start_task_for_this_user()
{
HRESULT hr = S_OK;
WCHAR username[USERNAME_LEN];
@ -242,7 +273,8 @@ bool disable_auto_start_task_for_this_user() {
// ------------------------------------------------------
// Get the Username for the task.
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) {
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN))
{
ExitWithLastError(hr, "Getting username failed: %x", hr);
}
@ -260,14 +292,14 @@ bool disable_auto_start_task_for_this_user() {
ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr);
// Connect to the task service.
hr = pService->Connect(_variant_t(), _variant_t(),
_variant_t(), _variant_t());
hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
// ------------------------------------------------------
// Get the PowerToys task folder.
hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder);
if (FAILED(hr)) {
if (FAILED(hr))
{
// Folder doesn't exist. No need to disable a non-existing task.
hr = S_OK;
ExitFunction();
@ -278,11 +310,13 @@ bool disable_auto_start_task_for_this_user() {
{
IRegisteredTask* pExistingRegisteredTask = NULL;
hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask);
if (SUCCEEDED(hr)) {
if (SUCCEEDED(hr))
{
// Task exists, try disabling it.
hr = pExistingRegisteredTask->put_Enabled(VARIANT_FALSE);
pExistingRegisteredTask->Release();
if (SUCCEEDED(hr)) {
if (SUCCEEDED(hr))
{
// Function disable. Sounds like a success.
ExitFunction();
}
@ -290,13 +324,16 @@ bool disable_auto_start_task_for_this_user() {
}
LExit:
if (pService) pService->Release();
if (pTaskFolder) pTaskFolder->Release();
if (pService)
pService->Release();
if (pTaskFolder)
pTaskFolder->Release();
return (SUCCEEDED(hr));
}
bool is_auto_start_task_active_for_this_user(){
bool is_auto_start_task_active_for_this_user()
{
HRESULT hr = S_OK;
WCHAR username[USERNAME_LEN];
@ -307,7 +344,8 @@ bool is_auto_start_task_active_for_this_user(){
// ------------------------------------------------------
// Get the Username for the task.
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) {
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN))
{
ExitWithLastError(hr, "Getting username failed: %x", hr);
}
@ -325,8 +363,7 @@ bool is_auto_start_task_active_for_this_user(){
ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr);
// Connect to the task service.
hr = pService->Connect(_variant_t(), _variant_t(),
_variant_t(), _variant_t());
hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
// ------------------------------------------------------
@ -339,12 +376,14 @@ bool is_auto_start_task_active_for_this_user(){
{
IRegisteredTask* pExistingRegisteredTask = NULL;
hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask);
if (SUCCEEDED(hr)) {
if (SUCCEEDED(hr))
{
// Task exists, get its value.
VARIANT_BOOL is_enabled;
hr = pExistingRegisteredTask->get_Enabled(&is_enabled);
pExistingRegisteredTask->Release();
if (SUCCEEDED(hr)) {
if (SUCCEEDED(hr))
{
// Got the value. Return it.
hr = (is_enabled == VARIANT_TRUE) ? S_OK : E_FAIL; // Fake success or fail to return the value.
ExitFunction();
@ -353,10 +392,10 @@ bool is_auto_start_task_active_for_this_user(){
}
LExit:
if (pService) pService->Release();
if (pTaskFolder) pTaskFolder->Release();
if (pService)
pService->Release();
if (pTaskFolder)
pTaskFolder->Release();
return (SUCCEEDED(hr));
}

View file

@ -10,23 +10,27 @@
static std::wstring settings_theme = L"system";
static bool run_as_elevated = false;
json::JsonObject load_general_settings() {
json::JsonObject load_general_settings()
{
auto loaded = PTSettingsHelper::load_general_settings();
settings_theme = loaded.GetNamedString(L"theme", L"system");
if (settings_theme != L"dark" && settings_theme != L"light") {
if (settings_theme != L"dark" && settings_theme != L"light")
{
settings_theme = L"system";
}
run_as_elevated = loaded.GetNamedBoolean(L"run_elevated", false);
return loaded;
}
json::JsonObject get_general_settings() {
json::JsonObject get_general_settings()
{
json::JsonObject result;
const bool startup = is_auto_start_task_active_for_this_user();
result.SetNamedValue(L"startup", json::value(startup));
json::JsonObject enabled;
for (auto&[name, powertoy] : modules()) {
for (auto& [name, powertoy] : modules())
{
enabled.SetNamedValue(name, json::value(powertoy.is_enabled()));
}
result.SetNamedValue(L"enabled", std::move(enabled));
@ -40,79 +44,104 @@ json::JsonObject get_general_settings() {
return result;
}
void apply_general_settings(const json::JsonObject& general_configs) {
if (json::has(general_configs, L"startup", json::JsonValueType::Boolean)) {
void apply_general_settings(const json::JsonObject& general_configs)
{
if (json::has(general_configs, L"startup", json::JsonValueType::Boolean))
{
const bool startup = general_configs.GetNamedBoolean(L"startup");
const bool current_startup = is_auto_start_task_active_for_this_user();
if (current_startup != startup) {
if (startup) {
if (current_startup != startup)
{
if (startup)
{
enable_auto_start_task_for_this_user();
} else {
}
else
{
disable_auto_start_task_for_this_user();
}
}
}
if (json::has(general_configs, L"enabled")) {
for (const auto& enabled_element : general_configs.GetNamedObject(L"enabled")) {
if (json::has(general_configs, L"enabled"))
{
for (const auto& enabled_element : general_configs.GetNamedObject(L"enabled"))
{
const auto value = enabled_element.Value();
if (value.ValueType() != json::JsonValueType::Boolean) {
if (value.ValueType() != json::JsonValueType::Boolean)
{
continue;
}
const std::wstring name{ enabled_element.Key().c_str() };
const bool found = modules().find(name) != modules().end();
if (!found) {
if (!found)
{
continue;
}
const bool module_inst_enabled = modules().at(name).is_enabled();
const bool target_enabled = value.GetBoolean();
if (module_inst_enabled == target_enabled) {
if (module_inst_enabled == target_enabled)
{
continue;
}
if (target_enabled) {
if (target_enabled)
{
modules().at(name).enable();
} else {
}
else
{
modules().at(name).disable();
}
}
}
run_as_elevated = general_configs.GetNamedBoolean(L"run_elevated", false);
if (json::has(general_configs, L"theme", json::JsonValueType::String)) {
if (json::has(general_configs, L"theme", json::JsonValueType::String))
{
settings_theme = general_configs.GetNamedString(L"theme");
}
json::JsonObject save_settings = get_general_settings();
PTSettingsHelper::save_general_settings(save_settings);
}
void start_initial_powertoys() {
void start_initial_powertoys()
{
bool only_enable_some_powertoys = false;
std::unordered_set<std::wstring> powertoys_to_enable;
json::JsonObject general_settings;
try {
try
{
general_settings = load_general_settings();
json::JsonObject enabled = general_settings.GetNamedObject(L"enabled");
for (const auto & enabled_element : enabled) {
if (enabled_element.Value().GetBoolean()) {
for (const auto& enabled_element : enabled)
{
if (enabled_element.Value().GetBoolean())
{
// Enable this powertoy.
powertoys_to_enable.emplace(enabled_element.Key());
}
}
only_enable_some_powertoys = true;
}
catch (...) {
catch (...)
{
// Couldn't read the general settings correctly.
// Load all powertoys.
// TODO: notify user about invalid json config
only_enable_some_powertoys = false;
}
for (auto&[name, powertoy] : modules()) {
if (only_enable_some_powertoys) {
if (powertoys_to_enable.find(name)!=powertoys_to_enable.end()) {
for (auto& [name, powertoy] : modules())
{
if (only_enable_some_powertoys)
{
if (powertoys_to_enable.find(name) != powertoys_to_enable.end())
{
powertoy.enable();
}
} else {
}
else
{
powertoy.enable();
}
}

View file

@ -2,15 +2,19 @@
#include "lowlevel_keyboard_event.h"
#include "powertoys_events.h"
namespace {
namespace
{
HHOOK hook_handle = nullptr;
HHOOK hook_handle_copy = nullptr; // make sure we do use nullptr in CallNextHookEx call
LRESULT CALLBACK hook_proc(int nCode, WPARAM wParam, LPARAM lParam) {
LRESULT CALLBACK hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
{
LowlevelKeyboardEvent event;
if (nCode == HC_ACTION) {
if (nCode == HC_ACTION)
{
event.lParam = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
event.wParam = wParam;
if (powertoys_events().signal_event(ll_keyboard, reinterpret_cast<intptr_t>(&event)) != 0) {
if (powertoys_events().signal_event(ll_keyboard, reinterpret_cast<intptr_t>(&event)) != 0)
{
return 1;
}
}
@ -21,24 +25,30 @@ namespace {
// Prevent system-wide input lagging while paused in the debugger
//#define DISABLE_LOWLEVEL_KBHOOK_WHEN_DEBUGGED
void start_lowlevel_keyboard_hook() {
void start_lowlevel_keyboard_hook()
{
#if defined(_DEBUG) && defined(DISABLE_LOWLEVEL_KBHOOK_WHEN_DEBUGGED)
if(IsDebuggerPresent()) {
if (IsDebuggerPresent())
{
return;
}
#endif
if (!hook_handle) {
if (!hook_handle)
{
hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, hook_proc, GetModuleHandle(NULL), NULL);
hook_handle_copy = hook_handle;
if (!hook_handle) {
if (!hook_handle)
{
throw std::runtime_error("Cannot install keyboard listener");
}
}
}
void stop_lowlevel_keyboard_hook() {
if (hook_handle) {
void stop_lowlevel_keyboard_hook()
{
if (hook_handle)
{
UnhookWindowsHookEx(hook_handle);
hook_handle = nullptr;
}

View file

@ -19,18 +19,20 @@
extern "C" IMAGE_DOS_HEADER __ImageBase;
void chdir_current_executable() {
void chdir_current_executable()
{
// Change current directory to the path of the executable.
WCHAR executable_path[MAX_PATH];
GetModuleFileName(NULL, executable_path, MAX_PATH);
PathRemoveFileSpec(executable_path);
if(!SetCurrentDirectory(executable_path)) {
if (!SetCurrentDirectory(executable_path))
{
show_last_error_message(L"Change Directory to Executable Path", GetLastError());
}
}
int runner() {
int runner()
{
DPIAware::EnableDPIAwarenessForThisProcess();
#if _DEBUG && _WIN64
@ -42,7 +44,8 @@ int runner() {
winrt::init_apartment();
start_tray_icon();
int result;
try {
try
{
chdir_current_executable();
// Load Powertyos DLLS
// For now only load known DLLs
@ -51,15 +54,20 @@ int runner() {
L"fancyzones.dll",
L"PowerRenameExt.dll"
};
for (auto& file : std::filesystem::directory_iterator(L"modules/")) {
for (auto& file : std::filesystem::directory_iterator(L"modules/"))
{
if (file.path().extension() != L".dll")
continue;
if (known_dlls.find(file.path().filename()) == known_dlls.end())
continue;
try {
try
{
auto module = load_powertoy(file.path().wstring());
modules().emplace(module.get_name(), std::move(module));
} catch (...) { }
}
catch (...)
{
}
}
// Start initial powertoys
start_initial_powertoys();
@ -67,7 +75,9 @@ int runner() {
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);
result = -1;
@ -76,17 +86,20 @@ int runner() {
return result;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
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) {
if (runner_mutex == NULL || GetLastError() == ERROR_ALREADY_EXISTS)
{
// The app is already running
return 0;
}
int result = 0;
try {
try
{
// Singletons initialization order needs to be preserved, first events and
// then modules to guarantee the reverse destruction order.
SystemMenuHelperInstace();
@ -97,23 +110,28 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
int rvalue = 0;
if (is_process_elevated() ||
general_settings.GetNamedBoolean(L"run_elevated", false) == false ||
strcmp(lpCmdLine, "--dont-elevate") == 0) {
strcmp(lpCmdLine, "--dont-elevate") == 0)
{
result = runner();
}
else {
else
{
schedule_restart_as_elevated();
result = 0;
}
}
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(), 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) {
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);

View file

@ -3,20 +3,24 @@
#include "lowlevel_keyboard_event.h"
#include <algorithm>
std::unordered_map<std::wstring, PowertoyModule>& modules() {
std::unordered_map<std::wstring, PowertoyModule>& modules()
{
static std::unordered_map<std::wstring, PowertoyModule> modules;
return modules;
}
PowertoyModule load_powertoy(const std::wstring& filename) {
PowertoyModule load_powertoy(const std::wstring& filename)
{
auto handle = winrt::check_pointer(LoadLibraryW(filename.c_str()));
auto create = reinterpret_cast<powertoy_create_func>(GetProcAddress(handle, "powertoy_create"));
if (!create) {
if (!create)
{
FreeLibrary(handle);
winrt::throw_last_error();
}
auto module = create();
if (!module) {
if (!module)
{
FreeLibrary(handle);
winrt::throw_last_error();
}
@ -24,7 +28,8 @@ PowertoyModule load_powertoy(const std::wstring& filename) {
return PowertoyModule(module, handle);
}
json::JsonObject PowertoyModule::json_config() const {
json::JsonObject PowertoyModule::json_config() const
{
int size = 0;
module->get_config(nullptr, &size);
std::wstring result;

View file

@ -11,9 +11,12 @@
class PowertoyModule;
#include <common/json.h>
struct PowertoyModuleDeleter {
void operator()(PowertoyModuleIface* module) const {
if (module) {
struct PowertoyModuleDeleter
{
void operator()(PowertoyModuleIface* module) const
{
if (module)
{
powertoys_events().unregister_system_menu_action(module);
powertoys_events().unregister_receiver(module);
module->destroy();
@ -21,70 +24,88 @@ struct PowertoyModuleDeleter {
}
};
struct PowertoyModuleDLLDeleter {
struct PowertoyModuleDLLDeleter
{
using pointer = HMODULE;
void operator()(HMODULE handle) const {
void operator()(HMODULE handle) const
{
FreeLibrary(handle);
}
};
class PowertoyModule {
class PowertoyModule
{
public:
PowertoyModule(PowertoyModuleIface* module, HMODULE handle) : handle(handle), module(module) {
if (!module) {
PowertoyModule(PowertoyModuleIface* module, HMODULE handle) :
handle(handle), module(module)
{
if (!module)
{
throw std::runtime_error("Module not initialized");
}
name = module->get_name();
auto want_signals = module->get_events();
if (want_signals) {
for (; *want_signals; ++want_signals) {
if (want_signals)
{
for (; *want_signals; ++want_signals)
{
powertoys_events().register_receiver(*want_signals, module);
}
}
if (SystemMenuHelperInstace().HasCustomConfig(module)) {
if (SystemMenuHelperInstace().HasCustomConfig(module))
{
powertoys_events().register_system_menu_action(module);
}
}
const std::wstring& get_name() const {
const std::wstring& get_name() const
{
return name;
}
json::JsonObject json_config() const;
const std::wstring get_config() const {
const std::wstring get_config() const
{
std::wstring result;
int size = 0;
module->get_config(nullptr, &size);
wchar_t* buffer = new wchar_t[size];
if (module->get_config(buffer, &size)) {
if (module->get_config(buffer, &size))
{
result.assign(buffer);
}
delete[] buffer;
return result;
}
void set_config(const std::wstring& config) {
void set_config(const std::wstring& config)
{
module->set_config(config.c_str());
}
void call_custom_action(const std::wstring& action) {
void call_custom_action(const std::wstring& action)
{
module->call_custom_action(action.c_str());
}
intptr_t signal_event(const std::wstring& signal_event, intptr_t data) {
intptr_t signal_event(const std::wstring& signal_event, intptr_t data)
{
return module->signal_event(signal_event.c_str(), data);
}
bool is_enabled() {
bool is_enabled()
{
return module->is_enabled();
}
void enable() {
void enable()
{
module->enable();
}
void disable() {
void disable()
{
module->disable();
}

View file

@ -4,66 +4,82 @@
#include "win_hook_event.h"
#include "system_menu_helper.h"
void first_subscribed(const std::wstring& event) {
void first_subscribed(const std::wstring& event)
{
if (event == ll_keyboard)
start_lowlevel_keyboard_hook();
else if (event == win_hook_event)
start_win_hook_event();
}
void last_unsubscribed(const std::wstring& event) {
void last_unsubscribed(const std::wstring& event)
{
if (event == ll_keyboard)
stop_lowlevel_keyboard_hook();
else if (event == win_hook_event)
stop_win_hook_event();
}
PowertoysEvents& powertoys_events() {
PowertoysEvents& powertoys_events()
{
static PowertoysEvents powertoys_events;
return powertoys_events;
}
void PowertoysEvents::register_receiver(const std::wstring & event, PowertoyModuleIface* module) {
void PowertoysEvents::register_receiver(const std::wstring& event, PowertoyModuleIface* module)
{
std::unique_lock lock(mutex);
auto& subscribers = receivers[event];
if (subscribers.empty()) {
if (subscribers.empty())
{
first_subscribed(event);
}
subscribers.push_back(module);
}
void PowertoysEvents::unregister_receiver(PowertoyModuleIface* module) {
void PowertoysEvents::unregister_receiver(PowertoyModuleIface* module)
{
std::unique_lock lock(mutex);
for (auto&[event, subscribers] : receivers) {
for (auto& [event, subscribers] : receivers)
{
subscribers.erase(remove(begin(subscribers), end(subscribers), module), end(subscribers));
if (subscribers.empty()) {
if (subscribers.empty())
{
last_unsubscribed(event);
}
}
}
void PowertoysEvents::register_system_menu_action(PowertoyModuleIface* module) {
void PowertoysEvents::register_system_menu_action(PowertoyModuleIface* module)
{
std::unique_lock lock(mutex);
system_menu_receivers.insert(module);
}
void PowertoysEvents::unregister_system_menu_action(PowertoyModuleIface* module) {
void PowertoysEvents::unregister_system_menu_action(PowertoyModuleIface* module)
{
std::unique_lock lock(mutex);
auto it = system_menu_receivers.find(module);
if (it != system_menu_receivers.end()) {
if (it != system_menu_receivers.end())
{
SystemMenuHelperInstace().Reset(module);
system_menu_receivers.erase(it);
}
}
void PowertoysEvents::handle_system_menu_action(const WinHookEvent& data) {
if (data.event == EVENT_SYSTEM_MENUSTART) {
for (auto& module : system_menu_receivers) {
void PowertoysEvents::handle_system_menu_action(const WinHookEvent& data)
{
if (data.event == EVENT_SYSTEM_MENUSTART)
{
for (auto& module : system_menu_receivers)
{
SystemMenuHelperInstace().Customize(module, data.hwnd);
}
}
else if (data.event == EVENT_OBJECT_INVOKED) {
if (PowertoyModuleIface* module{ SystemMenuHelperInstace().ModuleFromItemId(data.idChild) }) {
else if (data.event == EVENT_OBJECT_INVOKED)
{
if (PowertoyModuleIface * module{ SystemMenuHelperInstace().ModuleFromItemId(data.idChild) })
{
std::wstring itemName = SystemMenuHelperInstace().ItemNameFromItemId(data.idChild);
// Process event on specified system menu item by responsible module.
module->signal_system_menu_action(itemName.c_str());
@ -73,11 +89,14 @@ void PowertoysEvents::handle_system_menu_action(const WinHookEvent& data) {
}
}
intptr_t PowertoysEvents::signal_event(const std::wstring & event, intptr_t data) {
intptr_t PowertoysEvents::signal_event(const std::wstring& event, intptr_t data)
{
intptr_t rvalue = 0;
std::shared_lock lock(mutex);
if (auto it = receivers.find(event); it != end(receivers)) {
for (auto& module : it->second) {
if (auto it = receivers.find(event); it != end(receivers))
{
for (auto& module : it->second)
{
if (module)
rvalue |= module->signal_event(event.c_str(), data);
}

View file

@ -4,7 +4,8 @@
#include <interface/win_hook_event_data.h>
#include <string>
class PowertoysEvents {
class PowertoysEvents
{
public:
void register_receiver(const std::wstring& event, PowertoyModuleIface* module);
void unregister_receiver(PowertoyModuleIface* module);
@ -14,6 +15,7 @@ public:
void handle_system_menu_action(const WinHookEvent& data);
intptr_t signal_event(const std::wstring& event, intptr_t data);
private:
std::shared_mutex mutex;
std::unordered_map<std::wstring, std::vector<PowertoyModuleIface*>> receivers;
@ -24,4 +26,3 @@ PowertoysEvents& powertoys_events();
void first_subscribed(const std::wstring& event);
void last_unsubscribed(const std::wstring& event);

View file

@ -2,31 +2,37 @@
#include "restart_elevated.h"
#include "common/common.h"
enum State {
enum State
{
None,
RestartAsElevated,
RestartAsNonElevated
};
static State state = None;
void schedule_restart_as_elevated() {
void schedule_restart_as_elevated()
{
state = RestartAsElevated;
}
void schedule_restart_as_non_elevated() {
void schedule_restart_as_non_elevated()
{
state = RestartAsNonElevated;
}
bool is_restart_scheduled() {
bool is_restart_scheduled()
{
return state != None;
}
bool restart_if_scheduled() {
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) {
switch (state)
{
case RestartAsElevated:
return run_elevated(exe_path.get(), {});
case RestartAsNonElevated:

View file

@ -145,7 +145,6 @@ void receive_json_send_to_main_thread(const std::wstring& msg)
dispatch_run_on_main_ui_thread(dispatch_received_json_callback, copy);
}
// 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)
{

View file

@ -3,36 +3,46 @@
#include <interface/powertoy_module_interface.h>
namespace {
namespace
{
constexpr int KSeparatorPos = 1;
constexpr int KNewItemPos = 2;
unsigned int GenerateItemId() {
unsigned int GenerateItemId()
{
static unsigned int generator = 0x70777479;
return ++generator;
}
}
SystemMenuHelper& SystemMenuHelperInstace() {
SystemMenuHelper& SystemMenuHelperInstace()
{
static SystemMenuHelper instance;
return instance;
}
void SystemMenuHelper::SetConfiguration(PowertoyModuleIface* module, const std::vector<ItemInfo>& config) {
void SystemMenuHelper::SetConfiguration(PowertoyModuleIface* module, const std::vector<ItemInfo>& config)
{
Reset(module);
Configurations[module] = config;
for (auto& [window, modules] : ProcessedModules) {
for (auto& [window, modules] : ProcessedModules)
{
// Unregister module. After system menu is opened again, new configuration will be applied.
modules.erase(std::remove(std::begin(modules), std::end(modules), module), std::end(modules));
}
}
void SystemMenuHelper::ProcessSelectedItem(PowertoyModuleIface* module, HWND window, const wchar_t* itemName) {
for (const auto& item : Configurations[module]) {
if (itemName == item.name && item.checkBox) {
void SystemMenuHelper::ProcessSelectedItem(PowertoyModuleIface* module, HWND window, const wchar_t* itemName)
{
for (const auto& item : Configurations[module])
{
if (itemName == item.name && item.checkBox)
{
// Handle check/uncheck action only if specified by module configuration.
for (const auto& [id, data] : IdMappings) {
if (data.second == itemName) {
for (const auto& [id, data] : IdMappings)
{
if (data.second == itemName)
{
HMENU systemMenu = GetSystemMenu(window, false);
int state = (GetMenuState(systemMenu, id, MF_BYCOMMAND) == MF_CHECKED) ? MF_UNCHECKED : MF_CHECKED;
CheckMenuItem(systemMenu, id, MF_BYCOMMAND | state);
@ -44,26 +54,35 @@ void SystemMenuHelper::ProcessSelectedItem(PowertoyModuleIface* module, HWND win
}
}
bool SystemMenuHelper::Customize(PowertoyModuleIface* module, HWND window) {
bool SystemMenuHelper::Customize(PowertoyModuleIface* module, HWND window)
{
auto& modules = ProcessedModules[window];
for (const auto& m : modules) {
if (module == m) {
for (const auto& m : modules)
{
if (module == m)
{
return false;
}
}
AddSeparator(module, window);
for (const auto& info : Configurations[module]) {
for (const auto& info : Configurations[module])
{
AddItem(module, window, info.name, info.enable);
}
modules.push_back(module);
return true;
}
void SystemMenuHelper::Reset(PowertoyModuleIface* module) {
for (auto& [window, modules] : ProcessedModules) {
if (HMENU systemMenu{ GetSystemMenu(window, false) }) {
for (auto& [id, data] : IdMappings) {
if (data.first == module) {
void SystemMenuHelper::Reset(PowertoyModuleIface* module)
{
for (auto& [window, modules] : ProcessedModules)
{
if (HMENU systemMenu{ GetSystemMenu(window, false) })
{
for (auto& [id, data] : IdMappings)
{
if (data.first == module)
{
DeleteMenu(systemMenu, id, MF_BYCOMMAND);
}
}
@ -71,12 +90,15 @@ void SystemMenuHelper::Reset(PowertoyModuleIface* module) {
}
}
bool SystemMenuHelper::HasCustomConfig(PowertoyModuleIface* module) {
bool SystemMenuHelper::HasCustomConfig(PowertoyModuleIface* module)
{
return Configurations.find(module) != Configurations.end();
}
bool SystemMenuHelper::AddItem(PowertoyModuleIface* module, HWND window, const std::wstring& name, const bool enable) {
if (HMENU systemMenu{ GetSystemMenu(window, false) }) {
bool SystemMenuHelper::AddItem(PowertoyModuleIface* module, HWND window, const std::wstring& name, const bool enable)
{
if (HMENU systemMenu{ GetSystemMenu(window, false) })
{
MENUITEMINFO item;
item.cbSize = sizeof(item);
item.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;
@ -85,9 +107,11 @@ bool SystemMenuHelper::AddItem(PowertoyModuleIface* module, HWND window, const s
item.dwTypeData = const_cast<WCHAR*>(name.c_str());
item.cch = (UINT)name.size() + 1;
if (InsertMenuItem(systemMenu, GetMenuItemCount(systemMenu) - KNewItemPos, true, &item)) {
if (InsertMenuItem(systemMenu, GetMenuItemCount(systemMenu) - KNewItemPos, true, &item))
{
IdMappings[item.wID] = { module, name };
if (enable) {
if (enable)
{
EnableMenuItem(systemMenu, item.wID, MF_BYCOMMAND | MF_ENABLED);
}
return true;
@ -96,15 +120,18 @@ bool SystemMenuHelper::AddItem(PowertoyModuleIface* module, HWND window, const s
return false;
}
bool SystemMenuHelper::AddSeparator(PowertoyModuleIface* module, HWND window) {
if (HMENU systemMenu{ GetSystemMenu(window, false) }) {
bool SystemMenuHelper::AddSeparator(PowertoyModuleIface* module, HWND window)
{
if (HMENU systemMenu{ GetSystemMenu(window, false) })
{
MENUITEMINFO separator;
separator.cbSize = sizeof(separator);
separator.fMask = MIIM_ID | MIIM_FTYPE;
separator.fType = MFT_SEPARATOR;
separator.wID = GenerateItemId();
if (InsertMenuItem(systemMenu, GetMenuItemCount(systemMenu) - KSeparatorPos, true, &separator)) {
if (InsertMenuItem(systemMenu, GetMenuItemCount(systemMenu) - KSeparatorPos, true, &separator))
{
IdMappings[separator.wID] = { module, L"sepparator_dummy_name" };
return true;
}
@ -112,17 +139,21 @@ bool SystemMenuHelper::AddSeparator(PowertoyModuleIface* module, HWND window) {
return false;
}
PowertoyModuleIface* SystemMenuHelper::ModuleFromItemId(const int& id) {
PowertoyModuleIface* SystemMenuHelper::ModuleFromItemId(const int& id)
{
auto it = IdMappings.find(id);
if (it != IdMappings.end()) {
if (it != IdMappings.end())
{
return it->second.first;
}
return nullptr;
}
const std::wstring SystemMenuHelper::ItemNameFromItemId(const int& id) {
const std::wstring SystemMenuHelper::ItemNameFromItemId(const int& id)
{
auto itemIt = IdMappings.find(id);
if (itemIt != IdMappings.end()) {
if (itemIt != IdMappings.end())
{
return itemIt->second.second;
}
return std::wstring{};

View file

@ -10,7 +10,8 @@
class PowertoyModuleIface;
class SystemMenuHelper : public PowertoySystemMenuIface {
class SystemMenuHelper : public PowertoySystemMenuIface
{
public:
// PowertoySystemMenuIface
virtual void SetConfiguration(PowertoyModuleIface* module, const std::vector<ItemInfo>& config) override;

View file

@ -8,15 +8,18 @@ TRACELOGGING_DEFINE_PROVIDER(
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
TraceLoggingOptionProjectTelemetry());
void Trace::RegisterProvider() {
void Trace::RegisterProvider()
{
TraceLoggingRegister(g_hProvider);
}
void Trace::UnregisterProvider() {
void Trace::UnregisterProvider()
{
TraceLoggingUnregister(g_hProvider);
}
void Trace::EventLaunch(const std::wstring& versionNumber) {
void Trace::EventLaunch(const std::wstring& versionNumber)
{
TraceLoggingWrite(
g_hProvider,
"Runner_Launch",

View file

@ -1,6 +1,7 @@
#pragma once
class Trace {
class Trace
{
public:
static void RegisterProvider();
static void UnregisterProvider();

View file

@ -7,7 +7,8 @@
extern "C" IMAGE_DOS_HEADER __ImageBase;
namespace {
namespace
{
HWND tray_icon_hwnd = NULL;
// Message code that Windows will use for tray icon notifications.
@ -27,13 +28,16 @@ namespace {
}
// Struct to fill with callback and the data. The window_proc is responsible for cleaning it.
struct run_on_main_ui_thread_msg {
struct run_on_main_ui_thread_msg
{
main_loop_callback_function _callback;
PVOID data;
};
bool dispatch_run_on_main_ui_thread(main_loop_callback_function _callback, PVOID data) {
if (tray_icon_hwnd == NULL) {
bool dispatch_run_on_main_ui_thread(main_loop_callback_function _callback, PVOID data)
{
if (tray_icon_hwnd == NULL)
{
return false;
}
struct run_on_main_ui_thread_msg* wnd_msg = new struct run_on_main_ui_thread_msg();
@ -45,17 +49,21 @@ bool dispatch_run_on_main_ui_thread(main_loop_callback_function _callback, PVOID
return true;
}
LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) {
switch (message) {
LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
{
switch (message)
{
case WM_CREATE:
if (wm_taskbar_restart == 0) {
if (wm_taskbar_restart == 0)
{
tray_icon_hwnd = window;
wm_taskbar_restart = RegisterWindowMessageW(L"TaskbarCreated");
wm_run_on_main_ui_thread = RegisterWindowMessage(L"RunOnMainThreadCallback");
}
break;
case WM_DESTROY:
if (tray_icon_created) {
if (tray_icon_created)
{
Shell_NotifyIcon(NIM_DELETE, &tray_icon_data);
tray_icon_created = false;
}
@ -65,18 +73,21 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
DestroyWindow(window);
break;
case WM_COMMAND:
switch(wparam) {
switch (wparam)
{
case ID_SETTINGS_MENU_COMMAND:
open_settings_window();
break;
case ID_EXIT_MENU_COMMAND:
if (h_menu) {
if (h_menu)
{
DestroyMenu(h_menu);
}
DestroyWindow(window);
break;
case ID_ABOUT_MENU_COMMAND:
if (!about_box_shown) {
if (!about_box_shown)
{
about_box_shown = true;
std::wstring about_msg = L"PowerToys\nVersion " + get_product_version() + L"\n\xa9 2019 Microsoft Corporation";
MessageBox(nullptr, about_msg.c_str(), L"About PowerToys", MB_OK);
@ -88,28 +99,30 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
// Shell_NotifyIcon can fail when we invoke it during the time explorer.exe isn't present/ready to handle it.
// We'll also never receive wm_taskbar_restart message if the first call to Shell_NotifyIcon failed, so we use
// WM_WINDOWPOSCHANGING which is always received on explorer startup sequence.
case WM_WINDOWPOSCHANGING:
case WM_WINDOWPOSCHANGING: {
if (!tray_icon_created)
{
if(!tray_icon_created) {
tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE;
}
break;
}
default:
if (message == wm_icon_notify) {
switch(lparam) {
case WM_LBUTTONUP:
if (message == wm_icon_notify)
{
switch (lparam)
{
case WM_LBUTTONUP: {
open_settings_window();
break;
}
case WM_RBUTTONUP:
case WM_CONTEXTMENU:
case WM_CONTEXTMENU: {
if (!h_menu)
{
if (!h_menu) {
h_menu = LoadMenu(reinterpret_cast<HINSTANCE>(&__ImageBase), MAKEINTRESOURCE(ID_TRAY_MENU));
}
if (!h_sub_menu) {
if (!h_sub_menu)
{
h_sub_menu = GetSubMenu(h_menu, 0);
}
POINT mouse_pointer;
@ -119,15 +132,20 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
}
break;
}
} else if (message == wm_run_on_main_ui_thread) {
if (lparam != NULL) {
}
else if (message == wm_run_on_main_ui_thread)
{
if (lparam != NULL)
{
struct run_on_main_ui_thread_msg* msg = (struct run_on_main_ui_thread_msg*)lparam;
msg->_callback(msg->data);
delete msg;
lparam = NULL;
}
break;
} else if (message == wm_taskbar_restart) {
}
else if (message == wm_taskbar_restart)
{
tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE;
break;
}
@ -135,10 +153,12 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
return DefWindowProc(window, message, wparam, lparam);
}
void start_tray_icon() {
void start_tray_icon()
{
auto h_instance = reinterpret_cast<HINSTANCE>(&__ImageBase);
auto icon = LoadIcon(h_instance, MAKEINTRESOURCE(APPICON));
if (icon) {
if (icon)
{
UINT id_tray_icon = wm_icon_notify = RegisterWindowMessageW(L"WM_PowerToysIconNotify");
static LPCWSTR class_name = L"PToyTrayIconWindow";
@ -176,8 +196,10 @@ void start_tray_icon() {
}
}
void stop_tray_icon() {
if (tray_icon_created) {
void stop_tray_icon()
{
if (tray_icon_created)
{
SendMessage(tray_icon_hwnd, WM_CLOSE, 0, 0);
}
}

View file

@ -13,40 +13,65 @@ static bool processing_exception = false;
static WCHAR module_path[MAX_PATH];
static LPTOP_LEVEL_EXCEPTION_FILTER default_top_level_exception_handler = NULL;
static const WCHAR* exception_description(const DWORD& code) {
switch (code) {
case EXCEPTION_ACCESS_VIOLATION: return L"EXCEPTION_ACCESS_VIOLATION";
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return L"EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
case EXCEPTION_BREAKPOINT: return L"EXCEPTION_BREAKPOINT";
case EXCEPTION_DATATYPE_MISALIGNMENT: return L"EXCEPTION_DATATYPE_MISALIGNMENT";
case EXCEPTION_FLT_DENORMAL_OPERAND: return L"EXCEPTION_FLT_DENORMAL_OPERAND";
case EXCEPTION_FLT_DIVIDE_BY_ZERO: return L"EXCEPTION_FLT_DIVIDE_BY_ZERO";
case EXCEPTION_FLT_INEXACT_RESULT: return L"EXCEPTION_FLT_INEXACT_RESULT";
case EXCEPTION_FLT_INVALID_OPERATION: return L"EXCEPTION_FLT_INVALID_OPERATION";
case EXCEPTION_FLT_OVERFLOW: return L"EXCEPTION_FLT_OVERFLOW";
case EXCEPTION_FLT_STACK_CHECK: return L"EXCEPTION_FLT_STACK_CHECK";
case EXCEPTION_FLT_UNDERFLOW: return L"EXCEPTION_FLT_UNDERFLOW";
case EXCEPTION_ILLEGAL_INSTRUCTION: return L"EXCEPTION_ILLEGAL_INSTRUCTION";
case EXCEPTION_IN_PAGE_ERROR: return L"EXCEPTION_IN_PAGE_ERROR";
case EXCEPTION_INT_DIVIDE_BY_ZERO: return L"EXCEPTION_INT_DIVIDE_BY_ZERO";
case EXCEPTION_INT_OVERFLOW: return L"EXCEPTION_INT_OVERFLOW";
case EXCEPTION_INVALID_DISPOSITION: return L"EXCEPTION_INVALID_DISPOSITION";
case EXCEPTION_NONCONTINUABLE_EXCEPTION: return L"EXCEPTION_NONCONTINUABLE_EXCEPTION";
case EXCEPTION_PRIV_INSTRUCTION: return L"EXCEPTION_PRIV_INSTRUCTION";
case EXCEPTION_SINGLE_STEP: return L"EXCEPTION_SINGLE_STEP";
case EXCEPTION_STACK_OVERFLOW: return L"EXCEPTION_STACK_OVERFLOW";
default: return L"UNKNOWN EXCEPTION";
static const WCHAR* exception_description(const DWORD& code)
{
switch (code)
{
case EXCEPTION_ACCESS_VIOLATION:
return L"EXCEPTION_ACCESS_VIOLATION";
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
return L"EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
case EXCEPTION_BREAKPOINT:
return L"EXCEPTION_BREAKPOINT";
case EXCEPTION_DATATYPE_MISALIGNMENT:
return L"EXCEPTION_DATATYPE_MISALIGNMENT";
case EXCEPTION_FLT_DENORMAL_OPERAND:
return L"EXCEPTION_FLT_DENORMAL_OPERAND";
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
return L"EXCEPTION_FLT_DIVIDE_BY_ZERO";
case EXCEPTION_FLT_INEXACT_RESULT:
return L"EXCEPTION_FLT_INEXACT_RESULT";
case EXCEPTION_FLT_INVALID_OPERATION:
return L"EXCEPTION_FLT_INVALID_OPERATION";
case EXCEPTION_FLT_OVERFLOW:
return L"EXCEPTION_FLT_OVERFLOW";
case EXCEPTION_FLT_STACK_CHECK:
return L"EXCEPTION_FLT_STACK_CHECK";
case EXCEPTION_FLT_UNDERFLOW:
return L"EXCEPTION_FLT_UNDERFLOW";
case EXCEPTION_ILLEGAL_INSTRUCTION:
return L"EXCEPTION_ILLEGAL_INSTRUCTION";
case EXCEPTION_IN_PAGE_ERROR:
return L"EXCEPTION_IN_PAGE_ERROR";
case EXCEPTION_INT_DIVIDE_BY_ZERO:
return L"EXCEPTION_INT_DIVIDE_BY_ZERO";
case EXCEPTION_INT_OVERFLOW:
return L"EXCEPTION_INT_OVERFLOW";
case EXCEPTION_INVALID_DISPOSITION:
return L"EXCEPTION_INVALID_DISPOSITION";
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
return L"EXCEPTION_NONCONTINUABLE_EXCEPTION";
case EXCEPTION_PRIV_INSTRUCTION:
return L"EXCEPTION_PRIV_INSTRUCTION";
case EXCEPTION_SINGLE_STEP:
return L"EXCEPTION_SINGLE_STEP";
case EXCEPTION_STACK_OVERFLOW:
return L"EXCEPTION_STACK_OVERFLOW";
default:
return L"UNKNOWN EXCEPTION";
}
}
void init_symbols() {
void init_symbols()
{
SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
auto process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
}
void log_stack_trace(std::wstring& generalErrorDescription) {
void log_stack_trace(std::wstring& generalErrorDescription)
{
memset(p_symbol, '\0', sizeof(*p_symbol) + MAX_PATH);
memset(&module_path[0], '\0', sizeof(module_path));
line.LineNumber = 0;
@ -66,7 +91,8 @@ void log_stack_trace(std::wstring& generalErrorDescription) {
std::wstringstream ss;
ss << generalErrorDescription << std::endl;
for (ULONG frame = 0;; frame++) {
for (ULONG frame = 0;; frame++)
{
auto result = StackWalk64(IMAGE_FILE_MACHINE_AMD64,
process,
thread,
@ -86,34 +112,42 @@ void log_stack_trace(std::wstring& generalErrorDescription) {
SymGetLineFromAddr64(process, stack.AddrPC.Offset, &dwDisplacement, &line);
auto module_base = SymGetModuleBase64(process, stack.AddrPC.Offset);
if (module_base) {
if (module_base)
{
GetModuleFileName((HINSTANCE)module_base, module_path, MAX_PATH);
}
ss << module_path << "!"
<< p_symbol->Name
<< "(" << line.FileName << ":" << line.LineNumber << ")\n";
if (!result) {
if (!result)
{
break;
}
}
auto errorString = ss.str();
MessageBoxW(NULL, errorString.c_str(), L"Unhandled Error", MB_OK | MB_ICONERROR);
}
LONG WINAPI unhandled_exceptiont_handler(PEXCEPTION_POINTERS info) {
if (!processing_exception) {
LONG WINAPI unhandled_exceptiont_handler(PEXCEPTION_POINTERS info)
{
if (!processing_exception)
{
processing_exception = true;
try {
try
{
init_symbols();
std::wstring ex_description = L"Exception code not available";
if (info != NULL && info->ExceptionRecord != NULL && info->ExceptionRecord->ExceptionCode != NULL) {
if (info != NULL && info->ExceptionRecord != NULL && info->ExceptionRecord->ExceptionCode != NULL)
{
ex_description = exception_description(info->ExceptionRecord->ExceptionCode);
}
log_stack_trace(ex_description);
}
catch (...) {}
if (default_top_level_exception_handler != NULL && info != NULL) {
catch (...)
{
}
if (default_top_level_exception_handler != NULL && info != NULL)
{
default_top_level_exception_handler(info);
}
processing_exception = false;
@ -121,13 +155,15 @@ LONG WINAPI unhandled_exceptiont_handler(PEXCEPTION_POINTERS info) {
return EXCEPTION_CONTINUE_SEARCH;
}
extern "C" void AbortHandler(int signal_number) {
extern "C" void AbortHandler(int signal_number)
{
init_symbols();
std::wstring ex_description = L"SIGABRT was raised.";
log_stack_trace(ex_description);
}
void init_global_error_handlers() {
void init_global_error_handlers()
{
default_top_level_exception_handler = SetUnhandledExceptionFilter(unhandled_exceptiont_handler);
signal(SIGABRT, &AbortHandler);
}

View file

@ -17,7 +17,8 @@ static void CALLBACK win_hook_event_proc(HWINEVENTHOOK winEventHook,
LONG object,
LONG child,
DWORD eventThread,
DWORD eventTime) {
DWORD eventTime)
{
std::unique_lock lock(mutex);
hook_events.push_back({ event,
window,
@ -31,13 +32,16 @@ static void CALLBACK win_hook_event_proc(HWINEVENTHOOK winEventHook,
static bool running = false;
static std::thread dispatch_thread;
static void dispatch_thread_proc() {
static void dispatch_thread_proc()
{
std::unique_lock lock(mutex);
while (running) {
while (running)
{
dispatch_cv.wait(lock, [] { return !running || !hook_events.empty(); });
if (!running)
return;
while (!hook_events.empty()) {
while (!hook_events.empty())
{
auto event = hook_events.front();
hook_events.pop_front();
lock.unlock();
@ -51,7 +55,8 @@ static void dispatch_thread_proc() {
static HWINEVENTHOOK hook_handle;
void start_win_hook_event() {
void start_win_hook_event()
{
std::lock_guard lock(mutex);
if (running)
return;
@ -60,7 +65,8 @@ void start_win_hook_event() {
hook_handle = SetWinEventHook(EVENT_MIN, EVENT_MAX, nullptr, win_hook_event_proc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
}
void stop_win_hook_event() {
void stop_win_hook_event()
{
std::unique_lock lock(mutex);
if (!running)
return;
@ -74,9 +80,11 @@ void stop_win_hook_event() {
hook_events.shrink_to_fit();
}
void intercept_system_menu_action(intptr_t data) {
void intercept_system_menu_action(intptr_t data)
{
WinHookEvent* evt = reinterpret_cast<WinHookEvent*>(data);
if (evt->event == EVENT_SYSTEM_MENUSTART || evt->event == EVENT_OBJECT_INVOKED) {
if (evt->event == EVENT_SYSTEM_MENUSTART || evt->event == EVENT_OBJECT_INVOKED)
{
powertoys_events().handle_system_menu_action(*evt);
}
}

View file

@ -4,4 +4,3 @@
void start_win_hook_event();
void stop_win_hook_event();