Skip to content

Commit afc39e5

Browse files
yuyoyuppeudit3333
authored andcommitted
Runner: fix startup task state setting for MSIX (microsoft#1181)
1 parent 73254ed commit afc39e5

File tree

8 files changed

+147
-22
lines changed

8 files changed

+147
-22
lines changed

src/common/common.vcxproj

+2
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
<LanguageStandard>stdcpplatest</LanguageStandard>
6363
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
6464
<AdditionalIncludeDirectories>inc;telemetry;..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
65+
<AdditionalOptions>/await %(AdditionalOptions)</AdditionalOptions>
6566
</ClCompile>
6667
<Link>
6768
<SubSystem>Windows</SubSystem>
@@ -82,6 +83,7 @@
8283
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
8384
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
8485
<AdditionalIncludeDirectories>inc;telemetry;..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
86+
<AdditionalOptions>/await %(AdditionalOptions)</AdditionalOptions>
8587
</ClCompile>
8688
<Link>
8789
<SubSystem>Windows</SubSystem>

src/common/winstore.cpp

+65-4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,70 @@
33

44
#include <appmodel.h>
55

6-
bool running_as_packaged()
6+
#include <winrt/Windows.ApplicationModel.h>
7+
8+
using winrt::Windows::ApplicationModel::StartupTask;
9+
10+
namespace
11+
{
12+
const wchar_t* STARTUP_TASKID = L"PowerToysStartupTaskID";
13+
}
14+
15+
namespace winstore
716
{
8-
UINT32 length = 0;
9-
const auto rc = GetPackageFamilyName(GetCurrentProcess(), &length, nullptr);
10-
return rc != APPMODEL_ERROR_NO_PACKAGE;
17+
bool running_as_packaged()
18+
{
19+
UINT32 length = 0;
20+
const auto rc = GetPackageFamilyName(GetCurrentProcess(), &length, nullptr);
21+
return rc != APPMODEL_ERROR_NO_PACKAGE;
22+
}
23+
24+
std::future<StartupTaskState> get_startup_task_status_async()
25+
{
26+
const auto startupTask = co_await StartupTask::GetAsync(STARTUP_TASKID);
27+
co_return startupTask.State();
28+
}
29+
30+
std::future<void> switch_startup_task_state_async(const bool enabled)
31+
{
32+
const auto startupTask = co_await StartupTask::GetAsync(STARTUP_TASKID);
33+
enum class action
34+
{
35+
none,
36+
enable,
37+
disable,
38+
} action_to_try = action::none;
39+
switch (startupTask.State())
40+
{
41+
case StartupTaskState::Disabled:
42+
if (enabled)
43+
{
44+
action_to_try = action::enable;
45+
}
46+
break;
47+
case StartupTaskState::Enabled:
48+
if (!enabled)
49+
{
50+
action_to_try = action::disable;
51+
}
52+
break;
53+
}
54+
try
55+
{
56+
switch (action_to_try)
57+
{
58+
case action::enable:
59+
co_await startupTask.RequestEnableAsync();
60+
break;
61+
case action::disable:
62+
startupTask.Disable();
63+
break;
64+
}
65+
}
66+
catch (...)
67+
{
68+
// We can't handle the error, in case we don't have a permission to change startup task state
69+
}
70+
}
71+
1172
}

src/common/winstore.h

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
11
#pragma once
22

3-
bool running_as_packaged();
3+
#include <future>
4+
5+
#include <winrt/Windows.ApplicationModel.h>
6+
7+
8+
namespace winstore
9+
{
10+
using winrt::Windows::ApplicationModel::StartupTaskState;
11+
12+
bool running_as_packaged();
13+
std::future<void> switch_startup_task_state_async(const bool enabled);
14+
std::future<StartupTaskState> get_startup_task_status_async();
15+
}

src/runner/general_settings.cpp

+50-10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
static std::wstring settings_theme = L"system";
1212
static bool run_as_elevated = false;
1313

14+
// TODO: add resource.rc for settings project and localize
15+
namespace localized_strings
16+
{
17+
const std::wstring_view STARTUP_DISABLED_BY_POLICY = L"This setting has been disabled by your administrator.";
18+
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>.)";
19+
}
20+
1421
json::JsonObject load_general_settings()
1522
{
1623
auto loaded = PTSettingsHelper::load_general_settings();
@@ -27,10 +34,36 @@ json::JsonObject get_general_settings()
2734
{
2835
json::JsonObject result;
2936

30-
const bool packaged = running_as_packaged();
37+
const bool packaged = winstore::running_as_packaged();
3138
result.SetNamedValue(L"packaged", json::value(packaged));
3239

33-
const bool startup = is_auto_start_task_active_for_this_user();
40+
bool startup{};
41+
if (winstore::running_as_packaged())
42+
{
43+
using namespace localized_strings;
44+
const auto task_state = winstore::get_startup_task_status_async().get();
45+
switch (task_state)
46+
{
47+
case winstore::StartupTaskState::Disabled:
48+
startup = false;
49+
break;
50+
case winstore::StartupTaskState::Enabled:
51+
startup = true;
52+
break;
53+
case winstore::StartupTaskState::DisabledByPolicy:
54+
result.SetNamedValue(L"startup_disabled_reason", json::value(STARTUP_DISABLED_BY_POLICY));
55+
startup = false;
56+
break;
57+
case winstore::StartupTaskState::DisabledByUser:
58+
result.SetNamedValue(L"startup_disabled_reason", json::value(STARTUP_DISABLED_BY_USER));
59+
startup = false;
60+
break;
61+
}
62+
}
63+
else
64+
{
65+
startup = is_auto_start_task_active_for_this_user();
66+
}
3467
result.SetNamedValue(L"startup", json::value(startup));
3568

3669
json::JsonObject enabled;
@@ -54,16 +87,23 @@ void apply_general_settings(const json::JsonObject& general_configs)
5487
if (json::has(general_configs, L"startup", json::JsonValueType::Boolean))
5588
{
5689
const bool startup = general_configs.GetNamedBoolean(L"startup");
57-
const bool current_startup = is_auto_start_task_active_for_this_user();
58-
if (!running_as_packaged() && current_startup != startup)
90+
if (winstore::running_as_packaged())
5991
{
60-
if (startup)
61-
{
62-
enable_auto_start_task_for_this_user();
63-
}
64-
else
92+
winstore::switch_startup_task_state_async(startup).wait();
93+
}
94+
else
95+
{
96+
const bool current_startup = is_auto_start_task_active_for_this_user();
97+
if (current_startup != startup)
6598
{
66-
disable_auto_start_task_for_this_user();
99+
if (startup)
100+
{
101+
enable_auto_start_task_for_this_user();
102+
}
103+
else
104+
{
105+
disable_auto_start_task_for_this_user();
106+
}
67107
}
68108
}
69109
}

src/settings-web/src/components/BoolToggleSettingsControl.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export class BoolToggleSettingsControl extends BaseSettingsControl {
2424
public render(): JSX.Element {
2525
return (
2626
<Toggle
27+
disabled={this.props.disabled}
2728
onChange={
2829
(_event,_check) => {
2930
this.setState( (prev_state:any) => ({

src/settings-web/src/components/GeneralSettings.tsx

+8-4
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,18 @@ export class GeneralSettings extends React.Component <any, any> {
121121
}
122122
<Separator />
123123
<Text variant='xLarge'>General</Text>
124-
{!this.state.settings.general.packaged &&
125-
(
124+
<Stack>
125+
{this.state.settings.general.startup_disabled_reason != null &&
126+
<span style={{color:"#c50500"}} dangerouslySetInnerHTML={{__html: this.state.settings.general.startup_disabled_reason }} />
127+
}
128+
<Label>Run at Startup</Label>
126129
<BoolToggleSettingsControl
127-
setting={{display_name: 'Run at Startup', value: this.state.settings.general.startup}}
130+
disabled={this.state.settings.general.startup_disabled_reason}
131+
setting={{value: this.state.settings.general.startup}}
128132
on_change={this.parent_on_change}
129133
ref={(input) => {this.startup_reference=input;}}
130134
/>
131-
)}
135+
</Stack>
132136
<BoolToggleSettingsControl
133137
setting={{display_name: 'Always run as administrator', value: this.state.settings.general.run_elevated}}
134138
on_change={this.parent_on_change}

src/settings/main.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,13 @@ void initialize_webview(int nShowCmd)
243243

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

250255
g_webview.ContentLoading([=](IWebViewControl sender, WebViewControlContentLoadingEventArgs const& args) {

src/settings/settings-html/dist/bundle.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)