# HG changeset patch # User Christian Brabandt # Date 1697353986 -7200 # Node ID e9038f9de714e0c45d9f2f33cbab72605e92d0ae # Parent e2f6cf52e4963eb288c8b450e51538fece7df2c6 patch 9.0.2026: win32: python3 dll loading can be improved Commit: https://github.com/vim/vim/commit/ae3cfa47d3dcee75061db598eb19879693b2393a Author: Ken Takata Date: Sat Oct 14 11:49:09 2023 +0200 patch 9.0.2026: win32: python3 dll loading can be improved 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 Co-authored-by: Ken Takata diff --git a/runtime/doc/if_pyth.txt b/runtime/doc/if_pyth.txt --- 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 res 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 --- a/src/if_python3.c +++ b/src/if_python3.c @@ -835,17 +835,16 @@ Py_ssize_t py3_PyList_GET_SIZE(PyObject * 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 *libna } ++cp; } - vim_snprintf(subkey, sizeof(subkey), -# ifdef _WIN64 - "Software\\Python\\PythonCore\\%d.%d\\InstallPath", -# else - "Software\\Python\\PythonCore\\%d.%d-32\\InstallPath", + + WCHAR keyfound[32]; + HKEY hKeyTop[] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE}; + HKEY hKeyFound = NULL; +# ifdef USE_LIMITED_API + long maxminor = -1; # endif - PY_MAJOR_VERSION, PY_MINOR_VERSION); - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, subkey, 0, KEY_QUERY_VALUE, &hKey) - != ERROR_SUCCESS) - return NULL; - rc = RegQueryValueA(hKey, NULL, installpath, &len); - RegCloseKey(hKey); - if (ERROR_SUCCESS != rc) + 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 + if (*wp != L'\0') + continue; +# else + if (wcscmp(wp, L"-32") != 0) + continue; +# endif + + 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; - cp = installpath + len; - // Just in case registry value contains null terminators. - while (cp > installpath && *(cp-1) == '\0') - --cp; + + 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; + size_t len2 = len / sizeof(WCHAR) + 1 + strlen(libname); + WCHAR *path = alloc(len2 * sizeof(WCHAR)); + if (path == NULL) + return NULL; + 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. - while (cp > installpath && (*(cp-1) == '\\' || *(cp-1) == '/')) - --cp; - // Ignore if InstallPath is effectively empty. - if (cp <= installpath) - 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; + 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 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 --- 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,