feat: 优化实现开机启动

如果创建任务计划失败则回落到在启动文件夹中创建快捷方式
This commit is contained in:
刘旭 2022-08-06 20:55:37 +08:00
commit 1bcd208aef
4 changed files with 458 additions and 362 deletions

View file

@ -576,9 +576,9 @@ void AppSettings::IsAlwaysRunAsElevated(bool value) noexcept {
}
_isAlwaysRunAsElevated = value;
if (AutoStartHelper::IsAutoStartTaskActive()) {
if (AutoStartHelper::IsAutoStartEnabled()) {
// 更新启动任务
AutoStartHelper::CreateAutoStartTask(value);
AutoStartHelper::EnableAutoStart(value);
}
}

View file

@ -8,12 +8,18 @@
#pragma comment(lib, "Taskschd.lib")
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// 使用任务计划程序实现开机启动,优点是以管理员身份启动时不会显示 UAC
// 移植自 https://github.com/microsoft/PowerToys/blob/3d54cb838504c12f59516afaf1a00fde2dd5d01b/src/runner/auto_start_helper.cpp
// 实现开机启动
//
// 首先尝试使用任务计划程序,此方案的优点是以管理员身份启动时不会显示 UAC。
// 如果创建任务失败,则回落到在当前用户的启动文件夹中创建快捷方式。
//
// 任务计划程序的使用参考自
// https://github.com/microsoft/PowerToys/blob/3d54cb838504c12f59516afaf1a00fde2dd5d01b/src/runner/auto_start_helper.cpp
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace winrt::Magpie::App {
@ -23,363 +29,453 @@ static constexpr const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0'
static std::wstring GetTaskName(std::wstring_view userName) {
return StrUtils::ConcatW(L"Autorun for ", userName);
return StrUtils::ConcatW(L"Autorun for ", userName);
}
bool AutoStartHelper::CreateAutoStartTask(bool runElevated) {
WCHAR usernameDomain[USERNAME_DOMAIN_LEN];
WCHAR username[USERNAME_LEN];
static bool CreateAutoStartTask(bool runElevated) {
WCHAR usernameDomain[USERNAME_DOMAIN_LEN];
WCHAR username[USERNAME_LEN];
// ------------------------------------------------------
// Get the Domain/Username for the trigger.
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) {
Logger::Get().Win32Error("获取用户名失败");
return false;
}
if (!GetEnvironmentVariable(L"USERDOMAIN", usernameDomain, USERNAME_DOMAIN_LEN)) {
Logger::Get().Win32Error("获取用户域失败");
return false;
}
// ------------------------------------------------------
// Get the Domain/Username for the trigger.
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) {
Logger::Get().Win32Error("获取用户名失败");
return false;
}
if (!GetEnvironmentVariable(L"USERDOMAIN", usernameDomain, USERNAME_DOMAIN_LEN)) {
Logger::Get().Win32Error("获取用户域失败");
return false;
}
wcscat_s(usernameDomain, L"\\");
wcscat_s(usernameDomain, username);
wcscat_s(usernameDomain, L"\\");
wcscat_s(usernameDomain, username);
// ------------------------------------------------------
// Create an instance of the Task Service.
com_ptr<ITaskService> taskService;
HRESULT hr = CoCreateInstance(
CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&taskService)
);
if (FAILED(hr)) {
Logger::Get().ComError("创建 ITaskService 失败", hr);
return false;
}
// ------------------------------------------------------
// Create an instance of the Task Service.
com_ptr<ITaskService> taskService;
HRESULT hr = CoCreateInstance(
CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&taskService)
);
if (FAILED(hr)) {
Logger::Get().ComError("创建 ITaskService 失败", hr);
return false;
}
// Connect to the task service.
hr = taskService->Connect(Win32Utils::Variant(), Win32Utils::Variant(), Win32Utils::Variant(), Win32Utils::Variant());
if (FAILED(hr)) {
Logger::Get().ComError("ITaskService::Connect 失败", hr);
return false;
}
// Connect to the task service.
hr = taskService->Connect(Win32Utils::Variant(), Win32Utils::Variant(), Win32Utils::Variant(), Win32Utils::Variant());
if (FAILED(hr)) {
Logger::Get().ComError("ITaskService::Connect 失败", hr);
return false;
}
// ------------------------------------------------------
// Get the Magpie task folder. Creates it if it doesn't exist.
com_ptr<ITaskFolder> taskFolder;
hr = taskService->GetFolder(Win32Utils::BStr(L"\\Magpie"), taskFolder.put());
if (FAILED(hr)) {
// Folder doesn't exist. Get the Root folder and create the Magpie subfolder.
com_ptr<ITaskFolder> rootFolder = NULL;
hr = taskService->GetFolder(Win32Utils::BStr(L"\\"), rootFolder.put());
if (FAILED(hr)) {
Logger::Get().ComError("获取根目录失败", hr);
return false;
}
hr = rootFolder->CreateFolder(Win32Utils::BStr(L"\\Magpie"), Win32Utils::Variant(L""), taskFolder.put());
if (FAILED(hr)) {
Logger::Get().ComError("创建 Magpie 任务文件夹失败", hr);
return false;
}
}
// ------------------------------------------------------
// Get the Magpie task folder. Creates it if it doesn't exist.
com_ptr<ITaskFolder> taskFolder;
hr = taskService->GetFolder(Win32Utils::BStr(L"\\Magpie"), taskFolder.put());
if (FAILED(hr)) {
// Folder doesn't exist. Get the Root folder and create the Magpie subfolder.
com_ptr<ITaskFolder> rootFolder = NULL;
hr = taskService->GetFolder(Win32Utils::BStr(L"\\"), rootFolder.put());
if (FAILED(hr)) {
Logger::Get().ComError("获取根目录失败", hr);
return false;
}
// Create the task builder object to create the task.
com_ptr<ITaskDefinition> task;
hr = taskService->NewTask(0, task.put());
if (FAILED(hr)) {
Logger::Get().ComError("创建 ITaskDefinition 失败", hr);
return false;
}
hr = rootFolder->CreateFolder(Win32Utils::BStr(L"\\Magpie"), Win32Utils::Variant(L""), taskFolder.put());
if (FAILED(hr)) {
Logger::Get().ComError("创建 Magpie 任务文件夹失败", hr);
return false;
}
}
// ------------------------------------------------------
// Get the registration info for setting the identification.
com_ptr<IRegistrationInfo> regInfo;
hr = task->get_RegistrationInfo(regInfo.put());
if (FAILED(hr)) {
Logger::Get().ComError("获取 IRegistrationInfo 失败", hr);
return false;
}
hr = regInfo->put_Author(Win32Utils::BStr(usernameDomain));
if (FAILED(hr)) {
Logger::Get().ComError("IRegistrationInfo::put_Author 失败", hr);
return false;
}
// Create the task builder object to create the task.
com_ptr<ITaskDefinition> task;
hr = taskService->NewTask(0, task.put());
if (FAILED(hr)) {
Logger::Get().ComError("创建 ITaskDefinition 失败", hr);
return false;
}
// ------------------------------------------------------
// Create the settings for the task
com_ptr<ITaskSettings> taskSettings;
hr = task->get_Settings(taskSettings.put());
if (FAILED(hr)) {
Logger::Get().ComError("获取 ITaskSettings 失败", hr);
return false;
}
// ------------------------------------------------------
// Get the registration info for setting the identification.
com_ptr<IRegistrationInfo> regInfo;
hr = task->get_RegistrationInfo(regInfo.put());
if (FAILED(hr)) {
Logger::Get().ComError("获取 IRegistrationInfo 失败", hr);
return false;
}
hr = taskSettings->put_StartWhenAvailable(VARIANT_FALSE);
if (FAILED(hr)) {
Logger::Get().ComError("ITaskSettings::put_StartWhenAvailable 失败", hr);
return false;
}
hr = taskSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE);
if (FAILED(hr)) {
Logger::Get().ComError("ITaskSettings::put_StopIfGoingOnBatteries 失败", hr);
return false;
}
hr = taskSettings->put_ExecutionTimeLimit(Win32Utils::BStr(L"PT0S")); //Unlimited
if (FAILED(hr)) {
Logger::Get().ComError("ITaskSettings::put_ExecutionTimeLimit 失败", hr);
return false;
}
hr = taskSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE);
if (FAILED(hr)) {
Logger::Get().ComError("ITaskSettings::put_DisallowStartIfOnBatteries 失败", hr);
return false;
}
hr = regInfo->put_Author(Win32Utils::BStr(usernameDomain));
if (FAILED(hr)) {
Logger::Get().ComError("IRegistrationInfo::put_Author 失败", hr);
return false;
}
// ------------------------------------------------------
// Get the trigger collection to insert the logon trigger.
com_ptr<ITriggerCollection> triggerCollection;
hr = task->get_Triggers(triggerCollection.put());
if (FAILED(hr)) {
Logger::Get().ComError("获取 ITriggerCollection 失败", hr);
return false;
}
// Add the logon trigger to the task.
{
com_ptr<ITrigger> trigger;
hr = triggerCollection->Create(TASK_TRIGGER_LOGON, trigger.put());
if (FAILED(hr)) {
Logger::Get().ComError("创建 ITrigger 失败", hr);
return false;
}
// ------------------------------------------------------
// Create the settings for the task
com_ptr<ITaskSettings> taskSettings;
hr = task->get_Settings(taskSettings.put());
if (FAILED(hr)) {
Logger::Get().ComError("获取 ITaskSettings 失败", hr);
return false;
}
com_ptr<ILogonTrigger> logonTrigger = trigger.try_as<ILogonTrigger>();
if (!logonTrigger) {
Logger::Get().Error("获取 ILogonTrigger 失败");
return false;
}
hr = taskSettings->put_StartWhenAvailable(VARIANT_FALSE);
if (FAILED(hr)) {
Logger::Get().ComError("ITaskSettings::put_StartWhenAvailable 失败", hr);
return false;
}
hr = taskSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE);
if (FAILED(hr)) {
Logger::Get().ComError("ITaskSettings::put_StopIfGoingOnBatteries 失败", hr);
return false;
}
hr = taskSettings->put_ExecutionTimeLimit(Win32Utils::BStr(L"PT0S")); //Unlimited
if (FAILED(hr)) {
Logger::Get().ComError("ITaskSettings::put_ExecutionTimeLimit 失败", hr);
return false;
}
hr = taskSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE);
if (FAILED(hr)) {
Logger::Get().ComError("ITaskSettings::put_DisallowStartIfOnBatteries 失败", hr);
return false;
}
logonTrigger->put_Id(Win32Utils::BStr(L"Trigger1"));
// ------------------------------------------------------
// Get the trigger collection to insert the logon trigger.
com_ptr<ITriggerCollection> triggerCollection;
hr = task->get_Triggers(triggerCollection.put());
if (FAILED(hr)) {
Logger::Get().ComError("获取 ITriggerCollection 失败", hr);
return false;
}
// Timing issues may make explorer not be started when the task runs.
// Add a little delay to mitigate this.
logonTrigger->put_Delay(Win32Utils::BStr(L"PT03S"));
// Add the logon trigger to the task.
{
com_ptr<ITrigger> trigger;
hr = triggerCollection->Create(TASK_TRIGGER_LOGON, trigger.put());
if (FAILED(hr)) {
Logger::Get().ComError("创建 ITrigger 失败", hr);
return false;
}
// Define the user. The task will execute when the user logs on.
// The specified user must be a user on this computer.
hr = logonTrigger->put_UserId(Win32Utils::BStr(usernameDomain));
if (FAILED(hr)) {
Logger::Get().ComError("ILogonTrigger::put_UserId 失败", hr);
return false;
}
}
com_ptr<ILogonTrigger> logonTrigger = trigger.try_as<ILogonTrigger>();
if (!logonTrigger) {
Logger::Get().Error("获取 ILogonTrigger 失败");
return false;
}
// ------------------------------------------------------
// Add an Action to the task. This task will execute the path passed to this custom action.
{
com_ptr<IActionCollection> actionCollection;
logonTrigger->put_Id(Win32Utils::BStr(L"Trigger1"));
// Get the task action collection pointer.
hr = task->get_Actions(actionCollection.put());
if (FAILED(hr)) {
Logger::Get().ComError("获取 IActionCollection 失败", hr);
return false;
}
// Timing issues may make explorer not be started when the task runs.
// Add a little delay to mitigate this.
logonTrigger->put_Delay(Win32Utils::BStr(L"PT03S"));
// Create the action, specifying that it is an executable action.
com_ptr<IAction> action;
hr = actionCollection->Create(TASK_ACTION_EXEC, action.put());
if (FAILED(hr)) {
Logger::Get().ComError("创建 IAction 失败", hr);
return false;
}
// Define the user. The task will execute when the user logs on.
// The specified user must be a user on this computer.
hr = logonTrigger->put_UserId(Win32Utils::BStr(usernameDomain));
if (FAILED(hr)) {
Logger::Get().ComError("ILogonTrigger::put_UserId 失败", hr);
return false;
}
}
// QI for the executable task pointer.
com_ptr<IExecAction> execAction = action.try_as<IExecAction>();
if (!execAction) {
Logger::Get().Error("获取 IExecAction 失败");
return false;
}
// ------------------------------------------------------
// Add an Action to the task. This task will execute the path passed to this custom action.
{
com_ptr<IActionCollection> actionCollection;
// Set the path of the executable to Magpie (passed as CustomActionData).
WCHAR executablePath[MAX_PATH];
GetModuleFileName(NULL, executablePath, MAX_PATH);
hr = execAction->put_Path(Win32Utils::BStr(executablePath));
if (FAILED(hr)) {
Logger::Get().ComError("设置可执行文件路径失败", hr);
return false;
}
}
// Get the task action collection pointer.
hr = task->get_Actions(actionCollection.put());
if (FAILED(hr)) {
Logger::Get().ComError("获取 IActionCollection 失败", hr);
return false;
}
// ------------------------------------------------------
// Create the principal for the task
{
com_ptr<IPrincipal> principal;
hr = task->get_Principal(principal.put());
if (FAILED(hr)) {
Logger::Get().ComError("获取 IPrincipal 失败", hr);
return false;
}
// Create the action, specifying that it is an executable action.
com_ptr<IAction> action;
hr = actionCollection->Create(TASK_ACTION_EXEC, action.put());
if (FAILED(hr)) {
Logger::Get().ComError("创建 IAction 失败", hr);
return false;
}
// Set up principal information:
principal->put_Id(Win32Utils::BStr(L"Principal1"));
principal->put_UserId(Win32Utils::BStr(usernameDomain));
principal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN);
// QI for the executable task pointer.
com_ptr<IExecAction> execAction = action.try_as<IExecAction>();
if (!execAction) {
Logger::Get().Error("获取 IExecAction 失败");
return false;
}
if (runElevated) {
hr = principal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_HIGHEST);
} else {
hr = principal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_LUA);
}
if (FAILED(hr)) {
Logger::Get().ComError("IPrincipal::put_RunLevel 失败", hr);
return false;
}
}
// Set the path of the executable to Magpie (passed as CustomActionData).
WCHAR executablePath[MAX_PATH];
GetModuleFileName(NULL, executablePath, MAX_PATH);
hr = execAction->put_Path(Win32Utils::BStr(executablePath));
if (FAILED(hr)) {
Logger::Get().ComError("设置可执行文件路径失败", hr);
return false;
}
}
// ------------------------------------------------------
// Save the task in the Magpie folder.
{
com_ptr<IRegisteredTask> registeredTask;
static constexpr const wchar_t* SDDL_FULL_ACCESS_FOR_EVERYONE = L"D:(A;;FA;;;WD)";
// ------------------------------------------------------
// Create the principal for the task
{
com_ptr<IPrincipal> principal;
hr = task->get_Principal(principal.put());
if (FAILED(hr)) {
Logger::Get().ComError("获取 IPrincipal 失败", hr);
return false;
}
// 如果不是管理员身份某些情况下会因权限问题失败
hr = taskFolder->RegisterTaskDefinition(
Win32Utils::BStr(GetTaskName(username)),
task.get(),
TASK_CREATE_OR_UPDATE,
Win32Utils::Variant(usernameDomain),
Win32Utils::Variant(),
TASK_LOGON_INTERACTIVE_TOKEN,
Win32Utils::Variant(SDDL_FULL_ACCESS_FOR_EVERYONE),
registeredTask.put()
);
if (FAILED(hr)) {
Logger::Get().ComError("注册任务失败", hr);
return false;
}
// Set up principal information:
principal->put_Id(Win32Utils::BStr(L"Principal1"));
principal->put_UserId(Win32Utils::BStr(usernameDomain));
principal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN);
registeredTask->put_Enabled(VARIANT_TRUE);
}
if (runElevated) {
hr = principal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_HIGHEST);
} else {
hr = principal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_LUA);
}
return true;
if (FAILED(hr)) {
Logger::Get().ComError("IPrincipal::put_RunLevel 失败", hr);
return false;
}
}
// ------------------------------------------------------
// Save the task in the Magpie folder.
{
com_ptr<IRegisteredTask> registeredTask;
static constexpr const wchar_t* SDDL_FULL_ACCESS_FOR_EVERYONE = L"D:(A;;FA;;;WD)";
// 如果用户是 Administrator 账户,但 Magpie 不是以提升权限运行的,此调用会因权限问题失败
std::wstring taskName = GetTaskName(username);
hr = taskFolder->RegisterTaskDefinition(
Win32Utils::BStr(taskName),
task.get(),
TASK_CREATE_OR_UPDATE,
Win32Utils::Variant(usernameDomain),
Win32Utils::Variant(),
TASK_LOGON_INTERACTIVE_TOKEN,
Win32Utils::Variant(SDDL_FULL_ACCESS_FOR_EVERYONE),
registeredTask.put()
);
if (FAILED(hr)) {
Logger::Get().ComError("注册任务失败", hr);
return false;
}
registeredTask->put_Enabled(VARIANT_TRUE);
}
return true;
}
bool AutoStartHelper::DeleteAutoStartTask() {
// ------------------------------------------------------
// Get the Username for the task.
WCHAR username[USERNAME_LEN];
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) {
Logger::Get().Win32Error("获取用户名失败");
return false;
}
static bool DeleteAutoStartTask() {
// ------------------------------------------------------
// Get the Username for the task.
WCHAR username[USERNAME_LEN];
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) {
Logger::Get().Win32Error("获取用户名失败");
return false;
}
// ------------------------------------------------------
// Create an instance of the Task Service.
com_ptr<ITaskService> taskService;
HRESULT hr = CoCreateInstance(
CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&taskService)
);
if (FAILED(hr)) {
Logger::Get().ComError("创建 ITaskService 失败", hr);
return false;
}
// ------------------------------------------------------
// Create an instance of the Task Service.
com_ptr<ITaskService> taskService;
HRESULT hr = CoCreateInstance(
CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&taskService)
);
if (FAILED(hr)) {
Logger::Get().ComError("创建 ITaskService 失败", hr);
return false;
}
// Connect to the task service.
hr = taskService->Connect(Win32Utils::Variant(), Win32Utils::Variant(), Win32Utils::Variant(), Win32Utils::Variant());
if (FAILED(hr)) {
Logger::Get().ComError("ITaskService::Connect 失败", hr);
return false;
}
// Connect to the task service.
hr = taskService->Connect(Win32Utils::Variant(), Win32Utils::Variant(), Win32Utils::Variant(), Win32Utils::Variant());
if (FAILED(hr)) {
Logger::Get().ComError("ITaskService::Connect 失败", hr);
return false;
}
// ------------------------------------------------------
// Get the Magpie task folder.
com_ptr<ITaskFolder> taskFolder;
hr = taskService->GetFolder(Win32Utils::BStr(L"\\Magpie"), taskFolder.put());
if (FAILED(hr)) {
return true;
}
// ------------------------------------------------------
// Get the Magpie task folder.
com_ptr<ITaskFolder> taskFolder;
hr = taskService->GetFolder(Win32Utils::BStr(L"\\Magpie"), taskFolder.put());
if (FAILED(hr)) {
return true;
}
Win32Utils::BStr taskName(GetTaskName(username));
Win32Utils::BStr taskName(GetTaskName(username));
{
com_ptr<IRegisteredTask> existingRegisteredTask;
hr = taskFolder->GetTask(taskName, existingRegisteredTask.put());
if (FAILED(hr)) {
return true;
}
}
{
com_ptr<IRegisteredTask> existingRegisteredTask;
hr = taskFolder->GetTask(taskName, existingRegisteredTask.put());
if (FAILED(hr)) {
return true;
}
}
// Task exists, try disabling it.
hr = taskFolder->DeleteTask(taskName, 0);
if (FAILED(hr)) {
Logger::Get().ComError("删除任务失败", hr);
return false;
}
// Task exists, try disabling it.
hr = taskFolder->DeleteTask(taskName, 0);
if (FAILED(hr)) {
Logger::Get().ComError("删除任务失败", hr);
return false;
}
return true;
return true;
}
bool AutoStartHelper::IsAutoStartTaskActive() {
// ------------------------------------------------------
// Get the Username for the task.
WCHAR username[USERNAME_LEN];
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) {
Logger::Get().Win32Error("获取用户名失败");
return false;
}
static bool IsAutoStartTaskActive() {
// ------------------------------------------------------
// Get the Username for the task.
WCHAR username[USERNAME_LEN];
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) {
Logger::Get().Win32Error("获取用户名失败");
return false;
}
// ------------------------------------------------------
// Create an instance of the Task Service.
com_ptr<ITaskService> taskService;
HRESULT hr = CoCreateInstance(
CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&taskService)
);
if (FAILED(hr)) {
Logger::Get().ComError("创建 ITaskService 失败", hr);
return false;
}
// ------------------------------------------------------
// Create an instance of the Task Service.
com_ptr<ITaskService> taskService;
HRESULT hr = CoCreateInstance(
CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&taskService)
);
if (FAILED(hr)) {
Logger::Get().ComError("创建 ITaskService 失败", hr);
return false;
}
// Connect to the task service.
hr = taskService->Connect(Win32Utils::Variant(), Win32Utils::Variant(), Win32Utils::Variant(), Win32Utils::Variant());
if (FAILED(hr)) {
Logger::Get().ComError("ITaskService::Connect 失败", hr);
return false;
}
// Connect to the task service.
hr = taskService->Connect(Win32Utils::Variant(), Win32Utils::Variant(), Win32Utils::Variant(), Win32Utils::Variant());
if (FAILED(hr)) {
Logger::Get().ComError("ITaskService::Connect 失败", hr);
return false;
}
// ------------------------------------------------------
// Get the Magpie task folder.
com_ptr<ITaskFolder> taskFolder;
hr = taskService->GetFolder(Win32Utils::BStr(L"\\Magpie"), taskFolder.put());
if (FAILED(hr)) {
return false;
}
// ------------------------------------------------------
// Get the Magpie task folder.
com_ptr<ITaskFolder> taskFolder;
hr = taskService->GetFolder(Win32Utils::BStr(L"\\Magpie"), taskFolder.put());
if (FAILED(hr)) {
return false;
}
com_ptr<IRegisteredTask> existingRegisteredTask;
hr = taskFolder->GetTask(Win32Utils::BStr(GetTaskName(username)), existingRegisteredTask.put());
if (FAILED(hr)) {
return false;
}
com_ptr<IRegisteredTask> existingRegisteredTask;
hr = taskFolder->GetTask(Win32Utils::BStr(GetTaskName(username)), existingRegisteredTask.put());
if (FAILED(hr)) {
return false;
}
// Task exists, get its value.
VARIANT_BOOL isEnabled;
hr = existingRegisteredTask->get_Enabled(&isEnabled);
if (FAILED(hr)) {
return false;
}
// Task exists, get its value.
VARIANT_BOOL isEnabled;
hr = existingRegisteredTask->get_Enabled(&isEnabled);
if (FAILED(hr)) {
return false;
}
return isEnabled == VARIANT_TRUE;
return isEnabled == VARIANT_TRUE;
}
static std::wstring GetShortcutPath() {
std::wstring shortcutPath;
// 获取用户的启动文件夹路径
wchar_t* startupDir = nullptr;
HRESULT hr = SHGetKnownFolderPath(FOLDERID_Startup, 0, NULL, &startupDir);
if (FAILED(hr)) {
CoTaskMemFree(startupDir);
Logger::Get().ComError("获取启动文件夹失败", hr);
return {};
}
shortcutPath = StrUtils::ConcatW(startupDir, L"\\Magpie.lnk");
CoTaskMemFree(startupDir);
return shortcutPath;
}
static bool CreateAutoStartShortcut() {
com_ptr<IShellLink> shellLink;
HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shellLink));
if (FAILED(hr)) {
Logger::Get().ComError("创建 IShellLink 失败", hr);
return false;
}
WCHAR executablePath[MAX_PATH];
GetModuleFileName(NULL, executablePath, MAX_PATH);
shellLink->SetPath(executablePath);
com_ptr<IPersistFile> persistFile = shellLink.try_as<IPersistFile>();
if (!persistFile) {
Logger::Get().Error("获取 IPersistFile 失败");
return false;
}
hr = persistFile->Save(GetShortcutPath().c_str(), TRUE);
if (FAILED(hr)) {
Logger::Get().ComError("保存快捷方式失败", hr);
return false;
}
return true;
}
static bool DeleteAutoStartShortcut() {
std::wstring shortcutPath = GetShortcutPath();
if (shortcutPath.empty()) {
return false;
}
if (!Win32Utils::FileExists(shortcutPath.c_str())) {
return true;
}
if (!DeleteFile(shortcutPath.c_str())) {
Logger::Get().Win32Error("删除快捷方式失败");
return false;
}
return true;
}
static bool IsAutoStartShortcutExist() {
std::wstring shortcutPath = GetShortcutPath();
if (shortcutPath.empty()) {
return false;
}
return Win32Utils::FileExists(shortcutPath.c_str());
}
bool AutoStartHelper::EnableAutoStart(bool runElevated) {
if (CreateAutoStartTask(runElevated)) {
return true;
}
return CreateAutoStartShortcut();
}
bool AutoStartHelper::DisableAutoStart() {
bool result1 = DeleteAutoStartTask();
bool result2 = DeleteAutoStartShortcut();
return result1 || result2;
}
bool AutoStartHelper::IsAutoStartEnabled() {
return IsAutoStartTaskActive() || IsAutoStartShortcutExist();
}
}

View file

@ -3,11 +3,11 @@
namespace winrt::Magpie::App {
struct AutoStartHelper {
static bool CreateAutoStartTask(bool runElevated);
static bool EnableAutoStart(bool runElevated);
static bool DeleteAutoStartTask();
static bool DisableAutoStart();
static bool IsAutoStartTaskActive();
static bool IsAutoStartEnabled();
};
}

View file

@ -31,14 +31,14 @@ void SettingsViewModel::Theme(int32_t value) noexcept {
}
bool SettingsViewModel::IsRunAtStartup() const noexcept {
return AutoStartHelper::IsAutoStartTaskActive();
return AutoStartHelper::IsAutoStartEnabled();
}
void SettingsViewModel::IsRunAtStartup(bool value) noexcept {
if (value) {
AutoStartHelper::CreateAutoStartTask(AppSettings::Get().IsAlwaysRunAsElevated());
AutoStartHelper::EnableAutoStart(AppSettings::Get().IsAlwaysRunAsElevated());
} else {
AutoStartHelper::DeleteAutoStartTask();
AutoStartHelper::DisableAutoStart();
}
_propertyChangedEvent(*this, PropertyChangedEventArgs(L"IsRunAtStartup"));