https://github.com/python/cpython/commit/d5c21c12c17b6e4db2378755af8e3699516da187
commit: d5c21c12c17b6e4db2378755af8e3699516da187
branch: main
author: Vincent Cunningham <[email protected]>
committer: zooba <[email protected]>
date: 2024-01-25T00:23:28Z
summary:

gh-100107: Make py.exe launcher ignore app aliases that launch Microsoft Store 
(GH-114358)

files:
A Misc/NEWS.d/next/Windows/2024-01-23-00-05-05.gh-issue-100107.lkbP_Q.rst
M PC/launcher2.c

diff --git 
a/Misc/NEWS.d/next/Windows/2024-01-23-00-05-05.gh-issue-100107.lkbP_Q.rst 
b/Misc/NEWS.d/next/Windows/2024-01-23-00-05-05.gh-issue-100107.lkbP_Q.rst
new file mode 100644
index 00000000000000..388d61a2b3bd6d
--- /dev/null
+++ b/Misc/NEWS.d/next/Windows/2024-01-23-00-05-05.gh-issue-100107.lkbP_Q.rst
@@ -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
diff --git a/PC/launcher2.c b/PC/launcher2.c
index 2a8f8a101fc8a6..e426eccd700044 100644
--- a/PC/launcher2.c
+++ b/PC/launcher2.c
@@ -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)
@@ -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)
 {
@@ -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) &&

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to