]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Closes #23253: Delay-load ShellExecute
authorSteve Dower <steve.dower@microsoft.com>
Sat, 24 Jan 2015 16:18:24 +0000 (08:18 -0800)
committerSteve Dower <steve.dower@microsoft.com>
Sat, 24 Jan 2015 16:18:24 +0000 (08:18 -0800)
Doc/library/os.rst
Misc/NEWS
Modules/posixmodule.c

index 2c14f8f485c78f1b3fedba0f3ee8cf1857dec770..c4b8bacd7d35830158b278b57cc2b0dcf941f30e 100644 (file)
@@ -3024,6 +3024,10 @@ written in Python, such as a mail server's external command delivery program.
    doesn't work if it is.  Use the :func:`os.path.normpath` function to ensure that
    the path is properly encoded for Win32.
 
+   To reduce interpreter startup overhead, the Win32 :c:func:`ShellExecute`
+   function is not resolved until this function is first called.  If the function
+   cannot be resolved, :exc:`NotImplementedError` will be raised.
+
    Availability: Windows.
 
 
index 127a7478ff15f7bc78db8ee7e50d02619949d088..50e4bbe11c38d5090d022a4d95041f76c239500b 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ Release date: TBA
 Core and Builtins
 -----------------
 
+- Issue #23253: Delay-load ShellExecute[AW] in os.startfile for reduced
+  startup overhead on Windows.
+
 - Issue #22038: pyatomic.h now uses stdatomic.h or GCC built-in functions for
   atomic memory access if available. Patch written by Vitor de Lima and Gustavo
   Temple.
index 542e600e7f8b32c38ee286d0157205dcc6a467da..502e933440b06a75752bf7c89836176c8af71e52 100644 (file)
@@ -15128,6 +15128,37 @@ The filepath is relative to the current directory.  If you want to use\n\
 an absolute path, make sure the first character is not a slash (\"/\");\n\
 the underlying Win32 ShellExecute function doesn't work if it is.");
 
+/* Grab ShellExecute dynamically from shell32 */
+static int has_ShellExecute = -1;
+static HINSTANCE (CALLBACK *Py_ShellExecuteA)(HWND, LPCSTR, LPCSTR, LPCSTR,
+                                              LPCSTR, INT);
+static HINSTANCE (CALLBACK *Py_ShellExecuteW)(HWND, LPCWSTR, LPCWSTR, LPCWSTR,
+                                              LPCWSTR, INT);
+static int
+check_ShellExecute()
+{
+    HINSTANCE hShell32;
+
+    /* only recheck */
+    if (-1 == has_ShellExecute) {
+        Py_BEGIN_ALLOW_THREADS
+        hShell32 = LoadLibraryW(L"SHELL32");
+        Py_END_ALLOW_THREADS
+        if (hShell32) {
+            *(FARPROC*)&Py_ShellExecuteA = GetProcAddress(hShell32,
+                                            "ShellExecuteA");
+            *(FARPROC*)&Py_ShellExecuteW = GetProcAddress(hShell32,
+                                            "ShellExecuteW");
+            has_ShellExecute = Py_ShellExecuteA &&
+                               Py_ShellExecuteW;
+        } else {
+            has_ShellExecute = 0;
+        }
+    }
+    return has_ShellExecute;
+}
+
+
 static PyObject *
 win32_startfile(PyObject *self, PyObject *args)
 {
@@ -15138,6 +15169,14 @@ win32_startfile(PyObject *self, PyObject *args)
     HINSTANCE rc;
 
     PyObject *unipath, *uoperation = NULL;
+
+    if(!check_ShellExecute()) {
+        /* If the OS doesn't have ShellExecute, return a
+           NotImplementedError. */
+        return PyErr_Format(PyExc_NotImplementedError,
+            "startfile not available on this platform");
+    }
+
     if (!PyArg_ParseTuple(args, "U|s:startfile",
                           &unipath, &operation)) {
         PyErr_Clear();
@@ -15166,8 +15205,8 @@ win32_startfile(PyObject *self, PyObject *args)
         woperation = NULL;
 
     Py_BEGIN_ALLOW_THREADS
-    rc = ShellExecuteW((HWND)0, woperation, wpath,
-                       NULL, NULL, SW_SHOWNORMAL);
+    rc = Py_ShellExecuteW((HWND)0, woperation, wpath,
+                          NULL, NULL, SW_SHOWNORMAL);
     Py_END_ALLOW_THREADS
 
     Py_XDECREF(uoperation);
@@ -15189,8 +15228,8 @@ normal:
     }
     filepath = PyBytes_AsString(ofilepath);
     Py_BEGIN_ALLOW_THREADS
-    rc = ShellExecute((HWND)0, operation, filepath,
-                      NULL, NULL, SW_SHOWNORMAL);
+    rc = Py_ShellExecuteA((HWND)0, operation, filepath,
+                          NULL, NULL, SW_SHOWNORMAL);
     Py_END_ALLOW_THREADS
     if (rc <= (HINSTANCE)32) {
         PyObject *errval = win32_error("startfile", filepath);