Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runner: fix startup task state setting for MSIX #1181

Merged
merged 4 commits into from
Jan 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/common/common.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
<LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>inc;telemetry;..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/await %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
Expand All @@ -82,6 +83,7 @@
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>inc;telemetry;..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/await %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
Expand Down
69 changes: 65 additions & 4 deletions src/common/winstore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,70 @@

#include <appmodel.h>

bool running_as_packaged()
#include <winrt/Windows.ApplicationModel.h>

using winrt::Windows::ApplicationModel::StartupTask;

namespace
{
const wchar_t* STARTUP_TASKID = L"PowerToysStartupTaskID";
}

namespace winstore
{
UINT32 length = 0;
const auto rc = GetPackageFamilyName(GetCurrentProcess(), &length, nullptr);
return rc != APPMODEL_ERROR_NO_PACKAGE;
bool running_as_packaged()
{
UINT32 length = 0;
const auto rc = GetPackageFamilyName(GetCurrentProcess(), &length, nullptr);
return rc != APPMODEL_ERROR_NO_PACKAGE;
}

std::future<StartupTaskState> get_startup_task_status_async()
{
const auto startupTask = co_await StartupTask::GetAsync(STARTUP_TASKID);
co_return startupTask.State();
}

std::future<void> switch_startup_task_state_async(const bool enabled)
{
const auto startupTask = co_await StartupTask::GetAsync(STARTUP_TASKID);
enum class action
{
none,
enable,
disable,
} action_to_try = action::none;
switch (startupTask.State())
{
case StartupTaskState::Disabled:
if (enabled)
{
action_to_try = action::enable;
}
break;
case StartupTaskState::Enabled:
if (!enabled)
{
action_to_try = action::disable;
}
break;
}
try
{
switch (action_to_try)
{
case action::enable:
co_await startupTask.RequestEnableAsync();
break;
case action::disable:
startupTask.Disable();
break;
}
}
catch (...)
{
// We can't handle the error, in case we don't have a permission to change startup task state
}
}

}
14 changes: 13 additions & 1 deletion src/common/winstore.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
#pragma once

bool running_as_packaged();
#include <future>

#include <winrt/Windows.ApplicationModel.h>


namespace winstore
{
using winrt::Windows::ApplicationModel::StartupTaskState;

bool running_as_packaged();
std::future<void> switch_startup_task_state_async(const bool enabled);
std::future<StartupTaskState> get_startup_task_status_async();
}
60 changes: 50 additions & 10 deletions src/runner/general_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@
static std::wstring settings_theme = L"system";
static bool run_as_elevated = false;

// TODO: add resource.rc for settings project and localize
namespace localized_strings
{
const std::wstring_view STARTUP_DISABLED_BY_POLICY = L"This setting has been disabled by your administrator.";
const std::wstring_view STARTUP_DISABLED_BY_USER = LR"(This setting has been disabled manually via <a href="https://ms_settings_startupapps" target="_blank">Startup Settings</a>.)";
}

json::JsonObject load_general_settings()
{
auto loaded = PTSettingsHelper::load_general_settings();
Expand All @@ -27,10 +34,36 @@ json::JsonObject get_general_settings()
{
json::JsonObject result;

const bool packaged = running_as_packaged();
const bool packaged = winstore::running_as_packaged();
result.SetNamedValue(L"packaged", json::value(packaged));

const bool startup = is_auto_start_task_active_for_this_user();
bool startup{};
if (winstore::running_as_packaged())
{
using namespace localized_strings;
const auto task_state = winstore::get_startup_task_status_async().get();
switch (task_state)
{
case winstore::StartupTaskState::Disabled:
startup = false;
break;
case winstore::StartupTaskState::Enabled:
startup = true;
break;
case winstore::StartupTaskState::DisabledByPolicy:
result.SetNamedValue(L"startup_disabled_reason", json::value(STARTUP_DISABLED_BY_POLICY));
startup = false;
break;
case winstore::StartupTaskState::DisabledByUser:
result.SetNamedValue(L"startup_disabled_reason", json::value(STARTUP_DISABLED_BY_USER));
startup = false;
break;
}
}
else
{
startup = is_auto_start_task_active_for_this_user();
}
result.SetNamedValue(L"startup", json::value(startup));

json::JsonObject enabled;
Expand All @@ -54,16 +87,23 @@ 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 (!running_as_packaged() && current_startup != startup)
if (winstore::running_as_packaged())
{
if (startup)
{
enable_auto_start_task_for_this_user();
}
else
winstore::switch_startup_task_state_async(startup).wait();
}
else
{
const bool current_startup = is_auto_start_task_active_for_this_user();
if (current_startup != startup)
{
disable_auto_start_task_for_this_user();
if (startup)
{
enable_auto_start_task_for_this_user();
}
else
{
disable_auto_start_task_for_this_user();
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export class BoolToggleSettingsControl extends BaseSettingsControl {
public render(): JSX.Element {
return (
<Toggle
disabled={this.props.disabled}
onChange={
(_event,_check) => {
this.setState( (prev_state:any) => ({
Expand Down
12 changes: 8 additions & 4 deletions src/settings-web/src/components/GeneralSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,18 @@ export class GeneralSettings extends React.Component <any, any> {
}
<Separator />
<Text variant='xLarge'>General</Text>
{!this.state.settings.general.packaged &&
(
<Stack>
{this.state.settings.general.startup_disabled_reason != null &&
<span style={{color:"#c50500"}} dangerouslySetInnerHTML={{__html: this.state.settings.general.startup_disabled_reason }} />
Copy link
Contributor Author

@yuyoyuppe yuyoyuppe Jan 31, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's nothing dangerous about this, since we supply the value of startup_disabled_reason ourselves (and not from the internet).

}
<Label>Run at Startup</Label>
<BoolToggleSettingsControl
setting={{display_name: 'Run at Startup', value: this.state.settings.general.startup}}
disabled={this.state.settings.general.startup_disabled_reason}
setting={{value: this.state.settings.general.startup}}
on_change={this.parent_on_change}
ref={(input) => {this.startup_reference=input;}}
/>
)}
</Stack>
<BoolToggleSettingsControl
setting={{display_name: 'Always run as administrator', value: this.state.settings.general.run_elevated}}
on_change={this.parent_on_change}
Expand Down
9 changes: 7 additions & 2 deletions src/settings/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,13 @@ void initialize_webview(int nShowCmd)

g_webview.NewWindowRequested([=](IWebViewControl sender_requester, WebViewControlNewWindowRequestedEventArgs args) {
// Open the requested link in the default browser registered in the Shell
int res = static_cast<int>(reinterpret_cast<uintptr_t>(ShellExecute(nullptr, L"open", args.Uri().AbsoluteUri().c_str(), nullptr, nullptr, SW_SHOWNORMAL)));
WINRT_VERIFY(res > 32);
using winrt::Windows::Foundation::Uri;
Uri uri = args.Uri();
// WebView doesn't let us to open ms-settings:protocol links directly, so we translate it
// from a https placeholder
if (uri.AbsoluteUri() == L"https://ms_settings_startupapps/")
uri = Uri{L"ms-settings:startupapps"};
winrt::Windows::System::Launcher::LaunchUriAsync(uri);
});

g_webview.ContentLoading([=](IWebViewControl sender, WebViewControlContentLoadingEventArgs const& args) {
Expand Down
2 changes: 1 addition & 1 deletion src/settings/settings-html/dist/bundle.js

Large diffs are not rendered by default.