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

Launch elevated instances via shell:AppFolder #14637

Merged
9 commits merged into from
Jan 19, 2023

Conversation

jboelter
Copy link
Contributor

@jboelter jboelter commented Jan 5, 2023

This uses shell:AppsFolder to launch elevated instances of the app via
ShellExecuteEx and runas in elevate-shim.exe. The app to launch is
discovered via the GetCurrentApplicationUserModelId API.

e.g. shell:AppsFolder\WindowsTerminalDev_8wekyb3d8bbwe!App

This will fallback to launching WindowsTerminal.exe if it fails to
discover the app user model id to launch.

This also fixes a bug in elevate-shim where the first argument of
WinMain was lost (e.g. new-tab).

Curiously, AppLogic::RunAsUwp() is never called and
AppLogic::IsUwp() is always false when running debug builds locally
(e.g. WindowsTerminalDev). It's not clear if this is an artifact of
development packages or something else.

Validation Steps Performed

Various manual debug/execution scenarios.

Verified the fallback path by running the unbundled app by extracting
the CascadiaPackage_0.0.1.0_x64.msix from the 'drop' build artifact.

Fixes #14501

Fixes microsoft#14501

This uses `shell:AppsFolder` to launch elevated instances of the app via
`ShellExecuteEx` and `runas` in elevate-shim.exe. The app to launch is
discovered via the `GetCurrentApplicationUserModelId` API.

e.g. `shell:AppsFolder\WindowsTerminalDev_8wekyb3d8bbwe!App`

This will fallback to launching `WindowsTerminal.exe` if it fails to
discover the app user model id to launch.

This also fixes an innocuous bug in elevate-shim where the first
argument of WinMain was lost (e.g. `new-tab`).
@ghost ghost added Issue-Bug It either shouldn't be doing this or needs an investigation. Product-Terminal The new Windows Terminal. labels Jan 5, 2023
@jboelter
Copy link
Contributor Author

jboelter commented Jan 5, 2023

@microsoft-github-policy-service agree

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@jboelter
Copy link
Contributor Author

jboelter commented Jan 6, 2023

I'm not particularly attached to the specifics of the implementation; it was an iterative process to get here.

There may be a potential for (un)escaping issues in the command line conversion when it removes (replace w/ empty string) shell:AppsFolder... from the cmdline args. i.e. arg0 from __wargv is not the same as what is found in the full cmd line string.

This is also assuming the string returned from GetCurrentApplicationUserModelId doesn't have spaces in it.

edit: change was moved to elevate-shim; no need to parse the cmdline

It also wasn't clear if terminal is always an AppX package, in which case the fallback to invoking WindowsTerminal.exe isn't necessary.

Reverts the changes to AppLogic.*
Minimizes scope of changes to TerminalPage and elevate-shim
Use WIL for logging and win32 api interaction
@github-actions

This comment has been minimized.

@zadjii-msft zadjii-msft added this to the Terminal v1.17 milestone Jan 10, 2023
@jboelter
Copy link
Contributor Author

jboelter commented Jan 11, 2023

@zadjii-msft

Just had an idea while working on something entirely unrelated. Turns out that elevate-shim.exe can successfully call GetCurrentApplicationUserModelId. This means this change can be isolated to the shim and not have to deal with any command line argument parsing. It significantly simplifies the change to only a decision on how it generates the cmd to pass to shell execute.

seInfo.lpFile = module.c_str(); // This is `...\WindowsTerminal.exe`
seInfo.lpParameters = pCmdLine; // This is `new-tab -p {guid}`
seInfo.lpFile = cmd.c_str(); // This is `shell:AppsFolder\...` or `...\WindowsTerminal.exe`
seInfo.lpParameters = GetCommandLine(); // This is `new-tab -p {guid}`
Copy link
Member

Choose a reason for hiding this comment

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

Why not use the previous pCmdLine?

Copy link
Contributor Author

@jboelter jboelter Jan 18, 2023

Choose a reason for hiding this comment

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

I found an innocuous bug in how the first parameter, new-tab, was dropped when passed to elevate-shim.exe by wWinMain given how it's launched by CreateProcess. It appears wWinMain is assuming param zero is the executable path even if it's not.

However, the elevate-shim process is launched with a command line that doesn't include the executable path.

auto cmdline{
fmt::format(L"new-tab {}", newTerminalArgs.ToCommandline().c_str())
};
wil::unique_process_information pi;
STARTUPINFOW si{};
si.cb = sizeof(si);
LOG_IF_WIN32_BOOL_FALSE(CreateProcessW(exePath.c_str(),
cmdline.data(),
nullptr,
nullptr,
FALSE,
0,
nullptr,
nullptr,
&si,
&pi));


This is the !peb from elevate-shim.exe when launched from a dev build of terminal as an appx (I setup Windbg Preview as the post-mortem debugger and put a DebugBreak() at the top of elevate-shim to break in easily). Notice the CommandLine is missing the executable filepath as the first argument. You can also see this in Process Monitor.

    CurrentDirectory:  'C:\windows\system32\'
    WindowTitle:  'C:\source\github.com.jboelter.terminal\src\cascadia\CascadiaPackage\bin\x64\Debug\AppX\elevate-shim.exe'
    ImageFile:    'C:\source\github.com.jboelter.terminal\src\cascadia\CascadiaPackage\bin\x64\Debug\AppX\elevate-shim.exe'
    CommandLine:  '  new-tab --profile "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}"'
    DllPath:      'C:\source\github.com.jboelter.terminal\src\cascadia\CascadiaPackage\bin\x64\Debug\AppX;C:\Program Files\WindowsApps\Microsoft.VCLibs.140.00.Debug.UWPDesktop_14.0.30704.0_x64__8wekyb3d8bbwe;'

Copy link
Member

Choose a reason for hiding this comment

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

Yeeeeeeeep that's totally on me. We probably could fix that down in TerminalPage.cpp, but 🤷

@KalleOlaviNiemitalo
Copy link

Is shell:AppsFolder documented as an API? It's described in Find the Application User Model ID of an installed app for interactive use though, and there is FOLDERID_AppsFolder in KNOWNFOLDERID.

Copy link
Member

@zadjii-msft zadjii-msft left a comment

Choose a reason for hiding this comment

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

Every day I'm amazed and horrified. Let's give this a shot for 1.17. Somehow I have a feeling that this is going to be way more reliable, based on the fact that it's 500% crazier than what we had before 😆

Copy link
Member

@DHowett DHowett left a comment

Choose a reason for hiding this comment

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

Thanks so much for doing this. It's clever and thoughtfully-implemented 😄

@DHowett DHowett added the AutoMerge Marked for automatic merge by the bot when requirements are met label Jan 19, 2023
@ghost
Copy link

ghost commented Jan 19, 2023

Hello @DHowett!

Because this pull request has the AutoMerge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

@ghost ghost merged commit eab1c23 into microsoft:main Jan 19, 2023
@DHowett
Copy link
Member

DHowett commented Jan 19, 2023

Is shell:AppsFolder documented as an API? It's described in Find the Application User Model ID of an installed app for interactive use though, and there is FOLDERID_AppsFolder in KNOWNFOLDERID.

I know now (thanks to jboelter!) that PowerToys uses it, but I don't know whether it's been publicly documented. That's something we should definitely pursue. Thank you :)

@ghost
Copy link

ghost commented Jan 24, 2023

🎉Windows Terminal Preview v1.17.1023 has been released which incorporates this pull request.:tada:

Handy links:

carlos-zamora pushed a commit that referenced this pull request Jan 25, 2023
This uses `shell:AppsFolder` to launch elevated instances of the app via
`ShellExecuteEx` and `runas` in elevate-shim.exe. The app to launch is
discovered via the `GetCurrentApplicationUserModelId` API.

e.g. `shell:AppsFolder\WindowsTerminalDev_8wekyb3d8bbwe!App`

This will fallback to launching `WindowsTerminal.exe` if it fails to
discover the app user model id to launch.

This also fixes a bug in elevate-shim where the first argument of
WinMain was lost (e.g. `new-tab`). 

Curiously, `AppLogic::RunAsUwp()` is never called and
`AppLogic::IsUwp()` is always false when running debug builds locally
(e.g. WindowsTerminalDev). It's not clear if this is an artifact of
development packages or something else.

## Validation Steps Performed

Various manual debug/execution scenarios.

Verified the fallback path by running the unbundled app by extracting
the `CascadiaPackage_0.0.1.0_x64.msix` from the 'drop' build artifact.

Fixes #14501
DHowett pushed a commit that referenced this pull request Jan 27, 2023
This uses `shell:AppsFolder` to launch elevated instances of the app via
`ShellExecuteEx` and `runas` in elevate-shim.exe. The app to launch is
discovered via the `GetCurrentApplicationUserModelId` API.

e.g. `shell:AppsFolder\WindowsTerminalDev_8wekyb3d8bbwe!App`

This will fallback to launching `WindowsTerminal.exe` if it fails to
discover the app user model id to launch.

This also fixes a bug in elevate-shim where the first argument of
WinMain was lost (e.g. `new-tab`).

Curiously, `AppLogic::RunAsUwp()` is never called and
`AppLogic::IsUwp()` is always false when running debug builds locally
(e.g. WindowsTerminalDev). It's not clear if this is an artifact of
development packages or something else.

## Validation Steps Performed

Various manual debug/execution scenarios.

Verified the fallback path by running the unbundled app by extracting
the `CascadiaPackage_0.0.1.0_x64.msix` from the 'drop' build artifact.

Fixes #14501

(cherry picked from commit eab1c23)
Service-Card-Id: 87690177
Service-Version: 1.16
@ghost
Copy link

ghost commented Jan 27, 2023

🎉Windows Terminal v1.16.1026 (1.16.10261.0 and 1.16.10262.0) has been released which incorporates this pull request.:tada:

Handy links:

1 similar comment
@ghost
Copy link

ghost commented Jan 27, 2023

🎉Windows Terminal v1.16.1026 (1.16.10261.0 and 1.16.10262.0) has been released which incorporates this pull request.:tada:

Handy links:

@AnrDaemon
Copy link

"Release notes" link in bot posts is 404'd.

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
AutoMerge Marked for automatic merge by the bot when requirements are met Issue-Bug It either shouldn't be doing this or needs an investigation. Product-Terminal The new Windows Terminal.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

WindowsTerminal fails to launch elevate=true profiles on new install; elevate-shim does not set dllpath
6 participants