-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
gh-100107: Make Py launcher ignore app aliases that launch Microsoft Store #114358
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
Conversation
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's got all the pieces we need, though it can be simplified quite a bit. Would also be ideal to move it to its own function, so that someone reading this function can see from the call what it's doing but they don't have to actually read the details unless they want to.
PC/launcher2.c
Outdated
winerror(0, L"Failed to find %s on PATH\n", filename); | ||
return RC_BAD_VIRTUAL_PATH; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be able to FindClose
here and not worry about cleaning it up later.
PC/launcher2.c
Outdated
@@ -826,6 +841,72 @@ searchPath(SearchInfo *search, const wchar_t *shebang, int shebangLength) | |||
return RC_BAD_VIRTUAL_PATH; | |||
} | |||
|
|||
// Make sure we didn't find a reparse point that will open the Microsoft Store |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's start by refactoring all this out into another function ensure_no_redirector_stub
that either returns 0
(okay) or the RC constant that should be returned from here.
PC/launcher2.c
Outdated
} | ||
|
||
if (findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && | ||
findData.dwReserved0 & IO_REPARSE_TAG_APPEXECLINK) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After refactoring, use this check to exit early from the new function. That will keep the overall indent level lower for the rest of it.
PC/launcher2.c
Outdated
if (GetLastError() == ERROR_FILE_NOT_FOUND) { | ||
debug(L"# %s on disappeared\n", buffer); | ||
// The file found on PATH disappeared. Alias probably disabled by user while trying to run, let normal handling take over | ||
RC_NO_SHEBANG; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this error adds anything - we could lose this race at any time, so probably best to just return RC_NO_SHEBANG
for them all and it can fail if/when we try to launch it.
PC/launcher2.c
Outdated
if (GetLastError() == ERROR_FILE_NOT_FOUND) { | ||
debug(L"# %s on disappeared\n", buffer); | ||
// The file found on PATH disappeared. Alias probably disabled by user while trying to run, let normal handling take over | ||
RC_NO_SHEBANG; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto - no benefit to calling this one out separately. Normal handling for all errors should be okay
PC/launcher2.c
Outdated
|
||
appExecLinkFilePtr = (AppExecLinkFile*)&appExecLinkBuf; | ||
|
||
wchar_t redirectorPackageId[] = L"Microsoft.DesktopAppInstaller"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wchar_t redirectorPackageId[] = L"Microsoft.DesktopAppInstaller"; | |
const wchar_t *redirectorPackageId = L"Microsoft.DesktopAppInstaller_8wekyb3d8bbwe"; |
PC/launcher2.c
Outdated
const size_t bufSize = sizeof(AppExecLinkFile); | ||
wchar_t appExecLinkBuf[sizeof(AppExecLinkFile)]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These aren't necessary - just allocate the struct:
AppExecLinkFile appExecLink;
And then use sizeof(appExecLink)
anywhere we need it, which ought to only be the DeviceIOControl call.
PC/launcher2.c
Outdated
wchar_t partialId[30]; | ||
wcsncpy_s(partialId, redirectorStrLen + 1, appExecLinkFilePtr->stringList, redirectorStrLen); | ||
|
||
if (0 == wcsncmp(partialId, &redirectorPackageId, redirectorStrLen)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A simple wcscmp
ought to be fine here if you use the full package name. As far as I'm aware, the publisher ID has never changed and never will (it's always some kind of hash of "Microsoft").
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
Adding a NEWS entry would be great, too. Just something like |
move new code to own function simplify error handling simplify struct handling simplify string comparison
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
…flagrama/cpython into py-launcher-shebang-appexeclink
I have made the requested changes; please review again. Everything looks better to me except the actual call to the function and checking it's return value. Also, is there any chance of this getting backported into the next release of older supported versions? |
One leaked handle and we're good. And yeah, we can backport this to earlier versions, though it's worth noting that once you've installed 3.12 you'll need a later 3.12 to upgrade the installer - it won't downgrade to a 3.11 version, even if it's "newer". |
Co-authored-by: Steve Dower <steve.dower@microsoft.com>
…Microsoft Store (pythonGH-114358) (cherry picked from commit d5c21c1) Co-authored-by: Vincent Cunningham <flagrama@users.noreply.github.com>
…Microsoft Store (pythonGH-114358) (cherry picked from commit d5c21c1) Co-authored-by: Vincent Cunningham <flagrama@users.noreply.github.com>
Thanks! And congratulations on your first PR! |
GH-114541 is a backport of this pull request to the 3.12 branch. |
GH-114542 is a backport of this pull request to the 3.11 branch. |
Currently when you use the
#!/usr/bin/env python3
shebang on Windows 10 or Windows 11 the Py launcher will search the PATH environment variable and find the default NTFS reparse points called App Execution Aliases Microsoft added to the OSes. These are effectively stub exes that, when Python is not installed from the Microsoft Store, will launch the Microsoft Store to install Python, or if launched with arguments will report an error.This makes Windows 10/11 the only OS where the standard shebang does not work. It complicated packaging python scripts for ordinary users because they have an extra step, either disabling the app execution aliases, installing from the Microsoft Store, or launching the script manually. Windows ends up being the only OS that doesn't "just work" and changing the shebang to something else will break or degrade the experience in other OSes.
This PR solves this issue by checking if the exe found in the PATH is a reparse point. If it is, it will read the file and identify the alias that will launch the store and will drop out of the shebang handling as if nothing was found in the PATH. If it is an alias that does not launch the store, or an ordinary file it will just continue and use the found file as there shouldn't be any issues.
In my testing this now makes opening a script with the standard
#!/usr/bin/env python3
shebang work without additional work by the user.Note that I am not a Windows user or a Windows developer so it's possible that I've missed some workflow and don't know if it works, or my code may be inefficient. I've only really tested the workflow of the normal users that use a Python application I help develop and know that I have solved the issue there.