diff options
author | Ken Takata <kentkt@csc.jp> | 2023-10-14 11:49:09 +0200 |
---|---|---|
committer | Christian Brabandt <cb@256bit.org> | 2023-10-14 11:49:09 +0200 |
commit | ae3cfa47d3dcee75061db598eb19879693b2393a (patch) | |
tree | 97f5e2ea901b9427ac988a90e2678865cafcf966 /src | |
parent | 989426be6e9ae23d2413943890206cbe15d9df38 (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>
Diffstat (limited to 'src')
-rw-r--r-- | src/if_python3.c | 125 | ||||
-rw-r--r-- | src/version.c | 2 |
2 files changed, 95 insertions, 32 deletions
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, |