mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-01-18 14:41:21 +08:00
Coding style (runner) (#1013)
This commit is contained in:
parent
9708961654
commit
415a0cdf28
@ -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));
|
||||
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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{};
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
class Trace {
|
||||
class Trace
|
||||
{
|
||||
public:
|
||||
static void RegisterProvider();
|
||||
static void UnregisterProvider();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -4,4 +4,3 @@
|
||||
|
||||
void start_win_hook_event();
|
||||
void stop_win_hook_event();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user