Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +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
69 changes: 69 additions & 0 deletions PC/launcher2.c
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,21 @@ findArgv0End(const wchar_t *buffer, int bufferLength)
*** COMMAND-LINE PARSING ***
\******************************************************************************/

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


int
parseCommandLine(SearchInfo *search)
Expand Down Expand Up @@ -763,6 +778,55 @@ _shebangStartsWith(const wchar_t *buffer, int bufferLength, const wchar_t *prefi
}


int
ensure_no_redirector_stub(wchar_t* filename, wchar_t* buffer)
{
// Make sure we didn't find a reparse point that will open the Microsoft Store
// If we did, pretend there was no shebang and let normal handling take over
WIN32_FIND_DATAW findData;
HANDLE hFind = FindFirstFileW(buffer, &findData);
if (!hFind) {
// Let normal handling take over
debug(L"# Did not find %s on PATH\n", filename);
return RC_NO_SHEBANG;
}

FindClose(hFind);

if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
findData.dwReserved0 & IO_REPARSE_TAG_APPEXECLINK)) {
return 0;
}

HANDLE hReparsePoint = CreateFileW(buffer, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL);
if (!hReparsePoint) {
// Let normal handling take over
debug(L"# Did not find %s on PATH\n", filename);
return RC_NO_SHEBANG;
}

AppExecLinkFile appExecLink;

if (!DeviceIoControl(hReparsePoint, FSCTL_GET_REPARSE_POINT, NULL, 0, &appExecLink, sizeof(appExecLink), NULL, NULL)) {
// Let normal handling take over
debug(L"# Did not find %s on PATH\n", filename);
CloseHandle(hReparsePoint);
return RC_NO_SHEBANG;
}

CloseHandle(hReparsePoint);

const wchar_t* redirectorPackageId = L"Microsoft.DesktopAppInstaller_8wekyb3d8bbwe";

if (0 == wcscmp(appExecLink.stringList, redirectorPackageId)) {
debug(L"# ignoring redirector that would launch store\n");
return RC_NO_SHEBANG;
}

return 0;
}


int
searchPath(SearchInfo *search, const wchar_t *shebang, int shebangLength)
{
Expand Down Expand Up @@ -826,6 +890,11 @@ searchPath(SearchInfo *search, const wchar_t *shebang, int shebangLength)
return RC_BAD_VIRTUAL_PATH;
}

int result = ensure_no_redirector_stub(filename, buffer);
if (result) {
return result;
}

// Check that we aren't going to call ourselves again
// If we are, pretend there was no shebang and let normal handling take over
if (GetModuleFileNameW(NULL, filename, MAXLEN) &&
Expand Down