1
0
Fork 0
mirror of https://github.com/vim/vim synced 2025-03-16 06:47:52 +01:00

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: 

Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Ken Takata <kentkt@csc.jp>
This commit is contained in:
Ken Takata 2023-10-14 11:49:09 +02:00 committed by Christian Brabandt
parent 989426be6e
commit ae3cfa47d3
No known key found for this signature in database
GPG key ID: F3F92DA383FDDE09
3 changed files with 103 additions and 36 deletions

View file

@ -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 restriction is relaxed, and any Python 3
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*

View file

@ -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),
# 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)
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;
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;
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 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);
}
}

View file

@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2026,
/**/
2025,
/**/