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,351 +12,390 @@
// 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()
{
HRESULT hr = S_OK;
bool enable_auto_start_task_for_this_user() {
HRESULT hr = S_OK;
WCHAR username_domain[USERNAME_DOMAIN_LEN];
WCHAR username[USERNAME_LEN];
WCHAR username_domain[USERNAME_DOMAIN_LEN];
WCHAR username[USERNAME_LEN];
std::wstring wstrTaskName;
std::wstring wstrTaskName;
ITaskService* pService = NULL;
ITaskFolder* pTaskFolder = NULL;
ITaskDefinition* pTask = NULL;
IRegistrationInfo* pRegInfo = NULL;
ITaskSettings* pSettings = NULL;
ITriggerCollection* pTriggerCollection = NULL;
IRegisteredTask* pRegisteredTask = NULL;
ITaskService *pService = NULL;
ITaskFolder *pTaskFolder = NULL;
ITaskDefinition *pTask = NULL;
IRegistrationInfo *pRegInfo = NULL;
ITaskSettings *pSettings = NULL;
ITriggerCollection *pTriggerCollection = NULL;
IRegisteredTask *pRegisteredTask = NULL;
// ------------------------------------------------------
// Get the Domain/Username for the trigger.
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) {
ExitWithLastError(hr, "Getting username failed: %x", hr);
}
if (!GetEnvironmentVariable(L"USERDOMAIN", username_domain, USERNAME_DOMAIN_LEN)) {
ExitWithLastError(hr, "Getting the user's domain failed: %x", hr);
}
wcscat_s(username_domain, L"\\");
wcscat_s(username_domain, username);
// Task Name.
wstrTaskName = L"Autorun for ";
wstrTaskName += username;
// Get the executable path passed to the custom action.
WCHAR wszExecutablePath[MAX_PATH];
GetModuleFileName(NULL, wszExecutablePath, MAX_PATH);
// ------------------------------------------------------
// Create an instance of the Task Service.
hr = CoCreateInstance(CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskService,
(void**)&pService);
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());
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)) {
// 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)) {
pRootFolder->Release();
ExitOnFailure(hr, "Cannot create PowerToys task folder: %x", hr);
// ------------------------------------------------------
// Get the Domain/Username for the trigger.
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN))
{
ExitWithLastError(hr, "Getting username failed: %x", hr);
}
}
// If the task exists, just enable it.
{
IRegisteredTask *pExistingRegisteredTask = NULL;
hr=pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask);
if (SUCCEEDED(hr)) {
// Task exists, try enabling it.
hr = pExistingRegisteredTask->put_Enabled(VARIANT_TRUE);
pExistingRegisteredTask->Release();
if (SUCCEEDED(hr)) {
// Function enable. Sounds like a success.
ExitFunction();
}
if (!GetEnvironmentVariable(L"USERDOMAIN", username_domain, USERNAME_DOMAIN_LEN))
{
ExitWithLastError(hr, "Getting the user's domain failed: %x", hr);
}
}
wcscat_s(username_domain, L"\\");
wcscat_s(username_domain, username);
// Create the task builder object to create the task.
hr = pService->NewTask(0, &pTask);
ExitOnFailure(hr, "Failed to create a task definition: %x", hr);
// Task Name.
wstrTaskName = L"Autorun for ";
wstrTaskName += username;
// ------------------------------------------------------
// Get the registration info for setting the identification.
hr = pTask->get_RegistrationInfo(&pRegInfo);
ExitOnFailure(hr, "Cannot get identification pointer: %x", hr);
hr = pRegInfo->put_Author(_bstr_t(username_domain));
ExitOnFailure(hr, "Cannot put identification info: %x", hr);
// Get the executable path passed to the custom action.
WCHAR wszExecutablePath[MAX_PATH];
GetModuleFileName(NULL, wszExecutablePath, MAX_PATH);
// ------------------------------------------------------
// Create the settings for the task
hr = pTask->get_Settings(&pSettings);
ExitOnFailure(hr, "Cannot get settings pointer: %x", hr);
// ------------------------------------------------------
// Create an instance of the Task Service.
hr = CoCreateInstance(CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskService,
(void**)&pService);
ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr);
hr = pSettings->put_StartWhenAvailable(VARIANT_FALSE);
ExitOnFailure(hr, "Cannot put_StartWhenAvailable setting info: %x", hr);
hr = pSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE);
ExitOnFailure(hr, "Cannot put_StopIfGoingOnBatteries setting info: %x", hr);
hr = pSettings->put_ExecutionTimeLimit(_bstr_t(L"PT0S")); //Unlimited
ExitOnFailure(hr, "Cannot put_ExecutionTimeLimit setting info: %x", hr);
hr = pSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE);
ExitOnFailure(hr, "Cannot put_DisallowStartIfOnBatteries setting info: %x", hr);
// Connect to the task service.
hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
// ------------------------------------------------------
// Get the trigger collection to insert the logon trigger.
hr = pTask->get_Triggers(&pTriggerCollection);
ExitOnFailure(hr, "Cannot get trigger collection: %x", hr);
// Add the logon trigger to the task.
{
ITrigger *pTrigger = NULL;
ILogonTrigger *pLogonTrigger = NULL;
hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger);
ExitOnFailure(hr, "Cannot create the trigger: %x", hr);
hr = pTrigger->QueryInterface(
IID_ILogonTrigger, (void**)&pLogonTrigger);
pTrigger->Release();
ExitOnFailure(hr, "QueryInterface call failed for ILogonTrigger: %x", hr);
hr = pLogonTrigger->put_Id(_bstr_t(L"Trigger1"));
// Timing issues may make explorer not be started when the task runs.
// Add a little delay to mitigate this.
hr = pLogonTrigger->put_Delay(_bstr_t(L"PT03S"));
// Define the user. The task will execute when the user logs on.
// The specified user must be a user on this computer.
hr = pLogonTrigger->put_UserId(_bstr_t(username_domain));
pLogonTrigger->Release();
ExitOnFailure(hr, "Cannot add user ID to logon trigger: %x", hr);
}
// ------------------------------------------------------
// Add an Action to the task. This task will execute the path passed to this custom action.
{
IActionCollection *pActionCollection = NULL;
IAction *pAction = NULL;
IExecAction *pExecAction = NULL;
// Get the task action collection pointer.
hr = pTask->get_Actions(&pActionCollection);
ExitOnFailure(hr, "Cannot get Task collection pointer: %x", hr);
// Create the action, specifying that it is an executable action.
hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction);
pActionCollection->Release();
ExitOnFailure(hr, "Cannot create the action: %x", hr);
// QI for the executable task pointer.
hr = pAction->QueryInterface(
IID_IExecAction, (void**)&pExecAction);
pAction->Release();
ExitOnFailure(hr, "QueryInterface call failed for IExecAction: %x", hr);
// Set the path of the executable to PowerToys (passed as CustomActionData).
hr = pExecAction->put_Path(_bstr_t(wszExecutablePath));
pExecAction->Release();
ExitOnFailure(hr, "Cannot set path of executable: %x", hr);
}
// ------------------------------------------------------
// Create the principal for the task
{
IPrincipal *pPrincipal = NULL;
hr = pTask->get_Principal(&pPrincipal);
ExitOnFailure(hr, "Cannot get principal pointer: %x", hr);
// Set up principal information:
hr = pPrincipal->put_Id(_bstr_t(L"Principal1"));
hr = pPrincipal->put_UserId(_bstr_t(username_domain));
hr = pPrincipal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN);
// Run the task with the highest available privileges.
if (IsUserAnAdmin()) {
hr = pPrincipal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_HIGHEST);
} else {
hr = pPrincipal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_LUA);
// ------------------------------------------------------
// Get the PowerToys task folder. Creates it if it doesn't exist.
hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder);
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))
{
pRootFolder->Release();
ExitOnFailure(hr, "Cannot create PowerToys task folder: %x", hr);
}
}
pPrincipal->Release();
ExitOnFailure(hr, "Cannot put principal run level: %x", hr);
}
// ------------------------------------------------------
// Save the task in the PowerToys folder.
hr = pTaskFolder->RegisterTaskDefinition(
_bstr_t(wstrTaskName.c_str()),
pTask,
TASK_CREATE_OR_UPDATE,
_variant_t(username_domain),
_variant_t(),
TASK_LOGON_INTERACTIVE_TOKEN,
_variant_t(L""),
&pRegisteredTask);
ExitOnFailure(hr, "Error saving the Task : %x", hr);
// If the task exists, just enable it.
{
IRegisteredTask* pExistingRegisteredTask = NULL;
hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask);
if (SUCCEEDED(hr))
{
// Task exists, try enabling it.
hr = pExistingRegisteredTask->put_Enabled(VARIANT_TRUE);
pExistingRegisteredTask->Release();
if (SUCCEEDED(hr))
{
// Function enable. Sounds like a success.
ExitFunction();
}
}
}
// Create the task builder object to create the task.
hr = pService->NewTask(0, &pTask);
ExitOnFailure(hr, "Failed to create a task definition: %x", hr);
// ------------------------------------------------------
// Get the registration info for setting the identification.
hr = pTask->get_RegistrationInfo(&pRegInfo);
ExitOnFailure(hr, "Cannot get identification pointer: %x", hr);
hr = pRegInfo->put_Author(_bstr_t(username_domain));
ExitOnFailure(hr, "Cannot put identification info: %x", hr);
// ------------------------------------------------------
// Create the settings for the task
hr = pTask->get_Settings(&pSettings);
ExitOnFailure(hr, "Cannot get settings pointer: %x", hr);
hr = pSettings->put_StartWhenAvailable(VARIANT_FALSE);
ExitOnFailure(hr, "Cannot put_StartWhenAvailable setting info: %x", hr);
hr = pSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE);
ExitOnFailure(hr, "Cannot put_StopIfGoingOnBatteries setting info: %x", hr);
hr = pSettings->put_ExecutionTimeLimit(_bstr_t(L"PT0S")); //Unlimited
ExitOnFailure(hr, "Cannot put_ExecutionTimeLimit setting info: %x", hr);
hr = pSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE);
ExitOnFailure(hr, "Cannot put_DisallowStartIfOnBatteries setting info: %x", hr);
// ------------------------------------------------------
// Get the trigger collection to insert the logon trigger.
hr = pTask->get_Triggers(&pTriggerCollection);
ExitOnFailure(hr, "Cannot get trigger collection: %x", hr);
// Add the logon trigger to the task.
{
ITrigger* pTrigger = NULL;
ILogonTrigger* pLogonTrigger = NULL;
hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger);
ExitOnFailure(hr, "Cannot create the trigger: %x", hr);
hr = pTrigger->QueryInterface(
IID_ILogonTrigger, (void**)&pLogonTrigger);
pTrigger->Release();
ExitOnFailure(hr, "QueryInterface call failed for ILogonTrigger: %x", hr);
hr = pLogonTrigger->put_Id(_bstr_t(L"Trigger1"));
// Timing issues may make explorer not be started when the task runs.
// Add a little delay to mitigate this.
hr = pLogonTrigger->put_Delay(_bstr_t(L"PT03S"));
// Define the user. The task will execute when the user logs on.
// The specified user must be a user on this computer.
hr = pLogonTrigger->put_UserId(_bstr_t(username_domain));
pLogonTrigger->Release();
ExitOnFailure(hr, "Cannot add user ID to logon trigger: %x", hr);
}
// ------------------------------------------------------
// Add an Action to the task. This task will execute the path passed to this custom action.
{
IActionCollection* pActionCollection = NULL;
IAction* pAction = NULL;
IExecAction* pExecAction = NULL;
// Get the task action collection pointer.
hr = pTask->get_Actions(&pActionCollection);
ExitOnFailure(hr, "Cannot get Task collection pointer: %x", hr);
// Create the action, specifying that it is an executable action.
hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction);
pActionCollection->Release();
ExitOnFailure(hr, "Cannot create the action: %x", hr);
// QI for the executable task pointer.
hr = pAction->QueryInterface(
IID_IExecAction, (void**)&pExecAction);
pAction->Release();
ExitOnFailure(hr, "QueryInterface call failed for IExecAction: %x", hr);
// Set the path of the executable to PowerToys (passed as CustomActionData).
hr = pExecAction->put_Path(_bstr_t(wszExecutablePath));
pExecAction->Release();
ExitOnFailure(hr, "Cannot set path of executable: %x", hr);
}
// ------------------------------------------------------
// Create the principal for the task
{
IPrincipal* pPrincipal = NULL;
hr = pTask->get_Principal(&pPrincipal);
ExitOnFailure(hr, "Cannot get principal pointer: %x", hr);
// Set up principal information:
hr = pPrincipal->put_Id(_bstr_t(L"Principal1"));
hr = pPrincipal->put_UserId(_bstr_t(username_domain));
hr = pPrincipal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN);
// Run the task with the highest available privileges.
if (IsUserAnAdmin())
{
hr = pPrincipal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_HIGHEST);
}
else
{
hr = pPrincipal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_LUA);
}
pPrincipal->Release();
ExitOnFailure(hr, "Cannot put principal run level: %x", hr);
}
// ------------------------------------------------------
// Save the task in the PowerToys folder.
hr = pTaskFolder->RegisterTaskDefinition(
_bstr_t(wstrTaskName.c_str()),
pTask,
TASK_CREATE_OR_UPDATE,
_variant_t(username_domain),
_variant_t(),
TASK_LOGON_INTERACTIVE_TOKEN,
_variant_t(L""),
&pRegisteredTask);
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));
return (SUCCEEDED(hr));
}
bool disable_auto_start_task_for_this_user() {
HRESULT hr = S_OK;
bool disable_auto_start_task_for_this_user()
{
HRESULT hr = S_OK;
WCHAR username[USERNAME_LEN];
std::wstring wstrTaskName;
WCHAR username[USERNAME_LEN];
std::wstring wstrTaskName;
ITaskService *pService = NULL;
ITaskFolder *pTaskFolder = NULL;
ITaskService* pService = NULL;
ITaskFolder* pTaskFolder = NULL;
// ------------------------------------------------------
// Get the Username for the task.
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) {
ExitWithLastError(hr, "Getting username failed: %x", hr);
}
// Task Name.
wstrTaskName = L"Autorun for ";
wstrTaskName += username;
// ------------------------------------------------------
// Create an instance of the Task Service.
hr = CoCreateInstance(CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskService,
(void**)&pService);
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());
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
// ------------------------------------------------------
// Get the PowerToys task folder.
hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder);
if (FAILED(hr)) {
// Folder doesn't exist. No need to disable a non-existing task.
hr = S_OK;
ExitFunction();
}
// ------------------------------------------------------
// If the task exists, disable.
{
IRegisteredTask *pExistingRegisteredTask = NULL;
hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask);
if (SUCCEEDED(hr)) {
// Task exists, try disabling it.
hr = pExistingRegisteredTask->put_Enabled(VARIANT_FALSE);
pExistingRegisteredTask->Release();
if (SUCCEEDED(hr)) {
// Function disable. Sounds like a success.
ExitFunction();
}
// ------------------------------------------------------
// Get the Username for the task.
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN))
{
ExitWithLastError(hr, "Getting username failed: %x", hr);
}
// Task Name.
wstrTaskName = L"Autorun for ";
wstrTaskName += username;
// ------------------------------------------------------
// Create an instance of the Task Service.
hr = CoCreateInstance(CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskService,
(void**)&pService);
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());
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
// ------------------------------------------------------
// Get the PowerToys task folder.
hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder);
if (FAILED(hr))
{
// Folder doesn't exist. No need to disable a non-existing task.
hr = S_OK;
ExitFunction();
}
// ------------------------------------------------------
// If the task exists, disable.
{
IRegisteredTask* pExistingRegisteredTask = NULL;
hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask);
if (SUCCEEDED(hr))
{
// Task exists, try disabling it.
hr = pExistingRegisteredTask->put_Enabled(VARIANT_FALSE);
pExistingRegisteredTask->Release();
if (SUCCEEDED(hr))
{
// Function disable. Sounds like a success.
ExitFunction();
}
}
}
}
LExit:
if (pService) pService->Release();
if (pTaskFolder) pTaskFolder->Release();
if (pService)
pService->Release();
if (pTaskFolder)
pTaskFolder->Release();
return(SUCCEEDED(hr));
return (SUCCEEDED(hr));
}
bool is_auto_start_task_active_for_this_user(){
HRESULT hr = S_OK;
bool is_auto_start_task_active_for_this_user()
{
HRESULT hr = S_OK;
WCHAR username[USERNAME_LEN];
std::wstring wstrTaskName;
WCHAR username[USERNAME_LEN];
std::wstring wstrTaskName;
ITaskService *pService = NULL;
ITaskFolder *pTaskFolder = NULL;
ITaskService* pService = NULL;
ITaskFolder* pTaskFolder = NULL;
// ------------------------------------------------------
// Get the Username for the task.
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) {
ExitWithLastError(hr, "Getting username failed: %x", hr);
}
// Task Name.
wstrTaskName = L"Autorun for ";
wstrTaskName += username;
// ------------------------------------------------------
// Create an instance of the Task Service.
hr = CoCreateInstance(CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskService,
(void**)&pService);
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());
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
// ------------------------------------------------------
// Get the PowerToys task folder.
hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder);
ExitOnFailure(hr, "ITaskFolder doesn't exist: %x", hr);
// ------------------------------------------------------
// If the task exists, disable.
{
IRegisteredTask *pExistingRegisteredTask = NULL;
hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask);
if (SUCCEEDED(hr)) {
// Task exists, get its value.
VARIANT_BOOL is_enabled;
hr = pExistingRegisteredTask->get_Enabled(&is_enabled);
pExistingRegisteredTask->Release();
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();
}
// ------------------------------------------------------
// Get the Username for the task.
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN))
{
ExitWithLastError(hr, "Getting username failed: %x", hr);
}
// Task Name.
wstrTaskName = L"Autorun for ";
wstrTaskName += username;
// ------------------------------------------------------
// Create an instance of the Task Service.
hr = CoCreateInstance(CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskService,
(void**)&pService);
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());
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
// ------------------------------------------------------
// Get the PowerToys task folder.
hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder);
ExitOnFailure(hr, "ITaskFolder doesn't exist: %x", hr);
// ------------------------------------------------------
// If the task exists, disable.
{
IRegisteredTask* pExistingRegisteredTask = NULL;
hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask);
if (SUCCEEDED(hr))
{
// Task exists, get its value.
VARIANT_BOOL is_enabled;
hr = pExistingRegisteredTask->get_Enabled(&is_enabled);
pExistingRegisteredTask->Release();
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();
}
}
}
}
LExit:
if (pService) pService->Release();
if (pTaskFolder) pTaskFolder->Release();
return(SUCCEEDED(hr));
if (pService)
pService->Release();
if (pTaskFolder)
pTaskFolder->Release();
return (SUCCEEDED(hr));
}

View file

@ -10,110 +10,139 @@
static std::wstring settings_theme = L"system";
static bool run_as_elevated = false;
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") {
settings_theme = L"system";
}
run_as_elevated = loaded.GetNamedBoolean(L"run_elevated", false);
return loaded;
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")
{
settings_theme = L"system";
}
run_as_elevated = loaded.GetNamedBoolean(L"run_elevated", false);
return loaded;
}
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 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()) {
enabled.SetNamedValue(name, json::value(powertoy.is_enabled()));
}
result.SetNamedValue(L"enabled", std::move(enabled));
json::JsonObject enabled;
for (auto& [name, powertoy] : modules())
{
enabled.SetNamedValue(name, json::value(powertoy.is_enabled()));
}
result.SetNamedValue(L"enabled", std::move(enabled));
bool is_elevated = is_process_elevated();
result.SetNamedValue(L"is_elevated", json::value(is_elevated));
result.SetNamedValue(L"run_elevated", json::value(run_as_elevated));
result.SetNamedValue(L"theme", json::value(settings_theme));
result.SetNamedValue(L"system_theme", json::value(WindowsColors::is_dark_mode() ? L"dark" : L"light"));
result.SetNamedValue(L"powertoys_version", json::value(get_product_version()));
return result;
bool is_elevated = is_process_elevated();
result.SetNamedValue(L"is_elevated", json::value(is_elevated));
result.SetNamedValue(L"run_elevated", json::value(run_as_elevated));
result.SetNamedValue(L"theme", json::value(settings_theme));
result.SetNamedValue(L"system_theme", json::value(WindowsColors::is_dark_mode() ? L"dark" : L"light"));
result.SetNamedValue(L"powertoys_version", json::value(get_product_version()));
return result;
}
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) {
enable_auto_start_task_for_this_user();
} else {
disable_auto_start_task_for_this_user();
}
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)
{
enable_auto_start_task_for_this_user();
}
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")) {
const auto value = enabled_element.Value();
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) {
continue;
}
const bool module_inst_enabled = modules().at(name).is_enabled();
const bool target_enabled = value.GetBoolean();
if (module_inst_enabled == target_enabled) {
continue;
}
if (target_enabled) {
modules().at(name).enable();
} else {
modules().at(name).disable();
}
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)
{
continue;
}
const std::wstring name{ enabled_element.Key().c_str() };
const bool found = modules().find(name) != modules().end();
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)
{
continue;
}
if (target_enabled)
{
modules().at(name).enable();
}
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)) {
settings_theme = general_configs.GetNamedString(L"theme");
}
json::JsonObject save_settings = get_general_settings();
PTSettingsHelper::save_general_settings(save_settings);
run_as_elevated = general_configs.GetNamedBoolean(L"run_elevated", false);
if (json::has(general_configs, L"theme", json::JsonValueType::String))
{
settings_theme = general_configs.GetNamedString(L"theme");
}
json::JsonObject save_settings = get_general_settings();
PTSettingsHelper::save_general_settings(save_settings);
}
void start_initial_powertoys() {
bool only_enable_some_powertoys = false;
void start_initial_powertoys()
{
bool only_enable_some_powertoys = false;
std::unordered_set<std::wstring> powertoys_to_enable;
std::unordered_set<std::wstring> powertoys_to_enable;
json::JsonObject general_settings;
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()) {
// Enable this powertoy.
powertoys_to_enable.emplace(enabled_element.Key());
}
json::JsonObject general_settings;
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())
{
// Enable this powertoy.
powertoys_to_enable.emplace(enabled_element.Key());
}
}
only_enable_some_powertoys = true;
}
only_enable_some_powertoys = true;
}
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()) {
powertoy.enable();
}
} else {
powertoy.enable();
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())
{
powertoy.enable();
}
}
else
{
powertoy.enable();
}
}
}
}

View file

@ -4,5 +4,5 @@
json::JsonObject load_general_settings();
json::JsonObject get_general_settings();
void apply_general_settings(const json::JsonObject & general_configs);
void apply_general_settings(const json::JsonObject& general_configs);
void start_initial_powertoys();

View file

@ -2,44 +2,54 @@
#include "lowlevel_keyboard_event.h"
#include "powertoys_events.h"
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) {
LowlevelKeyboardEvent event;
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) {
return 1;
}
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)
{
LowlevelKeyboardEvent event;
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)
{
return 1;
}
}
return CallNextHookEx(hook_handle_copy, nCode, wParam, lParam);
}
return CallNextHookEx(hook_handle_copy, nCode, wParam, lParam);
}
}
// 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()) {
return;
}
if (IsDebuggerPresent())
{
return;
}
#endif
if (!hook_handle) {
hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, hook_proc, GetModuleHandle(NULL), NULL);
hook_handle_copy = hook_handle;
if (!hook_handle) {
throw std::runtime_error("Cannot install keyboard listener");
if (!hook_handle)
{
hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, hook_proc, GetModuleHandle(NULL), NULL);
hook_handle_copy = hook_handle;
if (!hook_handle)
{
throw std::runtime_error("Cannot install keyboard listener");
}
}
}
}
void stop_lowlevel_keyboard_hook() {
if (hook_handle) {
UnhookWindowsHookEx(hook_handle);
hook_handle = nullptr;
}
void stop_lowlevel_keyboard_hook()
{
if (hook_handle)
{
UnhookWindowsHookEx(hook_handle);
hook_handle = nullptr;
}
}

View file

@ -19,107 +19,125 @@
extern "C" IMAGE_DOS_HEADER __ImageBase;
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)) {
show_last_error_message(L"Change Directory to Executable Path", GetLastError());
}
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))
{
show_last_error_message(L"Change Directory to Executable Path", GetLastError());
}
}
int runner() {
DPIAware::EnableDPIAwarenessForThisProcess();
#if _DEBUG && _WIN64
//Global error handlers to diagnose errors.
//We prefer this not not show any longer until there's a bug to diagnose.
//init_global_error_handlers();
#endif
Trace::RegisterProvider();
winrt::init_apartment();
start_tray_icon();
int result;
try {
chdir_current_executable();
// Load Powertyos DLLS
// For now only load known DLLs
std::unordered_set<std::wstring> known_dlls = {
L"shortcut_guide.dll",
L"fancyzones.dll",
L"PowerRenameExt.dll"
};
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 {
auto module = load_powertoy(file.path().wstring());
modules().emplace(module.get_name(), std::move(module));
} catch (...) { }
}
// Start initial powertoys
start_initial_powertoys();
int runner()
{
DPIAware::EnableDPIAwarenessForThisProcess();
Trace::EventLaunch(get_product_version());
#if _DEBUG && _WIN64
//Global error handlers to diagnose errors.
//We prefer this not not show any longer until there's a bug to diagnose.
//init_global_error_handlers();
#endif
Trace::RegisterProvider();
winrt::init_apartment();
start_tray_icon();
int result;
try
{
chdir_current_executable();
// Load Powertyos DLLS
// For now only load known DLLs
std::unordered_set<std::wstring> known_dlls = {
L"shortcut_guide.dll",
L"fancyzones.dll",
L"PowerRenameExt.dll"
};
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
{
auto module = load_powertoy(file.path().wstring());
modules().emplace(module.get_name(), std::move(module));
}
catch (...)
{
}
}
// Start initial powertoys
start_initial_powertoys();
result = run_message_loop();
} 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;
}
Trace::UnregisterProvider();
return result;
Trace::EventLaunch(get_product_version());
result = run_message_loop();
}
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;
}
Trace::UnregisterProvider();
return result;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WCHAR username[UNLEN + 1];
DWORD username_length = UNLEN + 1;
GetUserNameW(username, &username_length);
auto runner_mutex = CreateMutexW(NULL, TRUE, (std::wstring(L"Local\\PowerToyRunMutex") + username).c_str());
if (runner_mutex == NULL || GetLastError() == ERROR_ALREADY_EXISTS) {
// The app is already running
return 0;
}
int result = 0;
try {
// Singletons initialization order needs to be preserved, first events and
// then modules to guarantee the reverse destruction order.
SystemMenuHelperInstace();
powertoys_events();
modules();
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WCHAR username[UNLEN + 1];
DWORD username_length = UNLEN + 1;
GetUserNameW(username, &username_length);
auto runner_mutex = CreateMutexW(NULL, TRUE, (std::wstring(L"Local\\PowerToyRunMutex") + username).c_str());
if (runner_mutex == NULL || GetLastError() == ERROR_ALREADY_EXISTS)
{
// The app is already running
return 0;
}
int result = 0;
try
{
// Singletons initialization order needs to be preserved, first events and
// then modules to guarantee the reverse destruction order.
SystemMenuHelperInstace();
powertoys_events();
modules();
auto general_settings = load_general_settings();
int rvalue = 0;
if (is_process_elevated() ||
general_settings.GetNamedBoolean(L"run_elevated", false) == false ||
strcmp(lpCmdLine, "--dont-elevate") == 0) {
result = runner();
auto general_settings = load_general_settings();
int rvalue = 0;
if (is_process_elevated() ||
general_settings.GetNamedBoolean(L"run_elevated", false) == false ||
strcmp(lpCmdLine, "--dont-elevate") == 0)
{
result = runner();
}
else
{
schedule_restart_as_elevated();
result = 0;
}
}
else {
schedule_restart_as_elevated();
result = 0;
catch (std::runtime_error& err)
{
std::string err_what = err.what();
MessageBoxW(NULL, std::wstring(err_what.begin(), err_what.end()).c_str(), GET_RESOURCE_STRING(IDS_ERROR).c_str(), MB_OK | MB_ICONERROR);
result = -1;
}
}
catch (std::runtime_error & err) {
std::string err_what = err.what();
MessageBoxW(NULL, std::wstring(err_what.begin(), err_what.end()).c_str(), GET_RESOURCE_STRING(IDS_ERROR).c_str(), MB_OK | MB_ICONERROR);
result = -1;
}
ReleaseMutex(runner_mutex);
CloseHandle(runner_mutex);
if (is_restart_scheduled()) {
if (restart_if_scheduled() == false) {
auto text = is_process_elevated() ? GET_RESOURCE_STRING(IDS_COULDNOT_RESTART_NONELEVATED) :
GET_RESOURCE_STRING(IDS_COULDNOT_RESTART_ELEVATED);
MessageBoxW(NULL, text.c_str(), GET_RESOURCE_STRING(IDS_ERROR).c_str(), MB_OK | MB_ICONERROR);
result = -1;
ReleaseMutex(runner_mutex);
CloseHandle(runner_mutex);
if (is_restart_scheduled())
{
if (restart_if_scheduled() == false)
{
auto text = is_process_elevated() ? GET_RESOURCE_STRING(IDS_COULDNOT_RESTART_NONELEVATED) :
GET_RESOURCE_STRING(IDS_COULDNOT_RESTART_ELEVATED);
MessageBoxW(NULL, text.c_str(), GET_RESOURCE_STRING(IDS_ERROR).c_str(), MB_OK | MB_ICONERROR);
result = -1;
}
}
}
stop_tray_icon();
return result;
stop_tray_icon();
return result;
}

View file

@ -3,32 +3,37 @@
#include "lowlevel_keyboard_event.h"
#include <algorithm>
std::unordered_map<std::wstring, PowertoyModule>& modules() {
static std::unordered_map<std::wstring, PowertoyModule> modules;
return 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) {
auto handle = winrt::check_pointer(LoadLibraryW(filename.c_str()));
auto create = reinterpret_cast<powertoy_create_func>(GetProcAddress(handle, "powertoy_create"));
if (!create) {
FreeLibrary(handle);
winrt::throw_last_error();
}
auto module = create();
if (!module) {
FreeLibrary(handle);
winrt::throw_last_error();
}
module->register_system_menu_helper(&SystemMenuHelperInstace());
return PowertoyModule(module, handle);
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)
{
FreeLibrary(handle);
winrt::throw_last_error();
}
auto module = create();
if (!module)
{
FreeLibrary(handle);
winrt::throw_last_error();
}
module->register_system_menu_helper(&SystemMenuHelperInstace());
return PowertoyModule(module, handle);
}
json::JsonObject PowertoyModule::json_config() const {
int size = 0;
module->get_config(nullptr, &size);
std::wstring result;
result.resize(size - 1);
module->get_config(result.data(), &size);
return json::JsonObject::Parse(result);
json::JsonObject PowertoyModule::json_config() const
{
int size = 0;
module->get_config(nullptr, &size);
std::wstring result;
result.resize(size - 1);
module->get_config(result.data(), &size);
return json::JsonObject::Parse(result);
}

View file

@ -11,87 +11,108 @@
class PowertoyModule;
#include <common/json.h>
struct PowertoyModuleDeleter {
void operator()(PowertoyModuleIface* module) const {
if (module) {
powertoys_events().unregister_system_menu_action(module);
powertoys_events().unregister_receiver(module);
module->destroy();
struct PowertoyModuleDeleter
{
void operator()(PowertoyModuleIface* module) const
{
if (module)
{
powertoys_events().unregister_system_menu_action(module);
powertoys_events().unregister_receiver(module);
module->destroy();
}
}
}
};
struct PowertoyModuleDLLDeleter {
using pointer = HMODULE;
void operator()(HMODULE handle) const {
FreeLibrary(handle);
}
struct PowertoyModuleDLLDeleter
{
using pointer = HMODULE;
void operator()(HMODULE handle) const
{
FreeLibrary(handle);
}
};
class PowertoyModule {
class PowertoyModule
{
public:
PowertoyModule(PowertoyModuleIface* module, HMODULE handle) : handle(handle), module(module) {
if (!module) {
throw std::runtime_error("Module not initialized");
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)
{
powertoys_events().register_receiver(*want_signals, module);
}
}
if (SystemMenuHelperInstace().HasCustomConfig(module))
{
powertoys_events().register_system_menu_action(module);
}
}
name = module->get_name();
auto want_signals = module->get_events();
if (want_signals) {
for (; *want_signals; ++want_signals) {
powertoys_events().register_receiver(*want_signals, module);
}
const std::wstring& get_name() const
{
return name;
}
if (SystemMenuHelperInstace().HasCustomConfig(module)) {
powertoys_events().register_system_menu_action(module);
json::JsonObject json_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))
{
result.assign(buffer);
}
delete[] buffer;
return result;
}
}
const std::wstring& get_name() const {
return name;
}
json::JsonObject json_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)) {
result.assign(buffer);
void set_config(const std::wstring& config)
{
module->set_config(config.c_str());
}
delete[] buffer;
return result;
}
void set_config(const std::wstring& config) {
module->set_config(config.c_str());
}
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) {
return module->signal_event(signal_event.c_str(), data);
}
void call_custom_action(const std::wstring& action)
{
module->call_custom_action(action.c_str());
}
bool is_enabled() {
return module->is_enabled();
}
void enable() {
module->enable();
}
void disable() {
module->disable();
}
intptr_t signal_event(const std::wstring& signal_event, intptr_t data)
{
return module->signal_event(signal_event.c_str(), data);
}
bool is_enabled()
{
return module->is_enabled();
}
void enable()
{
module->enable();
}
void disable()
{
module->disable();
}
private:
std::unique_ptr<HMODULE, PowertoyModuleDLLDeleter> handle;
std::unique_ptr<PowertoyModuleIface, PowertoyModuleDeleter> module;
std::wstring name;
std::unique_ptr<HMODULE, PowertoyModuleDLLDeleter> handle;
std::unique_ptr<PowertoyModuleIface, PowertoyModuleDeleter> module;
std::wstring name;
};
PowertoyModule load_powertoy(const std::wstring& filename);

View file

@ -4,83 +4,102 @@
#include "win_hook_event.h"
#include "system_menu_helper.h"
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 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) {
if (event == ll_keyboard)
stop_lowlevel_keyboard_hook();
else if (event == win_hook_event)
stop_win_hook_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() {
static PowertoysEvents powertoys_events;
return powertoys_events;
PowertoysEvents& powertoys_events()
{
static PowertoysEvents powertoys_events;
return powertoys_events;
}
void PowertoysEvents::register_receiver(const std::wstring & event, PowertoyModuleIface* module) {
std::unique_lock lock(mutex);
auto& subscribers = receivers[event];
if (subscribers.empty()) {
first_subscribed(event);
}
subscribers.push_back(module);
}
void PowertoysEvents::unregister_receiver(PowertoyModuleIface* module) {
std::unique_lock lock(mutex);
for (auto&[event, subscribers] : receivers) {
subscribers.erase(remove(begin(subscribers), end(subscribers), module), end(subscribers));
if (subscribers.empty()) {
last_unsubscribed(event);
void PowertoysEvents::register_receiver(const std::wstring& event, PowertoyModuleIface* module)
{
std::unique_lock lock(mutex);
auto& subscribers = receivers[event];
if (subscribers.empty())
{
first_subscribed(event);
}
}
subscribers.push_back(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) {
std::unique_lock lock(mutex);
auto it = system_menu_receivers.find(module);
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) {
SystemMenuHelperInstace().Customize(module, data.hwnd);
void PowertoysEvents::unregister_receiver(PowertoyModuleIface* module)
{
std::unique_lock lock(mutex);
for (auto& [event, subscribers] : receivers)
{
subscribers.erase(remove(begin(subscribers), end(subscribers), module), end(subscribers));
if (subscribers.empty())
{
last_unsubscribed(event);
}
}
}
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());
// Process event on specified system menu item by system menu helper (check/uncheck if needed).
SystemMenuHelperInstace().ProcessSelectedItem(module, GetForegroundWindow(), itemName.c_str());
}
}
}
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 (module)
rvalue |= module->signal_event(event.c_str(), data);
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)
{
std::unique_lock lock(mutex);
auto it = system_menu_receivers.find(module);
if (it != system_menu_receivers.end())
{
SystemMenuHelperInstace().Reset(module);
system_menu_receivers.erase(it);
}
}
return rvalue;
}
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) })
{
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());
// Process event on specified system menu item by system menu helper (check/uncheck if needed).
SystemMenuHelperInstace().ProcessSelectedItem(module, GetForegroundWindow(), itemName.c_str());
}
}
}
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 (module)
rvalue |= module->signal_event(event.c_str(), data);
}
}
return rvalue;
}

View file

@ -4,24 +4,25 @@
#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);
void register_receiver(const std::wstring& event, PowertoyModuleIface* module);
void unregister_receiver(PowertoyModuleIface* module);
void register_system_menu_action(PowertoyModuleIface* module);
void unregister_system_menu_action(PowertoyModuleIface* module);
void handle_system_menu_action(const WinHookEvent& data);
void register_system_menu_action(PowertoyModuleIface* module);
void unregister_system_menu_action(PowertoyModuleIface* module);
void handle_system_menu_action(const WinHookEvent& data);
intptr_t signal_event(const std::wstring& event, intptr_t 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;
std::unordered_set<PowertoyModuleIface*> system_menu_receivers;
std::shared_mutex mutex;
std::unordered_map<std::wstring, std::vector<PowertoyModuleIface*>> receivers;
std::unordered_set<PowertoyModuleIface*> system_menu_receivers;
};
PowertoysEvents& powertoys_events();
void first_subscribed(const std::wstring& event);
void last_unsubscribed(const std::wstring& event);

View file

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

View file

@ -68,7 +68,7 @@ void dispatch_json_action_to_module(const json::JsonObject& powertoys_configs)
else if (modules().find(name) != modules().end())
{
const auto element = powertoy_element.Value().Stringify();
modules().at(name).call_custom_action(element.c_str());
modules().at(name).call_custom_action(element.c_str());
}
}
}
@ -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)
{
@ -166,7 +165,7 @@ BOOL run_settings_non_elevated(LPCWSTR executable_path, LPWSTR executable_args,
SIZE_T size = 0;
InitializeProcThreadAttributeList(nullptr, 1, 0, &size);
auto pproc_buffer = std::unique_ptr<char[]>{new (std::nothrow)char[size]};
auto pproc_buffer = std::unique_ptr<char[]>{ new (std::nothrow) char[size] };
auto pptal = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(pproc_buffer.get());
if (!pptal)
{

View file

@ -3,127 +3,158 @@
#include <interface/powertoy_module_interface.h>
namespace {
constexpr int KSeparatorPos = 1;
constexpr int KNewItemPos = 2;
namespace
{
constexpr int KSeparatorPos = 1;
constexpr int KNewItemPos = 2;
unsigned int GenerateItemId() {
static unsigned int generator = 0x70777479;
return ++generator;
}
unsigned int GenerateItemId()
{
static unsigned int generator = 0x70777479;
return ++generator;
}
}
SystemMenuHelper& SystemMenuHelperInstace() {
static SystemMenuHelper instance;
return instance;
SystemMenuHelper& SystemMenuHelperInstace()
{
static SystemMenuHelper instance;
return instance;
}
void SystemMenuHelper::SetConfiguration(PowertoyModuleIface* module, const std::vector<ItemInfo>& config) {
Reset(module);
Configurations[module] = config;
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::SetConfiguration(PowertoyModuleIface* module, const std::vector<ItemInfo>& config)
{
Reset(module);
Configurations[module] = config;
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) {
// Handle check/uncheck action only if specified by module configuration.
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);
break;
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)
{
HMENU systemMenu = GetSystemMenu(window, false);
int state = (GetMenuState(systemMenu, id, MF_BYCOMMAND) == MF_CHECKED) ? MF_UNCHECKED : MF_CHECKED;
CheckMenuItem(systemMenu, id, MF_BYCOMMAND | state);
break;
}
}
break;
}
}
break;
}
}
}
bool SystemMenuHelper::Customize(PowertoyModuleIface* module, HWND window) {
auto& modules = ProcessedModules[window];
for (const auto& m : modules) {
if (module == m) {
return false;
}
}
AddSeparator(module, window);
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) {
DeleteMenu(systemMenu, id, MF_BYCOMMAND);
bool SystemMenuHelper::Customize(PowertoyModuleIface* module, HWND window)
{
auto& modules = ProcessedModules[window];
for (const auto& m : modules)
{
if (module == m)
{
return false;
}
}
}
}
}
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) }) {
MENUITEMINFO item;
item.cbSize = sizeof(item);
item.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;
item.fState = MF_UNCHECKED | MF_DISABLED; // Item is disabled by default.
item.wID = GenerateItemId();
item.dwTypeData = const_cast<WCHAR*>(name.c_str());
item.cch = (UINT)name.size() + 1;
if (InsertMenuItem(systemMenu, GetMenuItemCount(systemMenu) - KNewItemPos, true, &item)) {
IdMappings[item.wID] = { module, name };
if (enable) {
EnableMenuItem(systemMenu, item.wID, MF_BYCOMMAND | MF_ENABLED);
}
return true;
AddSeparator(module, window);
for (const auto& info : Configurations[module])
{
AddItem(module, window, info.name, info.enable);
}
}
return false;
modules.push_back(module);
return true;
}
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)) {
IdMappings[separator.wID] = { module, L"sepparator_dummy_name" };
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)
{
DeleteMenu(systemMenu, id, MF_BYCOMMAND);
}
}
}
}
}
return false;
}
PowertoyModuleIface* SystemMenuHelper::ModuleFromItemId(const int& id) {
auto it = IdMappings.find(id);
if (it != IdMappings.end()) {
return it->second.first;
}
return nullptr;
bool SystemMenuHelper::HasCustomConfig(PowertoyModuleIface* module)
{
return Configurations.find(module) != Configurations.end();
}
const std::wstring SystemMenuHelper::ItemNameFromItemId(const int& id) {
auto itemIt = IdMappings.find(id);
if (itemIt != IdMappings.end()) {
return itemIt->second.second;
}
return std::wstring{};
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;
item.fState = MF_UNCHECKED | MF_DISABLED; // Item is disabled by default.
item.wID = GenerateItemId();
item.dwTypeData = const_cast<WCHAR*>(name.c_str());
item.cch = (UINT)name.size() + 1;
if (InsertMenuItem(systemMenu, GetMenuItemCount(systemMenu) - KNewItemPos, true, &item))
{
IdMappings[item.wID] = { module, name };
if (enable)
{
EnableMenuItem(systemMenu, item.wID, MF_BYCOMMAND | MF_ENABLED);
}
return true;
}
}
return 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))
{
IdMappings[separator.wID] = { module, L"sepparator_dummy_name" };
return true;
}
}
return false;
}
PowertoyModuleIface* SystemMenuHelper::ModuleFromItemId(const int& id)
{
auto it = IdMappings.find(id);
if (it != IdMappings.end())
{
return it->second.first;
}
return nullptr;
}
const std::wstring SystemMenuHelper::ItemNameFromItemId(const int& id)
{
auto itemIt = IdMappings.find(id);
if (itemIt != IdMappings.end())
{
return itemIt->second.second;
}
return std::wstring{};
}

View file

@ -10,33 +10,34 @@
class PowertoyModuleIface;
class SystemMenuHelper : public PowertoySystemMenuIface {
class SystemMenuHelper : public PowertoySystemMenuIface
{
public:
// PowertoySystemMenuIface
virtual void SetConfiguration(PowertoyModuleIface* module, const std::vector<ItemInfo>& config) override;
virtual void ProcessSelectedItem(PowertoyModuleIface* module, HWND window, const wchar_t* itemName) override;
// PowertoySystemMenuIface
virtual void SetConfiguration(PowertoyModuleIface* module, const std::vector<ItemInfo>& config) override;
virtual void ProcessSelectedItem(PowertoyModuleIface* module, HWND window, const wchar_t* itemName) override;
bool Customize(PowertoyModuleIface* module, HWND window);
void Reset(PowertoyModuleIface* module);
bool Customize(PowertoyModuleIface* module, HWND window);
void Reset(PowertoyModuleIface* module);
bool HasCustomConfig(PowertoyModuleIface* module);
bool HasCustomConfig(PowertoyModuleIface* module);
PowertoyModuleIface* ModuleFromItemId(const int& id);
const std::wstring ItemNameFromItemId(const int& id);
PowertoyModuleIface* ModuleFromItemId(const int& id);
const std::wstring ItemNameFromItemId(const int& id);
private:
bool AddItem(PowertoyModuleIface* module, HWND window, const std::wstring& name, const bool enable);
bool AddSeparator(PowertoyModuleIface* module, HWND window);
bool AddItem(PowertoyModuleIface* module, HWND window, const std::wstring& name, const bool enable);
bool AddSeparator(PowertoyModuleIface* module, HWND window);
// Store processed modules per window to avoid handling it multiple times.
std::unordered_map<HWND, std::vector<PowertoyModuleIface*>> ProcessedModules{};
// Store processed modules per window to avoid handling it multiple times.
std::unordered_map<HWND, std::vector<PowertoyModuleIface*>> ProcessedModules{};
// Keep mappings form item id to the module who created it and item name for faster processing later.
std::unordered_map<int, std::pair<PowertoyModuleIface*, std::wstring>> IdMappings{};
// Keep mappings form item id to the module who created it and item name for faster processing later.
std::unordered_map<int, std::pair<PowertoyModuleIface*, std::wstring>> IdMappings{};
// Store configurations provided by module.
// This will be used to create custom system menu items and to handle updates.
std::unordered_map<PowertoyModuleIface*, std::vector<ItemInfo>> Configurations{};
// Store configurations provided by module.
// This will be used to create custom system menu items and to handle updates.
std::unordered_map<PowertoyModuleIface*, std::vector<ItemInfo>> Configurations{};
};
SystemMenuHelper& SystemMenuHelperInstace();

View file

@ -2,26 +2,29 @@
#include "trace.h"
TRACELOGGING_DEFINE_PROVIDER(
g_hProvider,
"Microsoft.PowerToys",
// {38e8889b-9731-53f5-e901-e8a7c1753074}
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
TraceLoggingOptionProjectTelemetry());
void Trace::RegisterProvider() {
TraceLoggingRegister(g_hProvider);
}
void Trace::UnregisterProvider() {
TraceLoggingUnregister(g_hProvider);
}
void Trace::EventLaunch(const std::wstring& versionNumber) {
TraceLoggingWrite(
g_hProvider,
"Runner_Launch",
TraceLoggingWideString(versionNumber.c_str(), "Version"),
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
"Microsoft.PowerToys",
// {38e8889b-9731-53f5-e901-e8a7c1753074}
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
TraceLoggingOptionProjectTelemetry());
void Trace::RegisterProvider()
{
TraceLoggingRegister(g_hProvider);
}
void Trace::UnregisterProvider()
{
TraceLoggingUnregister(g_hProvider);
}
void Trace::EventLaunch(const std::wstring& versionNumber)
{
TraceLoggingWrite(
g_hProvider,
"Runner_Launch",
TraceLoggingWideString(versionNumber.c_str(), "Version"),
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
}

View file

@ -1,8 +1,9 @@
#pragma once
class Trace {
class Trace
{
public:
static void RegisterProvider();
static void UnregisterProvider();
static void EventLaunch(const std::wstring& versionNumber);
static void RegisterProvider();
static void UnregisterProvider();
static void EventLaunch(const std::wstring& versionNumber);
};

View file

@ -7,177 +7,199 @@
extern "C" IMAGE_DOS_HEADER __ImageBase;
namespace {
HWND tray_icon_hwnd = NULL;
namespace
{
HWND tray_icon_hwnd = NULL;
// Message code that Windows will use for tray icon notifications.
UINT wm_icon_notify = 0;
// Message code that Windows will use for tray icon notifications.
UINT wm_icon_notify = 0;
// Contains the Windows Message for taskbar creation.
UINT wm_taskbar_restart = 0;
UINT wm_run_on_main_ui_thread = 0;
// Contains the Windows Message for taskbar creation.
UINT wm_taskbar_restart = 0;
UINT wm_run_on_main_ui_thread = 0;
NOTIFYICONDATAW tray_icon_data;
bool tray_icon_created = false;
NOTIFYICONDATAW tray_icon_data;
bool tray_icon_created = false;
bool about_box_shown = false;
bool about_box_shown = false;
HMENU h_menu = nullptr;
HMENU h_sub_menu = nullptr;
HMENU h_menu = nullptr;
HMENU h_sub_menu = nullptr;
}
// Struct to fill with callback and the data. The window_proc is responsible for cleaning it.
struct run_on_main_ui_thread_msg {
main_loop_callback_function _callback;
PVOID data;
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) {
return false;
}
struct run_on_main_ui_thread_msg *wnd_msg = new struct run_on_main_ui_thread_msg();
wnd_msg->_callback = _callback;
wnd_msg->data = data;
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();
wnd_msg->_callback = _callback;
wnd_msg->data = data;
PostMessage(tray_icon_hwnd, wm_run_on_main_ui_thread, 0, (LPARAM)wnd_msg);
PostMessage(tray_icon_hwnd, wm_run_on_main_ui_thread, 0, (LPARAM)wnd_msg);
return true;
return true;
}
LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) {
switch (message) {
case WM_CREATE:
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) {
Shell_NotifyIcon(NIM_DELETE, &tray_icon_data);
tray_icon_created = false;
}
PostQuitMessage(0);
break;
case WM_CLOSE:
DestroyWindow(window);
break;
case WM_COMMAND:
switch(wparam) {
case ID_SETTINGS_MENU_COMMAND:
open_settings_window();
break;
case ID_EXIT_MENU_COMMAND:
if (h_menu) {
DestroyMenu(h_menu);
LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
{
switch (message)
{
case WM_CREATE:
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)
{
Shell_NotifyIcon(NIM_DELETE, &tray_icon_data);
tray_icon_created = false;
}
PostQuitMessage(0);
break;
case WM_CLOSE:
DestroyWindow(window);
break;
case ID_ABOUT_MENU_COMMAND:
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);
about_box_shown = false;
case WM_COMMAND:
switch (wparam)
{
case ID_SETTINGS_MENU_COMMAND:
open_settings_window();
break;
case ID_EXIT_MENU_COMMAND:
if (h_menu)
{
DestroyMenu(h_menu);
}
DestroyWindow(window);
break;
case ID_ABOUT_MENU_COMMAND:
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);
about_box_shown = false;
}
break;
}
break;
// 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: {
if (!tray_icon_created)
{
tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE;
}
break;
}
break;
// 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:
{
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:
default:
if (message == wm_icon_notify)
{
open_settings_window();
break;
switch (lparam)
{
case WM_LBUTTONUP: {
open_settings_window();
break;
}
case WM_RBUTTONUP:
case WM_CONTEXTMENU: {
if (!h_menu)
{
h_menu = LoadMenu(reinterpret_cast<HINSTANCE>(&__ImageBase), MAKEINTRESOURCE(ID_TRAY_MENU));
}
if (!h_sub_menu)
{
h_sub_menu = GetSubMenu(h_menu, 0);
}
POINT mouse_pointer;
GetCursorPos(&mouse_pointer);
SetForegroundWindow(window); // Needed for the context menu to disappear.
TrackPopupMenu(h_sub_menu, TPM_CENTERALIGN | TPM_BOTTOMALIGN, mouse_pointer.x, mouse_pointer.y, 0, window, nullptr);
}
break;
}
}
case WM_RBUTTONUP:
case WM_CONTEXTMENU:
else if (message == wm_run_on_main_ui_thread)
{
if (!h_menu) {
h_menu = LoadMenu(reinterpret_cast<HINSTANCE>(&__ImageBase), MAKEINTRESOURCE(ID_TRAY_MENU));
}
if (!h_sub_menu) {
h_sub_menu = GetSubMenu(h_menu, 0);
}
POINT mouse_pointer;
GetCursorPos(&mouse_pointer);
SetForegroundWindow(window); // Needed for the context menu to disappear.
TrackPopupMenu(h_sub_menu, TPM_CENTERALIGN|TPM_BOTTOMALIGN, mouse_pointer.x, mouse_pointer.y, 0, window, nullptr);
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)
{
tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE;
break;
}
break;
}
} 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) {
tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE;
break;
}
}
return DefWindowProc(window, message, wparam, lparam);
return DefWindowProc(window, message, wparam, lparam);
}
void start_tray_icon() {
auto h_instance = reinterpret_cast<HINSTANCE>(&__ImageBase);
auto icon = LoadIcon(h_instance, MAKEINTRESOURCE(APPICON));
if (icon) {
UINT id_tray_icon = wm_icon_notify = RegisterWindowMessageW(L"WM_PowerToysIconNotify");
void start_tray_icon()
{
auto h_instance = reinterpret_cast<HINSTANCE>(&__ImageBase);
auto icon = LoadIcon(h_instance, MAKEINTRESOURCE(APPICON));
if (icon)
{
UINT id_tray_icon = wm_icon_notify = RegisterWindowMessageW(L"WM_PowerToysIconNotify");
static LPCWSTR class_name = L"PToyTrayIconWindow";
WNDCLASS wc = {};
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hInstance = h_instance;
wc.lpszClassName = class_name;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = tray_icon_window_proc;
wc.hIcon = icon;
RegisterClass(&wc);
auto hwnd = CreateWindowW(wc.lpszClassName,
L"PToyTrayIconWindow",
WS_OVERLAPPEDWINDOW | WS_POPUP,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
nullptr,
nullptr,
wc.hInstance,
nullptr);
WINRT_VERIFY(hwnd);
static LPCWSTR class_name = L"PToyTrayIconWindow";
WNDCLASS wc = {};
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hInstance = h_instance;
wc.lpszClassName = class_name;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = tray_icon_window_proc;
wc.hIcon = icon;
RegisterClass(&wc);
auto hwnd = CreateWindowW(wc.lpszClassName,
L"PToyTrayIconWindow",
WS_OVERLAPPEDWINDOW | WS_POPUP,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
nullptr,
nullptr,
wc.hInstance,
nullptr);
WINRT_VERIFY(hwnd);
memset(&tray_icon_data, 0, sizeof(tray_icon_data));
tray_icon_data.cbSize = sizeof(tray_icon_data);
tray_icon_data.hIcon = icon;
tray_icon_data.hWnd = hwnd;
tray_icon_data.uID = id_tray_icon;
tray_icon_data.uCallbackMessage = wm_icon_notify;
wcscpy_s(tray_icon_data.szTip, sizeof(tray_icon_data.szTip) / sizeof(WCHAR), L"PowerToys");
tray_icon_data.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
memset(&tray_icon_data, 0, sizeof(tray_icon_data));
tray_icon_data.cbSize = sizeof(tray_icon_data);
tray_icon_data.hIcon = icon;
tray_icon_data.hWnd = hwnd;
tray_icon_data.uID = id_tray_icon;
tray_icon_data.uCallbackMessage = wm_icon_notify;
wcscpy_s(tray_icon_data.szTip, sizeof(tray_icon_data.szTip) / sizeof(WCHAR), L"PowerToys");
tray_icon_data.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE;
}
tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE;
}
}
void stop_tray_icon() {
if (tray_icon_created) {
SendMessage(tray_icon_hwnd, WM_CLOSE, 0, 0);
}
void stop_tray_icon()
{
if (tray_icon_created)
{
SendMessage(tray_icon_hwnd, WM_CLOSE, 0, 0);
}
}

View file

@ -6,6 +6,6 @@ void stop_tray_icon();
// Open the Settings Window
void open_settings_window();
// Callback type to be called by the tray icon loop
typedef void(*main_loop_callback_function)(PVOID);
typedef void (*main_loop_callback_function)(PVOID);
// Calls a callback in _callback
bool dispatch_run_on_main_ui_thread(main_loop_callback_function _callback, PVOID data);

View file

@ -1,5 +1,5 @@
#include "pch.h"
#if _DEBUG && _WIN64
#if _DEBUG && _WIN64
#include "unhandled_exception_handler.h"
#include <DbgHelp.h>
#pragma comment(lib, "DbgHelp.lib")
@ -13,122 +13,158 @@ 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";
}
}
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) {
memset(p_symbol, '\0', sizeof(*p_symbol) + MAX_PATH);
memset(&module_path[0], '\0', sizeof(module_path));
line.LineNumber = 0;
CONTEXT context;
RtlCaptureContext(&context);
auto process = GetCurrentProcess();
auto thread = GetCurrentThread();
STACKFRAME64 stack;
memset(&stack, 0, sizeof(STACKFRAME64));
stack.AddrPC.Offset = context.Rip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.Rsp;
stack.AddrStack.Mode = AddrModeFlat;
stack.AddrFrame.Offset = context.Rbp;
stack.AddrFrame.Mode = AddrModeFlat;
std::wstringstream ss;
ss << generalErrorDescription << std::endl;
for (ULONG frame = 0;; frame++) {
auto result = StackWalk64(IMAGE_FILE_MACHINE_AMD64,
process,
thread,
&stack,
&context,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL);
p_symbol->MaxNameLength = MAX_PATH;
p_symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
DWORD64 dw64Displacement;
SymGetSymFromAddr64(process, stack.AddrPC.Offset, &dw64Displacement, p_symbol);
DWORD dwDisplacement;
SymGetLineFromAddr64(process, stack.AddrPC.Offset, &dwDisplacement, &line);
auto module_base = SymGetModuleBase64(process, stack.AddrPC.Offset);
if (module_base) {
GetModuleFileName((HINSTANCE)module_base, module_path, MAX_PATH);
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";
}
ss << module_path << "!"
<< p_symbol->Name
<< "(" << line.FileName << ":" << line.LineNumber << ")\n";
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) {
processing_exception = true;
try {
init_symbols();
std::wstring ex_description = L"Exception code not available";
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) {
default_top_level_exception_handler(info);
}
processing_exception = false;
}
return EXCEPTION_CONTINUE_SEARCH;
void init_symbols()
{
SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
auto process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
}
extern "C" void AbortHandler(int signal_number) {
init_symbols();
std::wstring ex_description = L"SIGABRT was raised.";
log_stack_trace(ex_description);
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;
CONTEXT context;
RtlCaptureContext(&context);
auto process = GetCurrentProcess();
auto thread = GetCurrentThread();
STACKFRAME64 stack;
memset(&stack, 0, sizeof(STACKFRAME64));
stack.AddrPC.Offset = context.Rip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.Rsp;
stack.AddrStack.Mode = AddrModeFlat;
stack.AddrFrame.Offset = context.Rbp;
stack.AddrFrame.Mode = AddrModeFlat;
std::wstringstream ss;
ss << generalErrorDescription << std::endl;
for (ULONG frame = 0;; frame++)
{
auto result = StackWalk64(IMAGE_FILE_MACHINE_AMD64,
process,
thread,
&stack,
&context,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL);
p_symbol->MaxNameLength = MAX_PATH;
p_symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
DWORD64 dw64Displacement;
SymGetSymFromAddr64(process, stack.AddrPC.Offset, &dw64Displacement, p_symbol);
DWORD dwDisplacement;
SymGetLineFromAddr64(process, stack.AddrPC.Offset, &dwDisplacement, &line);
auto module_base = SymGetModuleBase64(process, stack.AddrPC.Offset);
if (module_base)
{
GetModuleFileName((HINSTANCE)module_base, module_path, MAX_PATH);
}
ss << module_path << "!"
<< p_symbol->Name
<< "(" << line.FileName << ":" << line.LineNumber << ")\n";
if (!result)
{
break;
}
}
auto errorString = ss.str();
MessageBoxW(NULL, errorString.c_str(), L"Unhandled Error", MB_OK | MB_ICONERROR);
}
void init_global_error_handlers() {
default_top_level_exception_handler = SetUnhandledExceptionFilter(unhandled_exceptiont_handler);
signal(SIGABRT, &AbortHandler);
LONG WINAPI unhandled_exceptiont_handler(PEXCEPTION_POINTERS info)
{
if (!processing_exception)
{
processing_exception = true;
try
{
init_symbols();
std::wstring ex_description = L"Exception code not available";
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)
{
default_top_level_exception_handler(info);
}
processing_exception = false;
}
return EXCEPTION_CONTINUE_SEARCH;
}
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()
{
default_top_level_exception_handler = SetUnhandledExceptionFilter(unhandled_exceptiont_handler);
signal(SIGABRT, &AbortHandler);
}
#endif

View file

@ -1,4 +1,4 @@
#pragma once
#if _DEBUG && _WIN64
#if _DEBUG && _WIN64
void init_global_error_handlers();
#endif

View file

@ -17,66 +17,74 @@ static void CALLBACK win_hook_event_proc(HWINEVENTHOOK winEventHook,
LONG object,
LONG child,
DWORD eventThread,
DWORD eventTime) {
std::unique_lock lock(mutex);
hook_events.push_back({ event,
window,
object,
child,
eventThread,
eventTime });
lock.unlock();
dispatch_cv.notify_one();
DWORD eventTime)
{
std::unique_lock lock(mutex);
hook_events.push_back({ event,
window,
object,
child,
eventThread,
eventTime });
lock.unlock();
dispatch_cv.notify_one();
}
static bool running = false;
static std::thread dispatch_thread;
static void dispatch_thread_proc() {
std::unique_lock lock(mutex);
while (running) {
dispatch_cv.wait(lock, []{ return !running || !hook_events.empty(); });
if (!running)
return;
while (!hook_events.empty()) {
auto event = hook_events.front();
hook_events.pop_front();
lock.unlock();
intptr_t data = reinterpret_cast<intptr_t>(&event);
intercept_system_menu_action(data);
powertoys_events().signal_event(win_hook_event, data);
lock.lock();
static void dispatch_thread_proc()
{
std::unique_lock lock(mutex);
while (running)
{
dispatch_cv.wait(lock, [] { return !running || !hook_events.empty(); });
if (!running)
return;
while (!hook_events.empty())
{
auto event = hook_events.front();
hook_events.pop_front();
lock.unlock();
intptr_t data = reinterpret_cast<intptr_t>(&event);
intercept_system_menu_action(data);
powertoys_events().signal_event(win_hook_event, data);
lock.lock();
}
}
}
}
static HWINEVENTHOOK hook_handle;
void start_win_hook_event() {
std::lock_guard lock(mutex);
if (running)
return;
running = true;
dispatch_thread = std::thread(dispatch_thread_proc);
hook_handle = SetWinEventHook(EVENT_MIN, EVENT_MAX, nullptr, win_hook_event_proc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
void start_win_hook_event()
{
std::lock_guard lock(mutex);
if (running)
return;
running = true;
dispatch_thread = std::thread(dispatch_thread_proc);
hook_handle = SetWinEventHook(EVENT_MIN, EVENT_MAX, nullptr, win_hook_event_proc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
}
void stop_win_hook_event() {
std::unique_lock lock(mutex);
if (!running)
return;
running = false;
UnhookWinEvent(hook_handle);
lock.unlock();
dispatch_cv.notify_one();
dispatch_thread.join();
lock.lock();
hook_events.clear();
hook_events.shrink_to_fit();
void stop_win_hook_event()
{
std::unique_lock lock(mutex);
if (!running)
return;
running = false;
UnhookWinEvent(hook_handle);
lock.unlock();
dispatch_cv.notify_one();
dispatch_thread.join();
lock.lock();
hook_events.clear();
hook_events.shrink_to_fit();
}
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) {
powertoys_events().handle_system_menu_action(*evt);
}
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)
{
powertoys_events().handle_system_menu_action(*evt);
}
}

View file

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