[pypy-commit] cffi default: Add ffi.getwinerror().
arigo
noreply at buildbot.pypy.org
Tue Nov 12 13:48:33 CET 2013
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r1412:8a16eff7850c
Date: 2013-11-12 13:48 +0100
http://bitbucket.org/cffi/cffi/changeset/8a16eff7850c/
Log: Add ffi.getwinerror().
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -5227,6 +5227,9 @@
{"set_errno", b_set_errno, METH_VARARGS},
{"newp_handle", b_newp_handle, METH_VARARGS},
{"from_handle", b_from_handle, METH_O},
+#ifdef MS_WIN32
+ {"getwinerror", b_getwinerror, METH_VARARGS},
+#endif
{"_get_types", b__get_types, METH_NOARGS},
{"_testfunc", b__testfunc, METH_VARARGS},
{NULL, NULL} /* Sentinel */
diff --git a/c/misc_win32.h b/c/misc_win32.h
--- a/c/misc_win32.h
+++ b/c/misc_win32.h
@@ -80,6 +80,54 @@
/* else: cannot report the error */
}
+static PyObject *b_getwinerror(PyObject *self, PyObject *args)
+{
+ int err = -1;
+ int len;
+ char *s;
+ char *s_buf = NULL; /* Free via LocalFree */
+ char s_small_buf[28]; /* Room for "Windows Error 0xFFFFFFFF" */
+ PyObject *v;
+
+ if (!PyArg_ParseTuple(args, "|i", &err))
+ return NULL;
+
+ if (err == -1) {
+ struct cffi_errno_s *p;
+ p = _geterrno_object();
+ if (p == NULL)
+ return PyErr_NoMemory();
+ err = p->saved_lasterror;
+ }
+
+ len = FormatMessage(
+ /* Error API error */
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, /* no message source */
+ err,
+ MAKELANGID(LANG_NEUTRAL,
+ SUBLANG_DEFAULT), /* Default language */
+ (LPTSTR) &s_buf,
+ 0, /* size not used */
+ NULL); /* no args */
+ if (len==0) {
+ /* Only seen this in out of mem situations */
+ sprintf(s_small_buf, "Windows Error 0x%X", err);
+ s = s_small_buf;
+ s_buf = NULL;
+ } else {
+ s = s_buf;
+ /* remove trailing cr/lf and dots */
+ while (len > 0 && (s[len-1] <= ' ' || s[len-1] == '.'))
+ s[--len] = '\0';
+ }
+ v = Py_BuildValue("(is)", err, s);
+ LocalFree(s_buf);
+ return v;
+}
+
/************************************************************/
/* Emulate dlopen()&co. from the Windows API */
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -2698,6 +2698,16 @@
#
res = GetLastError()
assert res == 42
+ #
+ SetLastError(2)
+ code, message = getwinerror()
+ assert code == 2
+ assert message == "The system cannot find the file specified"
+ #
+ code, message = getwinerror(1155)
+ assert code == 1155
+ assert message == ("No application is associated with the "
+ "specified file for this operation")
def test_nonstandard_integer_types():
for typename in ['int8_t', 'uint8_t', 'int16_t', 'uint16_t', 'int32_t',
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -347,6 +347,9 @@
errno = property(_get_errno, _set_errno, None,
"the value of 'errno' from/to the C calls")
+ def getwinerror(self, code=-1):
+ return self._backend.getwinerror(code)
+
def _pointer_to(self, ctype):
from . import model
with self._lock:
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -1122,9 +1122,18 @@
``ffi.errno``: the value of ``errno`` received from the most recent C call
in this thread, and passed to the following C call, is available via
-reads and writes of the property ``ffi.errno``. On Windows we also save
-and restore the ``GetLastError()`` value, but to access it you need to
-declare and call the ``GetLastError()`` function as usual.
+reads and writes of the property ``ffi.errno``.
+
+``ffi.getwinerror(code=-1)``: on Windows, in addition to ``errno`` we
+also save and restore the ``GetLastError()`` value across function
+calls. This function returns this error code as a tuple ``(code,
+message)``, adding a readable message like Python does when raising
+WindowsError. If the argument ``code`` is given, format that code into
+a message instead of using ``GetLastError()``. *New in version 0.8.*
+(Note that it is also possible to declare and call the ``GetLastError()``
+function as usual.)
+
+.. "versionadded:: 0.8" --- inlined in the previous paragraph
``ffi.string(cdata, [maxlen])``: return a Python string (or unicode
string) from the 'cdata'. *New in version 0.3.*
diff --git a/testing/test_ffi_backend.py b/testing/test_ffi_backend.py
--- a/testing/test_ffi_backend.py
+++ b/testing/test_ffi_backend.py
@@ -194,3 +194,20 @@
assert p.a[0] == 200
assert p.a[1] == 300
assert p.a[2] == 400
+
+ @pytest.mark.skipif("sys.platform != 'win32'")
+ def test_getwinerror(self):
+ ffi = FFI()
+ code, message = ffi.getwinerror(1155)
+ assert code == 1155
+ assert message == ("No application is associated with the "
+ "specified file for this operation")
+ ffi.cdef("void SetLastError(int);")
+ lib = ffi.dlopen("Kernel32.dll")
+ lib.SetLastError(2)
+ code, message = ffi.getwinerror()
+ assert code == 2
+ assert message == "The system cannot find the file specified"
+ code, message = ffi.getwinerror(-1)
+ assert code == 2
+ assert message == "The system cannot find the file specified"
More information about the pypy-commit
mailing list