Skip to content

Commit 279bbd2

Browse files
gh-100107: Make py.exe launcher ignore app aliases that launch Microsoft Store (GH-114358)
(cherry picked from commit d5c21c1) Co-authored-by: Vincent Cunningham <[email protected]>
1 parent d7d3690 commit 279bbd2

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The ``py.exe`` launcher will no longer attempt to run the Microsoft Store redirector when launching a script containing a ``/usr/bin/env`` shebang

PC/launcher2.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,21 @@ findArgv0End(const wchar_t *buffer, int bufferLength)
561561
*** COMMAND-LINE PARSING ***
562562
\******************************************************************************/
563563

564+
// Adapted from https://stackoverflow.com/a/65583702
565+
typedef struct AppExecLinkFile { // For tag IO_REPARSE_TAG_APPEXECLINK
566+
DWORD reparseTag;
567+
WORD reparseDataLength;
568+
WORD reserved;
569+
ULONG version;
570+
wchar_t stringList[MAX_PATH * 4]; // Multistring (Consecutive UTF-16 strings each ending with a NUL)
571+
/* There are normally 4 strings here. Ex:
572+
Package ID: L"Microsoft.DesktopAppInstaller_8wekyb3d8bbwe"
573+
Entry Point: L"Microsoft.DesktopAppInstaller_8wekyb3d8bbwe!PythonRedirector"
574+
Executable: L"C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_1.17.106910_x64__8wekyb3d8bbwe\AppInstallerPythonRedirector.exe"
575+
Applic. Type: L"0" // Integer as ASCII. "0" = Desktop bridge application; Else sandboxed UWP application
576+
*/
577+
} AppExecLinkFile;
578+
564579

565580
int
566581
parseCommandLine(SearchInfo *search)
@@ -752,6 +767,55 @@ _shebangStartsWith(const wchar_t *buffer, int bufferLength, const wchar_t *prefi
752767
}
753768

754769

770+
int
771+
ensure_no_redirector_stub(wchar_t* filename, wchar_t* buffer)
772+
{
773+
// Make sure we didn't find a reparse point that will open the Microsoft Store
774+
// If we did, pretend there was no shebang and let normal handling take over
775+
WIN32_FIND_DATAW findData;
776+
HANDLE hFind = FindFirstFileW(buffer, &findData);
777+
if (!hFind) {
778+
// Let normal handling take over
779+
debug(L"# Did not find %s on PATH\n", filename);
780+
return RC_NO_SHEBANG;
781+
}
782+
783+
FindClose(hFind);
784+
785+
if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
786+
findData.dwReserved0 & IO_REPARSE_TAG_APPEXECLINK)) {
787+
return 0;
788+
}
789+
790+
HANDLE hReparsePoint = CreateFileW(buffer, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL);
791+
if (!hReparsePoint) {
792+
// Let normal handling take over
793+
debug(L"# Did not find %s on PATH\n", filename);
794+
return RC_NO_SHEBANG;
795+
}
796+
797+
AppExecLinkFile appExecLink;
798+
799+
if (!DeviceIoControl(hReparsePoint, FSCTL_GET_REPARSE_POINT, NULL, 0, &appExecLink, sizeof(appExecLink), NULL, NULL)) {
800+
// Let normal handling take over
801+
debug(L"# Did not find %s on PATH\n", filename);
802+
CloseHandle(hReparsePoint);
803+
return RC_NO_SHEBANG;
804+
}
805+
806+
CloseHandle(hReparsePoint);
807+
808+
const wchar_t* redirectorPackageId = L"Microsoft.DesktopAppInstaller_8wekyb3d8bbwe";
809+
810+
if (0 == wcscmp(appExecLink.stringList, redirectorPackageId)) {
811+
debug(L"# ignoring redirector that would launch store\n");
812+
return RC_NO_SHEBANG;
813+
}
814+
815+
return 0;
816+
}
817+
818+
755819
int
756820
searchPath(SearchInfo *search, const wchar_t *shebang, int shebangLength)
757821
{
@@ -813,6 +877,11 @@ searchPath(SearchInfo *search, const wchar_t *shebang, int shebangLength)
813877
return RC_BAD_VIRTUAL_PATH;
814878
}
815879

880+
int result = ensure_no_redirector_stub(filename, buffer);
881+
if (result) {
882+
return result;
883+
}
884+
816885
// Check that we aren't going to call ourselves again
817886
// If we are, pretend there was no shebang and let normal handling take over
818887
if (GetModuleFileNameW(NULL, filename, MAXLEN) &&

0 commit comments

Comments
 (0)