summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKen Takata <kentkt@csc.jp>2023-10-14 11:49:09 +0200
committerChristian Brabandt <cb@256bit.org>2023-10-14 11:49:09 +0200
commitae3cfa47d3dcee75061db598eb19879693b2393a (patch)
tree97f5e2ea901b9427ac988a90e2678865cafcf966
parent989426be6e9ae23d2413943890206cbe15d9df38 (diff)
patch 9.0.2026: win32: python3 dll loading can be improvedv9.0.2026
Problem: win32: python3 dll loading can be improved Solution: Load DLL from registry path Support loading python3.dll and/or python3xx.dll from the path written in the registry. To support Stable ABI's forwarder DLL (python3.dll), use the `LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR` flag for `LoadLibraryExW()` because python3xx.dll is placed in the same directory of python3.dll. If Stable ABI is used, search the latest version from the registry (both from HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE). If Stable ABI is not used, search only the matching version. closes: #13315 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Ken Takata <kentkt@csc.jp>
-rw-r--r--runtime/doc/if_pyth.txt8
-rw-r--r--src/if_python3.c125
-rw-r--r--src/version.c2
3 files changed, 101 insertions, 34 deletions
diff --git a/runtime/doc/if_pyth.txt b/runtime/doc/if_pyth.txt
index 3d3b92a662..c0b968e07c 100644
--- a/runtime/doc/if_pyth.txt
+++ b/runtime/doc/if_pyth.txt
@@ -754,8 +754,10 @@ you can use Vim without this file.
MS-Windows ~
To use the Python interface the Python DLL must be in your search path. In a
-console window type "path" to see what directories are used. The 'pythondll'
-or 'pythonthreedll' option can be also used to specify the Python DLL.
+console window type "path" to see what directories are used. If the DLL is
+not found in your search path, Vim will check the registry to find the path
+where Python is installed. The 'pythondll' or 'pythonthreedll' option can be
+also used to specify the Python DLL.
The name of the DLL should match the Python version Vim was compiled with.
Currently the name for Python 2 is "python27.dll", that is for Python 2.7.
@@ -782,6 +784,8 @@ and failures. With Stable ABI, this restriction is relaxed, and any Python 3
library with version of at least |v:python3_version| will work. See
|has-python| for how to check if Stable ABI is supported, or see if version
output includes |+python3/dyn-stable|.
+On MS-Windows, 'pythonthreedll' will be set to "python3.dll". When searching
+the DLL from the registry, Vim will search the latest version of Python.
==============================================================================
10. Python 3 *python3*
diff --git a/src/if_python3.c b/src/if_python3.c
index c3900892ea..a177371720 100644
--- a/src/if_python3.c
+++ b/src/if_python3.c
@@ -835,17 +835,16 @@ Py_ssize_t py3_PyList_GET_SIZE(PyObject *op)
* Look up the library "libname" using the InstallPath registry key.
* Return NULL when failed. Return an allocated string when successful.
*/
- static char *
+ static WCHAR *
py3_get_system_libname(const char *libname)
{
+ const WCHAR *pythoncore = L"Software\\Python\\PythonCore";
const char *cp = libname;
- char subkey[128];
+ WCHAR subkey[128];
HKEY hKey;
- char installpath[MAXPATHL];
- LONG len = sizeof(installpath);
- LSTATUS rc;
- size_t sysliblen;
- char *syslibname;
+ int i;
+ DWORD j, len;
+ LSTATUS ret;
while (*cp != '\0')
{
@@ -857,35 +856,95 @@ py3_get_system_libname(const char *libname)
}
++cp;
}
- vim_snprintf(subkey, sizeof(subkey),
+
+ WCHAR keyfound[32];
+ HKEY hKeyTop[] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE};
+ HKEY hKeyFound = NULL;
+# ifdef USE_LIMITED_API
+ long maxminor = -1;
+# endif
+ for (i = 0; i < ARRAY_LENGTH(hKeyTop); i++)
+ {
+ long major, minor;
+
+ ret = RegOpenKeyExW(hKeyTop[i], pythoncore, 0, KEY_READ, &hKey);
+ if (ret != ERROR_SUCCESS)
+ continue;
+ for (j = 0;; j++)
+ {
+ WCHAR keyname[32];
+ WCHAR *wp;
+
+ len = ARRAY_LENGTH(keyname);
+ ret = RegEnumKeyExW(hKey, j, keyname, &len,
+ NULL, NULL, NULL, NULL);
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ major = wcstol(keyname, &wp, 10);
+ if (*wp == L'.')
+ minor = wcstol(wp + 1, &wp, 10);
# ifdef _WIN64
- "Software\\Python\\PythonCore\\%d.%d\\InstallPath",
+ if (*wp != L'\0')
+ continue;
# else
- "Software\\Python\\PythonCore\\%d.%d-32\\InstallPath",
+ if (wcscmp(wp, L"-32") != 0)
+ continue;
# endif
- PY_MAJOR_VERSION, PY_MINOR_VERSION);
- if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, subkey, 0, KEY_QUERY_VALUE, &hKey)
- != ERROR_SUCCESS)
+
+ if (major != PY_MAJOR_VERSION)
+ continue;
+# ifdef USE_LIMITED_API
+ // Search the latest version.
+ if ((minor > maxminor)
+ && (minor >= ((Py_LIMITED_API >> 16) & 0xff)))
+ {
+ maxminor = minor;
+ wcscpy(keyfound, keyname);
+ hKeyFound = hKeyTop[i];
+ }
+# else
+ // Check if it matches with the compiled version.
+ if (minor == PY_MINOR_VERSION)
+ {
+ wcscpy(keyfound, keyname);
+ hKeyFound = hKeyTop[i];
+ break;
+ }
+# endif
+ }
+ RegCloseKey(hKey);
+# ifdef USE_LIMITED_API
+ if (hKeyFound != NULL)
+ break;
+# endif
+ }
+ if (hKeyFound == NULL)
return NULL;
- rc = RegQueryValueA(hKey, NULL, installpath, &len);
- RegCloseKey(hKey);
- if (ERROR_SUCCESS != rc)
+
+ swprintf(subkey, ARRAY_LENGTH(subkey), L"%ls\\%ls\\InstallPath",
+ pythoncore, keyfound);
+ ret = RegGetValueW(hKeyFound, subkey, NULL, RRF_RT_REG_SZ,
+ NULL, NULL, &len);
+ if (ret != ERROR_MORE_DATA && ret != ERROR_SUCCESS)
return NULL;
- cp = installpath + len;
- // Just in case registry value contains null terminators.
- while (cp > installpath && *(cp-1) == '\0')
- --cp;
- // Remove trailing path separators.
- while (cp > installpath && (*(cp-1) == '\\' || *(cp-1) == '/'))
- --cp;
- // Ignore if InstallPath is effectively empty.
- if (cp <= installpath)
+ size_t len2 = len / sizeof(WCHAR) + 1 + strlen(libname);
+ WCHAR *path = alloc(len2 * sizeof(WCHAR));
+ if (path == NULL)
return NULL;
- sysliblen = (cp - installpath) + 1 + STRLEN(libname) + 1;
- syslibname = alloc(sysliblen);
- vim_snprintf(syslibname, sysliblen, "%.*s\\%s",
- (int)(cp - installpath), installpath, libname);
- return syslibname;
+ ret = RegGetValueW(hKeyFound, subkey, NULL, RRF_RT_REG_SZ,
+ NULL, path, &len);
+ if (ret != ERROR_SUCCESS)
+ {
+ vim_free(path);
+ return NULL;
+ }
+ // Remove trailing path separators.
+ size_t len3 = wcslen(path);
+ if ((len3 > 0) && (path[len3 - 1] == L'/' || path[len3 - 1] == L'\\'))
+ --len3;
+ swprintf(path + len3, len2 - len3, L"\\%hs", libname);
+ return path;
}
# endif
@@ -923,11 +982,13 @@ py3_runtime_link_init(char *libname, int verbose)
if (!hinstPy3)
{
// Attempt to use the path from InstallPath as stored in the registry.
- char *syslibname = py3_get_system_libname(libname);
+ WCHAR *syslibname = py3_get_system_libname(libname);
if (syslibname != NULL)
{
- hinstPy3 = load_dll(syslibname);
+ hinstPy3 = LoadLibraryExW(syslibname, NULL,
+ LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |
+ LOAD_LIBRARY_SEARCH_SYSTEM32);
vim_free(syslibname);
}
}
diff --git a/src/version.c b/src/version.c
index 73a573df58..111254eade 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2026,
+/**/
2025,
/**/
2024,