Issue #1798: Add ctypes calling convention that allows safe access to
errno (and LastError, on Windows). ctypes maintains a module-global, but thread-local, variable that contains an error number; called 'ctypes_errno' for this discussion. This variable is a private copy of the systems 'errno' value; the copy is swapped with the 'errno' variable on several occasions. Foreign functions created with CDLL(..., use_errno=True), when called, swap the values just before the actual function call, and swapped again immediately afterwards. The 'use_errno' parameter defaults to False, in this case 'ctypes_errno' is not touched. The values are also swapped immeditately before and after ctypes callback functions are called, if the callbacks are constructed using the new optional use_errno parameter set to True: CFUNCTYPE(..., use_errno=TRUE) or WINFUNCTYPE(..., use_errno=True). Two new ctypes functions are provided to access the 'ctypes_errno' value from Python: - ctypes.set_errno(value) sets ctypes_errno to 'value', the previous ctypes_errno value is returned. - ctypes.get_errno() returns the current ctypes_errno value. --- On Windows, the same scheme is implemented for the error value which is managed by the GetLastError() and SetLastError() windows api calls. The ctypes functions are 'ctypes.set_last_error(value)' and 'ctypes.get_last_error()', the CDLL and WinDLL optional parameter is named 'use_last_error', defaults to False. --- On Windows, TlsSetValue and TlsGetValue calls are used to provide thread local storage for the variables; ctypes compiled with __GNUC__ uses __thread variables.
This commit is contained in:
parent
a2b34b87a9
commit
e70c3378c0
|
@ -33,7 +33,9 @@ if _os.name == "posix" and _sys.platform == "darwin":
|
|||
DEFAULT_MODE = RTLD_GLOBAL
|
||||
|
||||
from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \
|
||||
FUNCFLAG_PYTHONAPI as _FUNCFLAG_PYTHONAPI
|
||||
FUNCFLAG_PYTHONAPI as _FUNCFLAG_PYTHONAPI, \
|
||||
FUNCFLAG_USE_ERRNO as _FUNCFLAG_USE_ERRNO, \
|
||||
FUNCFLAG_USE_LASTERROR as _FUNCFLAG_USE_LASTERROR
|
||||
|
||||
"""
|
||||
WINOLEAPI -> HRESULT
|
||||
|
@ -73,8 +75,9 @@ def c_buffer(init, size=None):
|
|||
return create_string_buffer(init, size)
|
||||
|
||||
_c_functype_cache = {}
|
||||
def CFUNCTYPE(restype, *argtypes):
|
||||
"""CFUNCTYPE(restype, *argtypes) -> function prototype.
|
||||
def CFUNCTYPE(restype, *argtypes, **kw):
|
||||
"""CFUNCTYPE(restype, *argtypes,
|
||||
use_errno=False, use_last_error=False) -> function prototype.
|
||||
|
||||
restype: the result type
|
||||
argtypes: a sequence specifying the argument types
|
||||
|
@ -88,14 +91,21 @@ def CFUNCTYPE(restype, *argtypes):
|
|||
prototype((ordinal number, dll object)[, paramflags]) -> foreign function exported by ordinal
|
||||
prototype((function name, dll object)[, paramflags]) -> foreign function exported by name
|
||||
"""
|
||||
flags = _FUNCFLAG_CDECL
|
||||
if kw.pop("use_errno", False):
|
||||
flags |= _FUNCFLAG_USE_ERRNO
|
||||
if kw.pop("use_last_error", False):
|
||||
flags |= _FUNCFLAG_USE_LASTERROR
|
||||
if kw:
|
||||
raise ValueError("unexpected keyword argument(s) %s" % kw.keys())
|
||||
try:
|
||||
return _c_functype_cache[(restype, argtypes)]
|
||||
return _c_functype_cache[(restype, argtypes, flags)]
|
||||
except KeyError:
|
||||
class CFunctionType(_CFuncPtr):
|
||||
_argtypes_ = argtypes
|
||||
_restype_ = restype
|
||||
_flags_ = _FUNCFLAG_CDECL
|
||||
_c_functype_cache[(restype, argtypes)] = CFunctionType
|
||||
_flags_ = flags
|
||||
_c_functype_cache[(restype, argtypes, flags)] = CFunctionType
|
||||
return CFunctionType
|
||||
|
||||
if _os.name in ("nt", "ce"):
|
||||
|
@ -106,16 +116,23 @@ if _os.name in ("nt", "ce"):
|
|||
_FUNCFLAG_STDCALL = _FUNCFLAG_CDECL
|
||||
|
||||
_win_functype_cache = {}
|
||||
def WINFUNCTYPE(restype, *argtypes):
|
||||
def WINFUNCTYPE(restype, *argtypes, **kw):
|
||||
# docstring set later (very similar to CFUNCTYPE.__doc__)
|
||||
flags = _FUNCFLAG_STDCALL
|
||||
if kw.pop("use_errno", False):
|
||||
flags |= _FUNCFLAG_USE_ERRNO
|
||||
if kw.pop("use_last_error", False):
|
||||
flags |= _FUNCFLAG_USE_LASTERROR
|
||||
if kw:
|
||||
raise ValueError("unexpected keyword argument(s) %s" % kw.keys())
|
||||
try:
|
||||
return _win_functype_cache[(restype, argtypes)]
|
||||
return _win_functype_cache[(restype, argtypes, flags)]
|
||||
except KeyError:
|
||||
class WinFunctionType(_CFuncPtr):
|
||||
_argtypes_ = argtypes
|
||||
_restype_ = restype
|
||||
_flags_ = _FUNCFLAG_STDCALL
|
||||
_win_functype_cache[(restype, argtypes)] = WinFunctionType
|
||||
_flags_ = flags
|
||||
_win_functype_cache[(restype, argtypes, flags)] = WinFunctionType
|
||||
return WinFunctionType
|
||||
if WINFUNCTYPE.__doc__:
|
||||
WINFUNCTYPE.__doc__ = CFUNCTYPE.__doc__.replace("CFUNCTYPE", "WINFUNCTYPE")
|
||||
|
@ -124,6 +141,7 @@ elif _os.name == "posix":
|
|||
from _ctypes import dlopen as _dlopen
|
||||
|
||||
from _ctypes import sizeof, byref, addressof, alignment, resize
|
||||
from _ctypes import get_errno, set_errno
|
||||
from _ctypes import _SimpleCData
|
||||
|
||||
def _check_size(typ, typecode=None):
|
||||
|
@ -313,12 +331,24 @@ class CDLL(object):
|
|||
Calling the functions releases the Python GIL during the call and
|
||||
reacquires it afterwards.
|
||||
"""
|
||||
class _FuncPtr(_CFuncPtr):
|
||||
_flags_ = _FUNCFLAG_CDECL
|
||||
_restype_ = c_int # default, can be overridden in instances
|
||||
_func_flags_ = _FUNCFLAG_CDECL
|
||||
_func_restype_ = c_int
|
||||
|
||||
def __init__(self, name, mode=DEFAULT_MODE, handle=None):
|
||||
def __init__(self, name, mode=DEFAULT_MODE, handle=None,
|
||||
use_errno=False,
|
||||
use_last_error=False):
|
||||
self._name = name
|
||||
flags = self._func_flags_
|
||||
if use_errno:
|
||||
flags |= _FUNCFLAG_USE_ERRNO
|
||||
if use_last_error:
|
||||
flags |= _FUNCFLAG_USE_LASTERROR
|
||||
|
||||
class _FuncPtr(_CFuncPtr):
|
||||
_flags_ = flags
|
||||
_restype_ = self._func_restype_
|
||||
self._FuncPtr = _FuncPtr
|
||||
|
||||
if handle is None:
|
||||
self._handle = _dlopen(self._name, mode)
|
||||
else:
|
||||
|
@ -348,9 +378,7 @@ class PyDLL(CDLL):
|
|||
access Python API functions. The GIL is not released, and
|
||||
Python exceptions are handled correctly.
|
||||
"""
|
||||
class _FuncPtr(_CFuncPtr):
|
||||
_flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
|
||||
_restype_ = c_int # default, can be overridden in instances
|
||||
_func_flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
|
||||
|
||||
if _os.name in ("nt", "ce"):
|
||||
|
||||
|
@ -358,9 +386,7 @@ if _os.name in ("nt", "ce"):
|
|||
"""This class represents a dll exporting functions using the
|
||||
Windows stdcall calling convention.
|
||||
"""
|
||||
class _FuncPtr(_CFuncPtr):
|
||||
_flags_ = _FUNCFLAG_STDCALL
|
||||
_restype_ = c_int # default, can be overridden in instances
|
||||
_func_flags_ = _FUNCFLAG_STDCALL
|
||||
|
||||
# XXX Hm, what about HRESULT as normal parameter?
|
||||
# Mustn't it derive from c_long then?
|
||||
|
@ -384,9 +410,8 @@ if _os.name in ("nt", "ce"):
|
|||
HRESULT error values are automatically raised as WindowsError
|
||||
exceptions.
|
||||
"""
|
||||
class _FuncPtr(_CFuncPtr):
|
||||
_flags_ = _FUNCFLAG_STDCALL
|
||||
_restype_ = HRESULT
|
||||
_func_flags_ = _FUNCFLAG_STDCALL
|
||||
_func_restype_ = HRESULT
|
||||
|
||||
class LibraryLoader(object):
|
||||
def __init__(self, dlltype):
|
||||
|
@ -424,6 +449,7 @@ if _os.name in ("nt", "ce"):
|
|||
GetLastError = windll.kernel32.GetLastError
|
||||
else:
|
||||
GetLastError = windll.coredll.GetLastError
|
||||
from _ctypes import get_last_error, set_last_error
|
||||
|
||||
def WinError(code=None, descr=None):
|
||||
if code is None:
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
import unittest, os, errno
|
||||
from ctypes import *
|
||||
from ctypes.util import find_library
|
||||
import threading
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
def test_open(self):
|
||||
libc_name = find_library("c")
|
||||
if libc_name is not None:
|
||||
libc = CDLL(libc_name, use_errno=True)
|
||||
if os.name == "nt":
|
||||
libc_open = libc._open
|
||||
else:
|
||||
libc_open = libc.open
|
||||
|
||||
libc_open.argtypes = c_char_p, c_int
|
||||
|
||||
self.failUnlessEqual(libc_open("", 0), -1)
|
||||
self.failUnlessEqual(get_errno(), errno.ENOENT)
|
||||
|
||||
self.failUnlessEqual(set_errno(32), errno.ENOENT)
|
||||
self.failUnlessEqual(get_errno(), 32)
|
||||
|
||||
|
||||
def _worker():
|
||||
set_errno(0)
|
||||
|
||||
libc = CDLL(libc_name, use_errno=False)
|
||||
if os.name == "nt":
|
||||
libc_open = libc._open
|
||||
else:
|
||||
libc_open = libc.open
|
||||
libc_open.argtypes = c_char_p, c_int
|
||||
self.failUnlessEqual(libc_open("", 0), -1)
|
||||
self.failUnlessEqual(get_errno(), 0)
|
||||
|
||||
t = threading.Thread(target=_worker)
|
||||
t.start()
|
||||
t.join()
|
||||
|
||||
self.failUnlessEqual(get_errno(), 32)
|
||||
set_errno(0)
|
||||
|
||||
if os.name == "nt":
|
||||
|
||||
def test_GetLastError(self):
|
||||
dll = WinDLL("kernel32", use_last_error=True)
|
||||
GetModuleHandle = dll.GetModuleHandleA
|
||||
GetModuleHandle.argtypes = [c_wchar_p]
|
||||
|
||||
self.failUnlessEqual(0, GetModuleHandle("foo"))
|
||||
self.failUnlessEqual(get_last_error(), 126)
|
||||
|
||||
self.failUnlessEqual(set_last_error(32), 126)
|
||||
self.failUnlessEqual(get_last_error(), 32)
|
||||
|
||||
def _worker():
|
||||
set_last_error(0)
|
||||
|
||||
dll = WinDLL("kernel32", use_last_error=False)
|
||||
GetModuleHandle = dll.GetModuleHandleW
|
||||
GetModuleHandle.argtypes = [c_wchar_p]
|
||||
GetModuleHandle("bar")
|
||||
|
||||
self.failUnlessEqual(get_last_error(), 0)
|
||||
|
||||
t = threading.Thread(target=_worker)
|
||||
t.start()
|
||||
t.join()
|
||||
|
||||
self.failUnlessEqual(get_last_error(), 32)
|
||||
|
||||
set_last_error(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
|
@ -72,6 +72,9 @@ Extension Modules
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #1798: Add ctypes calling convention that allows safe access
|
||||
to errno.
|
||||
|
||||
- Patch #2125: Add GetInteger and GetString methods for
|
||||
msilib.Record objects.
|
||||
|
||||
|
|
|
@ -3271,7 +3271,7 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
thunk = AllocFunctionCallback(callable,
|
||||
dict->argtypes,
|
||||
dict->restype,
|
||||
dict->flags & FUNCFLAG_CDECL);
|
||||
dict->flags);
|
||||
if (!thunk)
|
||||
return NULL;
|
||||
|
||||
|
@ -5273,6 +5273,17 @@ init_ctypes(void)
|
|||
if (!m)
|
||||
return;
|
||||
|
||||
#ifdef MS_WIN32
|
||||
dwTlsIndex_LastError = TlsAlloc();
|
||||
dwTlsIndex_errno = TlsAlloc();
|
||||
if (dwTlsIndex_LastError == TLS_OUT_OF_INDEXES
|
||||
|| dwTlsIndex_errno == TLS_OUT_OF_INDEXES) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Could not allocate TLSIndex for LastError value");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
_pointer_type_cache = PyDict_New();
|
||||
if (_pointer_type_cache == NULL)
|
||||
return;
|
||||
|
@ -5394,6 +5405,8 @@ init_ctypes(void)
|
|||
PyModule_AddObject(m, "FUNCFLAG_STDCALL", PyInt_FromLong(FUNCFLAG_STDCALL));
|
||||
#endif
|
||||
PyModule_AddObject(m, "FUNCFLAG_CDECL", PyInt_FromLong(FUNCFLAG_CDECL));
|
||||
PyModule_AddObject(m, "FUNCFLAG_USE_ERRNO", PyInt_FromLong(FUNCFLAG_USE_ERRNO));
|
||||
PyModule_AddObject(m, "FUNCFLAG_USE_LASTERROR", PyInt_FromLong(FUNCFLAG_USE_LASTERROR));
|
||||
PyModule_AddObject(m, "FUNCFLAG_PYTHONAPI", PyInt_FromLong(FUNCFLAG_PYTHONAPI));
|
||||
PyModule_AddStringConstant(m, "__version__", "1.1.0");
|
||||
|
||||
|
|
|
@ -189,6 +189,7 @@ static void _CallPythonObject(void *mem,
|
|||
SETFUNC setfunc,
|
||||
PyObject *callable,
|
||||
PyObject *converters,
|
||||
int flags,
|
||||
void **pArgs)
|
||||
{
|
||||
Py_ssize_t i;
|
||||
|
@ -271,8 +272,22 @@ static void _CallPythonObject(void *mem,
|
|||
#define CHECK(what, x) \
|
||||
if (x == NULL) _AddTraceback(what, "_ctypes/callbacks.c", __LINE__ - 1), PyErr_Print()
|
||||
|
||||
if (flags & FUNCFLAG_USE_ERRNO)
|
||||
_swap_errno();
|
||||
#ifdef MS_WIN32
|
||||
if (flags & FUNCFLAG_USE_LASTERROR)
|
||||
_swap_last_error();
|
||||
#endif
|
||||
|
||||
result = PyObject_CallObject(callable, arglist);
|
||||
CHECK("'calling callback function'", result);
|
||||
|
||||
#ifdef MS_WIN32
|
||||
if (flags & FUNCFLAG_USE_LASTERROR)
|
||||
_swap_last_error();
|
||||
#endif
|
||||
if (flags & FUNCFLAG_USE_ERRNO)
|
||||
_swap_errno();
|
||||
if ((restype != &ffi_type_void) && result) {
|
||||
PyObject *keep;
|
||||
assert(setfunc);
|
||||
|
@ -322,6 +337,7 @@ static void closure_fcn(ffi_cif *cif,
|
|||
p->setfunc,
|
||||
p->callable,
|
||||
p->converters,
|
||||
p->flags,
|
||||
args);
|
||||
}
|
||||
|
||||
|
@ -351,7 +367,7 @@ static CThunkObject* CThunkObject_new(Py_ssize_t nArgs)
|
|||
CThunkObject *AllocFunctionCallback(PyObject *callable,
|
||||
PyObject *converters,
|
||||
PyObject *restype,
|
||||
int is_cdecl)
|
||||
int flags)
|
||||
{
|
||||
int result;
|
||||
CThunkObject *p;
|
||||
|
@ -371,6 +387,7 @@ CThunkObject *AllocFunctionCallback(PyObject *callable,
|
|||
goto error;
|
||||
}
|
||||
|
||||
p->flags = flags;
|
||||
for (i = 0; i < nArgs; ++i) {
|
||||
PyObject *cnv = PySequence_GetItem(converters, i);
|
||||
if (cnv == NULL)
|
||||
|
@ -398,7 +415,7 @@ CThunkObject *AllocFunctionCallback(PyObject *callable,
|
|||
|
||||
cc = FFI_DEFAULT_ABI;
|
||||
#if defined(MS_WIN32) && !defined(_WIN32_WCE) && !defined(MS_WIN64)
|
||||
if (is_cdecl == 0)
|
||||
if ((flags & FUNCFLAG_CDECL) == 0)
|
||||
cc = FFI_STDCALL;
|
||||
#endif
|
||||
result = ffi_prep_cif(&p->cif, cc,
|
||||
|
|
|
@ -83,6 +83,131 @@
|
|||
#define DONT_USE_SEH
|
||||
#endif
|
||||
|
||||
/*
|
||||
ctypes maintains a module-global, but thread-local, variable that contains
|
||||
an error number; called 'ctypes_errno' for this discussion. This variable
|
||||
is a private copy of the systems 'errno' value; the copy is swapped with the
|
||||
'errno' variable on several occasions.
|
||||
|
||||
Foreign functions created with CDLL(..., use_errno=True), when called, swap
|
||||
the values just before the actual function call, and swapped again
|
||||
immediately afterwards. The 'use_errno' parameter defaults to False, in
|
||||
this case 'ctypes_errno' is not touched.
|
||||
|
||||
The values are also swapped immeditately before and after ctypes callback
|
||||
functions are called, if the callbacks are constructed using the new
|
||||
optional use_errno parameter set to True: CFUNCTYPE(..., use_errno=TRUE) or
|
||||
WINFUNCTYPE(..., use_errno=True).
|
||||
|
||||
Two new ctypes functions are provided to access the 'ctypes_errno' value
|
||||
from Python:
|
||||
|
||||
- ctypes.set_errno(value) sets ctypes_errno to 'value', the previous
|
||||
ctypes_errno value is returned.
|
||||
|
||||
- ctypes.get_errno() returns the current ctypes_errno value.
|
||||
|
||||
---
|
||||
|
||||
On Windows, the same scheme is implemented for the error value which is
|
||||
managed by the GetLastError() and SetLastError() windows api calls.
|
||||
|
||||
The ctypes functions are 'ctypes.set_last_error(value)' and
|
||||
'ctypes.get_last_error()', the CDLL and WinDLL optional parameter is named
|
||||
'use_last_error', defaults to False.
|
||||
|
||||
---
|
||||
|
||||
On Windows, TlsSetValue and TlsGetValue calls are used to provide thread
|
||||
local storage for the variables; ctypes compiled with __GNUC__ uses __thread
|
||||
variables.
|
||||
*/
|
||||
|
||||
#if defined(MS_WIN32)
|
||||
DWORD dwTlsIndex_LastError;
|
||||
DWORD dwTlsIndex_errno;
|
||||
|
||||
void
|
||||
_swap_last_error(void)
|
||||
{
|
||||
DWORD temp = GetLastError();
|
||||
SetLastError((DWORD)TlsGetValue(dwTlsIndex_LastError));
|
||||
TlsSetValue(dwTlsIndex_LastError, (void *)temp);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
get_last_error(PyObject *self, PyObject *args)
|
||||
{
|
||||
return PyInt_FromLong((DWORD)TlsGetValue(dwTlsIndex_LastError));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
set_last_error(PyObject *self, PyObject *args)
|
||||
{
|
||||
DWORD new_value, prev_value;
|
||||
if (!PyArg_ParseTuple(args, "i", &new_value))
|
||||
return NULL;
|
||||
prev_value = (DWORD)TlsGetValue(dwTlsIndex_LastError);
|
||||
TlsSetValue(dwTlsIndex_LastError, (void *)new_value);
|
||||
return PyInt_FromLong(prev_value);
|
||||
}
|
||||
|
||||
void
|
||||
_swap_errno(void)
|
||||
{
|
||||
int temp = errno;
|
||||
errno = (int)TlsGetValue(dwTlsIndex_errno);
|
||||
TlsSetValue(dwTlsIndex_errno, (void *)temp);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
get_errno(PyObject *self, PyObject *args)
|
||||
{
|
||||
return PyInt_FromLong((int)TlsGetValue(dwTlsIndex_errno));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
set_errno(PyObject *self, PyObject *args)
|
||||
{
|
||||
int new_value, prev_value;
|
||||
if (!PyArg_ParseTuple(args, "i", &new_value))
|
||||
return NULL;
|
||||
prev_value = (int)TlsGetValue(dwTlsIndex_errno);
|
||||
TlsSetValue(dwTlsIndex_errno, (void *)new_value);
|
||||
return PyInt_FromLong(prev_value);
|
||||
}
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
static __thread int ctypes_errno;
|
||||
|
||||
void
|
||||
_swap_errno(void)
|
||||
{
|
||||
int temp = errno;
|
||||
errno = ctypes_errno;
|
||||
ctypes_errno = temp;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
get_errno(PyObject *self, PyObject *args)
|
||||
{
|
||||
return PyInt_FromLong(ctypes_errno);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
set_errno(PyObject *self, PyObject *args)
|
||||
{
|
||||
int new_errno;
|
||||
if (!PyArg_ParseTuple(args, "i", &new_errno))
|
||||
return NULL;
|
||||
return PyInt_FromLong(_save_errno(new_errno));
|
||||
}
|
||||
#else
|
||||
|
||||
#error "TLS not implemented in this configuration"
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MS_WIN32
|
||||
PyObject *ComError;
|
||||
|
||||
|
@ -660,7 +785,11 @@ static int _call_function_pointer(int flags,
|
|||
if ((flags & FUNCFLAG_PYTHONAPI) == 0)
|
||||
Py_UNBLOCK_THREADS
|
||||
#endif
|
||||
if (flags & FUNCFLAG_USE_ERRNO)
|
||||
_swap_errno();
|
||||
#ifdef MS_WIN32
|
||||
if (flags & FUNCFLAG_USE_LASTERROR)
|
||||
_swap_last_error();
|
||||
#ifndef DONT_USE_SEH
|
||||
__try {
|
||||
#endif
|
||||
|
@ -675,7 +804,11 @@ static int _call_function_pointer(int flags,
|
|||
;
|
||||
}
|
||||
#endif
|
||||
if (flags & FUNCFLAG_USE_LASTERROR)
|
||||
_swap_last_error();
|
||||
#endif
|
||||
if (flags & FUNCFLAG_USE_ERRNO)
|
||||
_swap_errno();
|
||||
#ifdef WITH_THREAD
|
||||
if ((flags & FUNCFLAG_PYTHONAPI) == 0)
|
||||
Py_BLOCK_THREADS
|
||||
|
@ -1667,6 +1800,8 @@ pointer(PyObject *self, PyObject *arg)
|
|||
}
|
||||
|
||||
PyMethodDef module_methods[] = {
|
||||
{"get_errno", get_errno, METH_NOARGS},
|
||||
{"set_errno", set_errno, METH_VARARGS},
|
||||
{"POINTER", POINTER, METH_O },
|
||||
{"pointer", pointer, METH_O },
|
||||
{"_unpickle", unpickle, METH_VARARGS },
|
||||
|
@ -1675,6 +1810,8 @@ PyMethodDef module_methods[] = {
|
|||
{"set_conversion_mode", set_conversion_mode, METH_VARARGS, set_conversion_mode_doc},
|
||||
#endif
|
||||
#ifdef MS_WIN32
|
||||
{"get_last_error", get_last_error, METH_NOARGS},
|
||||
{"set_last_error", set_last_error, METH_VARARGS},
|
||||
{"CopyComPointer", copy_com_pointer, METH_VARARGS, copy_com_pointer_doc},
|
||||
{"FormatError", format_error, METH_VARARGS, format_error_doc},
|
||||
{"LoadLibrary", load_library, METH_VARARGS, load_library_doc},
|
||||
|
|
|
@ -87,6 +87,7 @@ typedef struct {
|
|||
PyObject_VAR_HEAD
|
||||
ffi_closure *pcl; /* the C callable */
|
||||
ffi_cif cif;
|
||||
int flags;
|
||||
PyObject *converters;
|
||||
PyObject *callable;
|
||||
PyObject *restype;
|
||||
|
@ -185,7 +186,7 @@ extern PyMethodDef module_methods[];
|
|||
extern CThunkObject *AllocFunctionCallback(PyObject *callable,
|
||||
PyObject *converters,
|
||||
PyObject *restype,
|
||||
int stdcall);
|
||||
int flags);
|
||||
/* a table entry describing a predefined ctypes type */
|
||||
struct fielddesc {
|
||||
char code;
|
||||
|
@ -303,6 +304,8 @@ PyObject *_CallProc(PPROC pProc,
|
|||
#define FUNCFLAG_CDECL 0x1
|
||||
#define FUNCFLAG_HRESULT 0x2
|
||||
#define FUNCFLAG_PYTHONAPI 0x4
|
||||
#define FUNCFLAG_USE_ERRNO 0x8
|
||||
#define FUNCFLAG_USE_LASTERROR 0x10
|
||||
|
||||
#define TYPEFLAG_ISPOINTER 0x100
|
||||
#define TYPEFLAG_HASPOINTER 0x200
|
||||
|
@ -421,8 +424,16 @@ extern int IsSimpleSubType(PyObject *obj);
|
|||
|
||||
extern PyObject *_pointer_type_cache;
|
||||
|
||||
extern void _swap_errno(void);
|
||||
|
||||
#ifdef MS_WIN32
|
||||
|
||||
extern void _swap_last_error(void);
|
||||
|
||||
extern PyObject *ComError;
|
||||
|
||||
extern DWORD dwTlsIndex_LastError;
|
||||
extern DWORD dwTlsIndex_errno;
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue