mirror of
https://github.com/python/cpython.git
synced 2025-08-03 00:23:06 +00:00
Merge changes from the upstream version:
- cast is implemented as a foreign function now - On Windows, it is now possible to access functions exported by ordinal only
This commit is contained in:
parent
f4b066084a
commit
b03cb602e8
7 changed files with 191 additions and 92 deletions
|
@ -2388,6 +2388,11 @@ static PPROC FindAddress(void *handle, char *name, PyObject *type)
|
|||
address = (PPROC)GetProcAddress(handle, name);
|
||||
if (address)
|
||||
return address;
|
||||
|
||||
if (((size_t)name & ~0xFFFF) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* It should not happen that dict is NULL, but better be safe */
|
||||
if (dict==NULL || dict->flags & FUNCFLAG_CDECL)
|
||||
return address;
|
||||
|
@ -2493,6 +2498,28 @@ _validate_paramflags(PyTypeObject *type, PyObject *paramflags)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_get_name(PyObject *obj, char **pname)
|
||||
{
|
||||
#ifdef MS_WIN32
|
||||
if (PyInt_Check(obj) || PyLong_Check(obj)) {
|
||||
/* We have to use MAKEINTRESOURCEA for Windows CE.
|
||||
Works on Windows as well, of course.
|
||||
*/
|
||||
*pname = MAKEINTRESOURCEA(PyInt_AsUnsignedLongMask(obj) & 0xFFFF);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
if (PyString_Check(obj) || PyUnicode_Check(obj)) {
|
||||
*pname = PyString_AsString(obj);
|
||||
return pname ? 1 : 0;
|
||||
}
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"function name must be string or integer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
CFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
|
@ -2504,7 +2531,7 @@ CFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
void *handle;
|
||||
PyObject *paramflags = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "sO|O", &name, &dll, ¶mflags))
|
||||
if (!PyArg_ParseTuple(args, "(O&O)|O", _get_name, &name, &dll, ¶mflags))
|
||||
return NULL;
|
||||
if (paramflags == Py_None)
|
||||
paramflags = NULL;
|
||||
|
@ -2529,9 +2556,14 @@ CFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
#ifdef MS_WIN32
|
||||
address = FindAddress(handle, name, (PyObject *)type);
|
||||
if (!address) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"function '%s' not found",
|
||||
name);
|
||||
if ((size_t)name & ~0xFFFF)
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"function '%s' not found",
|
||||
name);
|
||||
else
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"function ordinal %d not found",
|
||||
name);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
|
@ -2608,8 +2640,9 @@ CFuncPtr_FromVtblIndex(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
"O" - must be a callable, creates a C callable function
|
||||
|
||||
two or more argument forms (the third argument is a paramflags tuple)
|
||||
"sO|O" - function name, dll object (with an integer handle)
|
||||
"is|O" - vtable index, method name, creates callable calling COM vtbl
|
||||
"(sO)|..." - (function name, dll object (with an integer handle)), paramflags
|
||||
"(iO)|..." - (function ordinal, dll object (with an integer handle)), paramflags
|
||||
"is|..." - vtable index, method name, creates callable calling COM vtbl
|
||||
*/
|
||||
static PyObject *
|
||||
CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
|
@ -2622,14 +2655,13 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
if (PyTuple_GET_SIZE(args) == 0)
|
||||
return GenericCData_new(type, args, kwds);
|
||||
|
||||
/* Shouldn't the following better be done in __init__? */
|
||||
if (2 <= PyTuple_GET_SIZE(args)) {
|
||||
#ifdef MS_WIN32
|
||||
if (PyInt_Check(PyTuple_GET_ITEM(args, 0)))
|
||||
return CFuncPtr_FromVtblIndex(type, args, kwds);
|
||||
#endif
|
||||
if (1 <= PyTuple_GET_SIZE(args) && PyTuple_Check(PyTuple_GET_ITEM(args, 0)))
|
||||
return CFuncPtr_FromDll(type, args, kwds);
|
||||
}
|
||||
|
||||
#ifdef MS_WIN32
|
||||
if (2 <= PyTuple_GET_SIZE(args) && PyInt_Check(PyTuple_GET_ITEM(args, 0)))
|
||||
return CFuncPtr_FromVtblIndex(type, args, kwds);
|
||||
#endif
|
||||
|
||||
if (1 == PyTuple_GET_SIZE(args)
|
||||
&& (PyInt_Check(PyTuple_GET_ITEM(args, 0))
|
||||
|
@ -4351,6 +4383,42 @@ string_at(const char *ptr, Py_ssize_t size)
|
|||
return PyString_FromStringAndSize(ptr, size);
|
||||
}
|
||||
|
||||
static int
|
||||
cast_check_pointertype(PyObject *arg)
|
||||
{
|
||||
StgDictObject *dict;
|
||||
|
||||
if (PointerTypeObject_Check(arg))
|
||||
return 1;
|
||||
dict = PyType_stgdict(arg);
|
||||
if (dict) {
|
||||
if (PyString_Check(dict->proto)
|
||||
&& (strchr("sPzUZXO", PyString_AS_STRING(dict->proto)[0]))) {
|
||||
/* simple pointer types, c_void_p, c_wchar_p, BSTR, ... */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"cast() argument 2 must be a pointer type, not %s",
|
||||
PyType_Check(arg)
|
||||
? ((PyTypeObject *)arg)->tp_name
|
||||
: arg->ob_type->tp_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cast(void *ptr, PyObject *ctype)
|
||||
{
|
||||
CDataObject *result;
|
||||
if (0 == cast_check_pointertype(ctype))
|
||||
return NULL;
|
||||
result = (CDataObject *)PyObject_CallFunctionObjArgs(ctype, NULL);
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
/* Should we assert that result is a pointer type? */
|
||||
memcpy(result->b_ptr, &ptr, sizeof(void *));
|
||||
return (PyObject *)result;
|
||||
}
|
||||
|
||||
#ifdef CTYPES_UNICODE
|
||||
static PyObject *
|
||||
|
@ -4486,6 +4554,7 @@ init_ctypes(void)
|
|||
PyModule_AddObject(m, "_memmove_addr", PyLong_FromVoidPtr(memmove));
|
||||
PyModule_AddObject(m, "_memset_addr", PyLong_FromVoidPtr(memset));
|
||||
PyModule_AddObject(m, "_string_at_addr", PyLong_FromVoidPtr(string_at));
|
||||
PyModule_AddObject(m, "_cast_addr", PyLong_FromVoidPtr(cast));
|
||||
#ifdef CTYPES_UNICODE
|
||||
PyModule_AddObject(m, "_wstring_at_addr", PyLong_FromVoidPtr(wstring_at));
|
||||
#endif
|
||||
|
|
|
@ -1423,71 +1423,7 @@ set_conversion_mode(PyObject *self, PyObject *args)
|
|||
}
|
||||
#endif
|
||||
|
||||
static char cast_doc[] =
|
||||
"cast(cobject, ctype) -> ctype-instance\n\
|
||||
\n\
|
||||
Create an instance of ctype, and copy the internal memory buffer\n\
|
||||
of cobject to the new instance. Should be used to cast one type\n\
|
||||
of pointer to another type of pointer.\n\
|
||||
Doesn't work correctly with ctypes integers.\n";
|
||||
|
||||
static int cast_check_pointertype(PyObject *arg, PyObject **pobj)
|
||||
{
|
||||
StgDictObject *dict;
|
||||
|
||||
if (PointerTypeObject_Check(arg)) {
|
||||
*pobj = arg;
|
||||
return 1;
|
||||
}
|
||||
dict = PyType_stgdict(arg);
|
||||
if (dict) {
|
||||
if (PyString_Check(dict->proto)
|
||||
&& (strchr("sPzUZXO", PyString_AS_STRING(dict->proto)[0]))) {
|
||||
/* simple pointer types, c_void_p, c_wchar_p, BSTR, ... */
|
||||
*pobj = arg;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (PyType_Check(arg)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"cast() argument 2 must be a pointer type, not %s",
|
||||
((PyTypeObject *)arg)->tp_name);
|
||||
} else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"cast() argument 2 must be a pointer type, not a %s",
|
||||
arg->ob_type->tp_name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *cast(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *obj, *ctype;
|
||||
struct argument a;
|
||||
CDataObject *result;
|
||||
|
||||
/* We could and should allow array types for the second argument
|
||||
also, but we cannot use the simple memcpy below for them. */
|
||||
if (!PyArg_ParseTuple(args, "OO&:cast", &obj, &cast_check_pointertype, &ctype))
|
||||
return NULL;
|
||||
if (-1 == ConvParam(obj, 1, &a))
|
||||
return NULL;
|
||||
result = (CDataObject *)PyObject_CallFunctionObjArgs(ctype, NULL);
|
||||
if (result == NULL) {
|
||||
Py_XDECREF(a.keep);
|
||||
return NULL;
|
||||
}
|
||||
// result->b_size
|
||||
// a.ffi_type->size
|
||||
memcpy(result->b_ptr, &a.value,
|
||||
min(result->b_size, (int)a.ffi_type->size));
|
||||
Py_XDECREF(a.keep);
|
||||
return (PyObject *)result;
|
||||
}
|
||||
|
||||
|
||||
PyMethodDef module_methods[] = {
|
||||
{"cast", cast, METH_VARARGS, cast_doc},
|
||||
#ifdef CTYPES_UNICODE
|
||||
{"set_conversion_mode", set_conversion_mode, METH_VARARGS, set_conversion_mode_doc},
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue