diff options
author | Steve Dower <steve.dower@microsoft.com> | 2019-03-29 23:37:16 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-29 23:37:16 (GMT) |
commit | 2438cdf0e932a341c7613bf4323d06b91ae9f1f1 (patch) | |
tree | 231cdf3f22e1d5eb9f88fe7a511ab47e3cf8d225 /Modules/posixmodule.c | |
parent | 32119e10b792ad7ee4e5f951a2d89ddbaf111cc5 (diff) | |
download | cpython-2438cdf0e932a341c7613bf4323d06b91ae9f1f1.zip cpython-2438cdf0e932a341c7613bf4323d06b91ae9f1f1.tar.gz cpython-2438cdf0e932a341c7613bf4323d06b91ae9f1f1.tar.bz2 |
bpo-36085: Enable better DLL resolution on Windows (GH-12302)
Diffstat (limited to 'Modules/posixmodule.c')
-rw-r--r-- | Modules/posixmodule.c | 133 |
1 files changed, 129 insertions, 4 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 3f76018..7c4e5f0 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1442,17 +1442,23 @@ win32_error(const char* function, const char* filename) } static PyObject * -win32_error_object(const char* function, PyObject* filename) +win32_error_object_err(const char* function, PyObject* filename, DWORD err) { /* XXX - see win32_error for comments on 'function' */ - errno = GetLastError(); if (filename) return PyErr_SetExcFromWindowsErrWithFilenameObject( PyExc_OSError, - errno, + err, filename); else - return PyErr_SetFromWindowsErr(errno); + return PyErr_SetFromWindowsErr(err); +} + +static PyObject * +win32_error_object(const char* function, PyObject* filename) +{ + errno = GetLastError(); + return win32_error_object_err(function, filename, errno); } #endif /* MS_WINDOWS */ @@ -13161,6 +13167,113 @@ error: } #endif /* HAVE_GETRANDOM_SYSCALL */ +#ifdef MS_WINDOWS +/* bpo-36085: Helper functions for managing DLL search directories + * on win32 + */ + +typedef DLL_DIRECTORY_COOKIE (WINAPI *PAddDllDirectory)(PCWSTR newDirectory); +typedef BOOL (WINAPI *PRemoveDllDirectory)(DLL_DIRECTORY_COOKIE cookie); + +/*[clinic input] +os._add_dll_directory + + path: path_t + +Add a path to the DLL search path. + +This search path is used when resolving dependencies for imported +extension modules (the module itself is resolved through sys.path), +and also by ctypes. + +Returns an opaque value that may be passed to os.remove_dll_directory +to remove this directory from the search path. +[clinic start generated code]*/ + +static PyObject * +os__add_dll_directory_impl(PyObject *module, path_t *path) +/*[clinic end generated code: output=80b025daebb5d683 input=1de3e6c13a5808c8]*/ +{ + HMODULE hKernel32; + PAddDllDirectory AddDllDirectory; + DLL_DIRECTORY_COOKIE cookie = 0; + DWORD err = 0; + + /* For Windows 7, we have to load this. As this will be a fairly + infrequent operation, just do it each time. Kernel32 is always + loaded. */ + Py_BEGIN_ALLOW_THREADS + if (!(hKernel32 = GetModuleHandleW(L"kernel32")) || + !(AddDllDirectory = (PAddDllDirectory)GetProcAddress( + hKernel32, "AddDllDirectory")) || + !(cookie = (*AddDllDirectory)(path->wide))) { + err = GetLastError(); + } + Py_END_ALLOW_THREADS + + if (err) { + return win32_error_object_err("add_dll_directory", + path->object, err); + } + + return PyCapsule_New(cookie, "DLL directory cookie", NULL); +} + +/*[clinic input] +os._remove_dll_directory + + cookie: object + +Removes a path from the DLL search path. + +The parameter is an opaque value that was returned from +os.add_dll_directory. You can only remove directories that you added +yourself. +[clinic start generated code]*/ + +static PyObject * +os__remove_dll_directory_impl(PyObject *module, PyObject *cookie) +/*[clinic end generated code: output=594350433ae535bc input=c1d16a7e7d9dc5dc]*/ +{ + HMODULE hKernel32; + PRemoveDllDirectory RemoveDllDirectory; + DLL_DIRECTORY_COOKIE cookieValue; + DWORD err = 0; + + if (!PyCapsule_IsValid(cookie, "DLL directory cookie")) { + PyErr_SetString(PyExc_TypeError, + "Provided cookie was not returned from os.add_dll_directory"); + return NULL; + } + + cookieValue = (DLL_DIRECTORY_COOKIE)PyCapsule_GetPointer( + cookie, "DLL directory cookie"); + + /* For Windows 7, we have to load this. As this will be a fairly + infrequent operation, just do it each time. Kernel32 is always + loaded. */ + Py_BEGIN_ALLOW_THREADS + if (!(hKernel32 = GetModuleHandleW(L"kernel32")) || + !(RemoveDllDirectory = (PRemoveDllDirectory)GetProcAddress( + hKernel32, "RemoveDllDirectory")) || + !(*RemoveDllDirectory)(cookieValue)) { + err = GetLastError(); + } + Py_END_ALLOW_THREADS + + if (err) { + return win32_error_object_err("remove_dll_directory", + NULL, err); + } + + if (PyCapsule_SetName(cookie, NULL)) { + return NULL; + } + + Py_RETURN_NONE; +} + +#endif static PyMethodDef posix_methods[] = { @@ -13349,6 +13462,10 @@ static PyMethodDef posix_methods[] = { OS_SCANDIR_METHODDEF OS_FSPATH_METHODDEF OS_GETRANDOM_METHODDEF +#ifdef MS_WINDOWS + OS__ADD_DLL_DIRECTORY_METHODDEF + OS__REMOVE_DLL_DIRECTORY_METHODDEF +#endif {NULL, NULL} /* Sentinel */ }; @@ -13826,6 +13943,14 @@ all_ins(PyObject *m) if (PyModule_AddIntConstant(m, "_COPYFILE_DATA", COPYFILE_DATA)) return -1; #endif +#ifdef MS_WINDOWS + if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_DEFAULT_DIRS", LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) return -1; + if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_APPLICATION_DIR", LOAD_LIBRARY_SEARCH_APPLICATION_DIR)) return -1; + if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_SYSTEM32", LOAD_LIBRARY_SEARCH_SYSTEM32)) return -1; + if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_USER_DIRS", LOAD_LIBRARY_SEARCH_USER_DIRS)) return -1; + if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR", LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)) return -1; +#endif + return 0; } |