# HG changeset patch # User Bram Moolenaar # Date 1608901203 -3600 # Node ID 9c8353f580769b8598d8b5d0cbc24802fccaea51 # Parent 42ad87391b9439ba3c8e97df091df9802c09606e patch 8.2.2211: MS-Windows: can't load Python dll if not in the path Commit: https://github.com/vim/vim/commit/b2f9e0e2c537bcde16dab3b62687a17e17849ce1 Author: Bram Moolenaar Date: Fri Dec 25 13:52:37 2020 +0100 patch 8.2.2211: MS-Windows: can't load Python dll if not in the path Problem: MS-Windows: can't load Python dll if not in the path. Solution: Use the InstallPath registry entry. (Kelvin Lee, closes https://github.com/vim/vim/issues/7540) diff --git a/src/if_python3.c b/src/if_python3.c --- a/src/if_python3.c +++ b/src/if_python3.c @@ -671,6 +671,65 @@ py3_PyType_HasFeature(PyTypeObject *type # define PyType_HasFeature(t,f) py3_PyType_HasFeature(t,f) # endif +# ifdef MSWIN +/* + * Look up the library "libname" using the InstallPath registry key. + * Return NULL when failed. Return an allocated string when successful. + */ + static char * +py3_get_system_libname(const char *libname) +{ + const char *cp = libname; + char subkey[128]; + HKEY hKey; + char installpath[MAXPATHL]; + LONG len = sizeof(installpath); + LSTATUS rc; + size_t sysliblen; + char *syslibname; + + while (*cp != '\0') + { + if (*cp == ':' || *cp == '\\' || *cp == '/') + { + // Bail out if "libname" contains path separator, assume it is + // an absolute path. + return NULL; + } + ++cp; + } + vim_snprintf(subkey, sizeof(subkey), +# ifdef _WIN64 + "Software\\Python\\PythonCore\\%d.%d\\InstallPath", +# else + "Software\\Python\\PythonCore\\%d.%d-32\\InstallPath", +# 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) + 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) + 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; +} +# endif + /* * Load library and get all pointers. * Parameter 'libname' provides name of DLL. @@ -701,6 +760,20 @@ py3_runtime_link_init(char *libname, int return OK; hinstPy3 = load_dll(libname); +# ifdef MSWIN + if (!hinstPy3) + { + // Attempt to use the path from InstallPath as stored in the registry. + char *syslibname = py3_get_system_libname(libname); + + if (syslibname != NULL) + { + hinstPy3 = load_dll(syslibname); + vim_free(syslibname); + } + } +# endif + if (!hinstPy3) { if (verbose) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2211, +/**/ 2210, /**/ 2209,