changeset 23336:9c8353f58076 v8.2.2211

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 <Bram@vim.org> 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)
author Bram Moolenaar <Bram@vim.org>
date Fri, 25 Dec 2020 14:00:03 +0100
parents 42ad87391b94
children 9ca71ad5406b
files src/if_python3.c src/version.c
diffstat 2 files changed, 75 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- 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)
--- 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,