From b2f9e0e2c537bcde16dab3b62687a17e17849ce1 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 25 Dec 2020 13:52:37 +0100 Subject: 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 #7540) --- src/if_python3.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'src/if_python3.c') diff --git a/src/if_python3.c b/src/if_python3.c index ea4fd7dd8b..f9c8002da1 100644 --- a/src/if_python3.c +++ b/src/if_python3.c @@ -671,6 +671,65 @@ py3_PyType_HasFeature(PyTypeObject *type, unsigned long feature) # 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 verbose) 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) -- cgit v1.2.3