The ctypes module
"ctypes home":../ctypes.html :: tutorial :: "reference":reference.html :: "faq":faq.html
"'ctypes'":../ctypes.html is a Python module allowing to create and
manipulate C data types in Python. These can then be passed to
C-functions loaded from dynamic link libraries.
For background information about the C data types, see also
"Standard C Types":http://www-ccs.ucsd.edu/c/types.html at UCSD
(external link).
For details about common operations on these types, see "ctypes
reference":reference.html
Purpose
The purpose of this module is to be a greatly enhanced and much
more complete replacement of Sam Rushing's calldll/npstruct/windll
modules. 'ctypes' is not based on Sam's work, it has different
roots.
Requirements
Internally 'ctypes' makes heavy use of the new type system
introduced in Python 2.2, so it will not work in earlier versions.
Loading dynamic link libraries into Python
'ctypes' exports the objects 'windll', 'cdll' and 'oledll' to load
dynamic link libraries.
You can load libraries by retrieving them as attributes. 'cdll'
loads libraries which export functions using the 'cdecl' calling
convention, while 'windll' libraries call functions using the
'stdcall' calling convention. 'oledll' also uses the 'stdcall'
calling convention, and assumes the functions return a Windows
'HRESULT'. These are used to automatically raise 'WindowsError'
Python exceptions when the function call failes.
Here are some examples::
>>> from ctypes import windll, cdll
>>> print windll.kernel32
>>> print cdll.msvcrt
Retrieving functions from loaded dlls
Functions are (lazily) exposed as attributes of dlls::
>>> from ctypes import windll, cdll
>>> print cdll.msvcrt.printf
<_cdecl_Function 'printf', address 78025147 at 80a2b0>
>>> print windll.kernel32.GetModuleHandleA
<_stdcall_Function 'GetModuleHandleA', address 77e8380e at 7e95b8>
>>> print windll.kernel32.MyOwnFunction
Traceback (most recent last):
File "", line 1, in ?
File "ctypes.py", line 179, in __getattr__
func = DynFunction(name, self, 0)
ValueError: function 'MyOwnFunction' not found
Note that win32 system dlls like 'kernel32', 'user32', and others,
sometimes expose ANSI as well as UNICODE versions of
functions. The UNICODE version is exposed with an 'W' appended to
the name, while the ANSI version is exposed with an 'A' appended
to the name. The win32 'GetModuleHandle' function, which returns a
*module handle* for a given module name, has these C prototypes::
/* ANSI version */
HMODULE GetModuleHandleA(LPCSTR lpModuleName);
/* UNICODE version */
HMODULE GetModuleHandleW(LPCWSTR lpModuleName);
'windll' does not try to hide these differences, you must load the
version you need explicitely by specifying 'GetModuleHandleA' or
'GetModuleHandleW' explicitely, and call them with normal strings
or unicode strings respectively.
Sometimes, dlls export functions with names which aren't valid
Python identifiers, like '"??2@YAPAXI@Z"'. In this case you have
to use 'getattr' to retrieve the function::
>>> getattr(cdll.msvcrt, "??2@YAPAXI@Z")
<_ctypes.ExportedFunction object at 0x007A60E0>
>>>
Calling functions
You can call these functions like any other Python callable. This
example uses the 'time()' function, which returns system time in
seconds since the UNIX epoch, and the 'GetModuleHandleA()'
function, which returns a win32 module handle.
This example calls both functions with a NULL pointer::
>>> from ctypes import cdll, windll
>>> print cdll.msvcrt.time(0)
1022091405
>>> print hex(windll.kernel32.GetModuleHandleA(0))
0x1d000000
'ctypes' tries at its best to protect you from calling functions
with the wrong number of arguments. It does this by examining the
stack after the function returns::
>>> windll.kernel32.GetModuleHandleA()
Traceback (most recent call last):
File "", line 1, in ?
ValueError: Procedure probably called with not enough arguments
>>> windll.kernel32.GetModuleHandleA(0, 0)
Traceback (most recent call last):
File "", line 1, in ?
ValueError: Procedure probably called with too many arguments
>>>
'ctypes' uses win32 structured exception handling to prevent
crashes from general protection faults when functions are called
with invalid argument values::
>>> windll.kernel32.GetModuleHandleA(32)
Traceback (most recent call last):
File "", line 1, in ?
WindowsError: exception: access violation
>>>
There are, however, enough ways to crash Python with 'ctypes',
so you should be careful.
Calling functions with integers, strings and unicode strings
Python integers, strings and unicode strings are the only Python
objects that may directly be used as parameters in C API calls.
Examples (please note that printf prints to the real standard
output channel, *not* to 'sys.stdout', so these examples will only
work at the console prompt, not from within *idle* or *PythonWin*)::
>>> from ctypes import cdll; msvcrt = cdll.msvcrt
>>> msvcrt.printf("Hello, %s\n", "World!")
Hello, World!
14
>>> msvcrt.printf("Hello, %S", u"World!") # Note the upper case S!
Hello, World!
14
>>> msvcrt.printf("%d bottles of beer\n", 42)
42 bottles of beer
19
>>> msvcrt.printf("%f bottles of beer\n", 42.5)
Traceback (most recent call last):
File "", line 1, in ?
TypeError: Don't know how to convert parameter 2
>>>
Calling functions with other simple Python data types
Python floats have to be wrapped in 'c_float()' or
'c_double()' calls, so that they can be converted to the
correct C data type (float or double)::
>>> from ctypes import cdll, c_double
>>> printf = cdll.msvcrt.printf
>>> printf("An int %d, a double %f\n", 1234, c_double(3.14))
Integer 1234, double 3.1400001049
34
>>>
Wrapping Python numbers in 'c_double' or 'c_float' objects create
*mutable* C data types. There are also other wrappers like
'c_int', 'c_string', and more. The current value of all these
objects can be read and written from Python as the 'value'
property.
Calling functions with your own custom data types
XXX explain the required _as_parameter_ property
Specifying required argument types
It is possible to specify the required argument types of functions
exported from DLLs by assigning the 'argtypes' attribute. This
must be set to a list of C data types (note that 'printf' is a bad
example here, because it takes a variable number and different
types of parameters depending on the format string)::
>>> from ctypes import cdll, c_int, c_string, c_double
>>> printf = cdll.msvcrt.printf
>>> printf.argtypes = [c_string, c_string, c_int, c_double]
>>> printf("String '%s', Int %d, Double %f\n", "Hi", 10, 2.2)
String 'Hi', Int 10, Double 2.200000
Specifying a format protects against incompatible argument types
(just as a prototype for a C function), and tries to convert the
arguments to valid types::
>>> printf("%d %d %d", 1, 2, 3)
Traceback (most recent call last):
File "", line 1, in ?
TypeError: argument 2 must be string, not int
>>> printf("%s %d %f", "X", 2, 3)
X 2 3.000000
13
>>>
XXX Explain this for other C datatypes (Structures, Pointers)
XXX How to specify other Python datatypes: requires a from_param
classmethod
Return types
XXX Move this after the 'Passing parameters by reference section'?
By default functions are assumed to return integers. A different
return type can be specified by setting the 'restype' attribute of
the function object.
Allowed values are the single character strings '"i"', '"d"', '"f"',
'"s"', which specify the C 'int', 'double', 'float', and 'char *'
data types, and pointers to other data types::
>>> from ctypes import c_string, byref, cdll
>>> strchr = cdll.msvcrt.strchr
>>> strchr("abcdef", ord("d"))
8059983
>>> strchr.restype = "s"
>>> strchr("abcdef", ord("d"))
'def'
>>> print strchr("abcdef", ord("x"))
None
>>>
If you want to avoid the 'ord("x")' calls above, you can also use
the 'c_char' datatype::
>>> from ctypes import c_char, c_string, byref, cdll
>>> msvcrt = cdll.msvcrt
>>> msvcrt.strchr.restype = "s"
>>> msvcrt.strchr.argtypes = [c_string, c_char]
>>> msvcrt.strchr("abcdef", "d")
'def'
>>> msvcrt.strchr("abcdef", "def")
Traceback (most recent call last):
File "", line 1, in ?
TypeError: one character string expected
>>> print msvcrt.strchr("abcdef", "x")
None
>>>
**New in version 0.2.0**: you can use a callable Python object (a
function, a class, a class-method) and assign it to the 'restype'
attribute. This callable will be called with the integer the C
function returns, and the result of this call will be used as the
result of the function call. This is useful to check for error
return values and automatically raise an exception::
>>> from ctypes import windll, WinError
>>> GetModuleHandle = windll.kernel32.GetModuleHandleA
>>> def ValidHandle(value):
... if value == 0:
... raise WinError()
... return value
...
>>>
>>> GetModuleHandle.restype = ValidHandle
>>> GetModuleHandle(None)
486539264
>>> GetModuleHandle("something silly")
Traceback (most recent call last):
File "", line 1, in ?
File "", line 3, in ValidHandle
WindowsError: [Errno 126] The specified module could not be found.
>>>
'WinError' is a function which will call Windows' FormatMessage
api to get the string representation of an error code. 'WinError'
takes an optional error code parameter, if none is used, it calls
'GetLastError' to retrieve it.
Passing parameters by reference
Sometimes a C api function expects a *pointer* to simple data type
as parameter, and the C function writes into the corresponding
location. This is also known as *passing parameters by reference*.
Lightweight pointers are created by calling 'byref(obj)' ::
>>> from ctypes import c_int, c_float, c_string, byref, cdll
>>> msvcrt = cdll("msvcrt")
>>> i = c_int()
>>> f = c_float()
>>> s = c_string('\000' * 32)
>>> print i.value, f.value, repr(s.value)
0 0.0 ''
>>> msvcrt.sscanf("1 3.14 Hello", "%d %f %s",
... byref(i), byref(f), s)
3
>>> print i.value, f.value, repr(s.value)
1 3.1400001049 'Hello'
Beware: 'byref()' creates a lightweight pointer, which should only
be used to pass a parameter by reference to an API call. Full
pointers can also be created with 'ctypes', read on.
COM
to be written. In short: You *can* call methods on COM objects,
you can even *implement* and expose COM objects.
For now, see the 'test' directory of the source distribution for
examples.
Structures and Unions
Structures and unions must derive from the 'Structure' and 'Union'
base classes which are defined in the 'ctypes' module. Each
subclass must define a '_fields_' attribute. '_fields_' must be a
list of *2-tuples*, containing a *field name* and a *field type*.
Field names are strings denoting the name of the fields, field
types can be a format character specifying the type of the field
in a similar way as Python's "struct
module":http://www.python.org/doc/current/lib/module-struct.html :
|-----------------------------------------|
|format|C type |Python type |
|=========================================|
|c |char |character |
|-----------------------------------------|
|b |char |integer |
|-----------------------------------------|
|B |unsigned char |integer |
|-----------------------------------------|
|h |short |integer |
|-----------------------------------------|
|H |unsigned short |integer |
|-----------------------------------------|
|i |int |integer |
|-----------------------------------------|
|I |unsigned int |integer |
|-----------------------------------------|
|l |long |integer |
|-----------------------------------------|
|L |unsigned long |long |
|-----------------------------------------|
|q |__int64 |long |
|-----------------------------------------|
|Q |unsigned __int64 |long |
|-----------------------------------------|
|s |char[] |string without|
| | |NUL bytes |
|-----------------------------------------|
|S |char[] |string with |
| | |NUL bytes |
|-----------------------------------------|
|z |char * |string |
|-----------------------------------------|
|Z |wchar_t * |unicode |
|-----------------------------------------|
|w |wchar[] |unicode |
|-----------------------------------------|
The format characters 's', 'S' and 'w' may be preceeded by a
decimal integer, which specifies how many characters this field
contains. If the repeat count is missing, the field width is 1.
Here is a simple example of a POINT structure, which contains two
integers named 'x' and 'y' ::
>>> from ctypes import Structure
>>> class POINT(Structure):
... _fields_ = [("x", "i"),
... ("y", "i")]
...
>>> point = POINT(10, 20)
>>> print point.x, point.y
10 20
>>>
You can, however, build much more complicated
structures. Structures can itself contain other structures by
using a structure as a field type.
Here is a RECT structure which contains two POINTs named
'upperleft' and 'lowerright' ::
>>> class RECT(Structure):
... _fields_ = [("upperleft", POINT),
... ("lowerright", POINT)]
...
>>> rc = RECT(point)
>>> print rc.upperleft.x, rc.upperleft.y
10 20
>>> print rc.lowerright.x, rc.lowerright.y
0 0
>>>
Fields descriptors can be retrieved from the class, they have
readonly 'size' and 'offset' attributes describing the size in
bytes and the offset of this field from the beginning of the
internal memory buffer:
>>> print POINT.x.size, POINT.x.offset
0 4
>>> print POINT.y.size, POINT.y.offset
4 4
>>>
Arrays
Arrays are sequences, containing a fixed number of instances of
the same type.
The "classical" way to create Array classes is by subclassing
'Array', supplying '_type_' and a '_length_' class attributes.
Again, '_type_' must be a Structure subclass or a format character
(with optional length field for 's' or 'S')::
from ctypes import Array
class TenPointsArray(Array):
_type_ = POINT
_length_ = 10
You can also create Array subclasses by multiplying a data type
class with a positive integer::
TenPointsArray = POINT * 10
This is especially useful if you are not interested in the class
itself, only in the instances. Here is an example of an somewhat
artifical data type, a structure containing 4 POINTs among other
stuff::
>>> from ctypes import Structure
>>> class POINT(Structure):
... _fields_ = ("x", "i"), ("y", "i")
...
>>> class MyStruct(Structure):
... _fields_ = [("a", "i"),
... ("b", "f"),
... ("point_array", POINT * 4)]
>>>
>>> print len(MyStruct().point_array)
4
Instances are created in the usual way, by calling the class::
arr = TenPointsArray()
for pt in arr:
print pt.x, pt.y
The above code print a series of '0 0' lines, because the array
contents is initialized to zeros.
Pointers
Note: This section is out of date and needs to be rewritten. In
the meantime refer to the samples in the source distribution for
examples.
Pointers are created by subclassing 'ctypes._Pointer', supplying a
'_type_' class attribute. '_type_' must be a 'Structure' subclass::
from ctypes import _Pointer
class LPINT(_Pointer):
_type_ = c_int
lpint = LPINT()
lpint.contents = c_int(42)
'_Pointer' instances have a 'contents' attribute, which contains the
pointed at value, and can be read and written::
print lpint.contents.value
lpint.contents.value = c_int(3)
lpint.contents.value = "abc" # raises TypeError
A more convenient way to create Pointers is the 'Pointer'
function. Calling 'Pointer' with a *class* returns a '_Pointer'
subclass, calling 'Pointer' with an *instance* returns an instance
of the pointer class pointing to the passed value. If you call
'Pointer'with an instance, a new class is created on the fly::
>>> from ctypes import Pointer, c_int
>>> LPINT = Pointer(c_int)
>>> print LPINT
>>> pi = LPINT(c_int(42))
>>> print pi
>>> pi2 = Pointer(c_int(22))
>>> print pi2
>>> print pi2.__class__
Note that calling Pointer with a class *instance* creates a new
pointer *class* on the fly, and returns an instance of this class.
Structures and Unions (again)
The shorthand notation for creating Pointer and Array subclasses
is very convenient in combination with Structures containing
Pointers or Arrays.
blahg blah
Incomplete Types
*Incomplete Types* are structures, unions or arrays whose members
are not yet specified. In the 'ctypes' context, you can create
Pointers to these types by passing their name (as a string) to the
Pointer function, and complete the _Pointer subclass later.
Consider this example (C-code)::
struct cell;
struct {
int value;
struct cell *next;
} cell;
The straightforward translation into Python would be::
class cell(Structure):
_fields_ = [("value", "i"),
("next", Pointer(cell))]
Unfortunately this will not work - it raises a name error::
Traceback (most recent call last):
File "", line 1, in ?
File "", line 2, in cell
NameError: name 'cell' is not defined
because 'class cell' is not available in the class statement itself.
We can do it by creating an *incomplete _Pointer subclass* by
calling Pointer with the class _name_, and later setting the
complete type of the _Pointer subclass 'lpcell' ::
from ctypes import Structure, Pointer, SetPointerType
lpcell = POINTER("cell")
class cell(Structure):
_fields_ = [("value", "i"),
("next", lpcell)]
SetPointerType(lpcell, cell)
Callback functions
Sometimes, functions expect a function pointer (callback function)
as an argument.
'ctypes' has a 'CFunction' base type, which is used to define and
create function pointers from Python callable objects.
Subclasses must provide a '_types_' attribute, which is a string
containing format specifiers (only 'i' for 'int' and 's' for 'char
*' are currently allowed) for the arguments the function expects
and a '_stdcall_' attribute, which must be '1' to specify the
'__stdcall' calling convention, or '0' to specify '__cdecl'
calling convention.
Instances of function pointers are created by calling the
(sub)class with a *Python callable* as argument. This callable
must return None (which will be interpreted as '0'), or an
integer.
We are now trying to create a C callable function ('callback')
which we can pass to the standard C library 'qsort' function.
'qsort' expects
The following example creates a C callable function ('callback')
usable by the 'qsort' standard library function::
class CMPFUNC(CFunction):
_types_ = 'ii'
_stdcall_ = 1
def compare(adr1, adr2):
return cmp(adr1, adr2)
cmpfunc = CMPFUNC(compare)
Note that the same effect could be achived by this code::
class CMPFUNC(CFunction):
_types_ = 'ii'
_stdcall_ = 0
cmpfunc = CMPFUNC(cmp)
'cmpfunc' will now be a *pointer* to a C callable function with
this signature::
int __cdecl cmpfunc(int, int);
Beware: If you use the 'qsort' standard library function to sort
an array of integers, the 'compare' function will receive
*pointers* into the array, not the array items itself, so the
above code will *not* work with qsort.
To remedy, we must expect *pointers* in the compare function, and
retrieve the actual contents, and compare those.
This code implements a function doing this::
from ctypes import CFunction, c_int
class CMPFUNC(CFunction):
_types_ = "ii"
_stdcall_ = 0
def compare(a1, a2):
v1 = c_int.from_pointer(a1).value
v2 = c_int.from_pointer(a2).value
return cmp(v1, v2)
cmpfunc = CMPFUNC(compare)
Assuming 'ia10' is an array in 10 integers, and '4' is sizeof(int),
we can sort the array contents in this way::
msvcrt.qsort(ia, len(ia), 4, compare)
Surprises
There are some corners in 'ctypes' where you may be expect
something else than what actually happens.
Consider the following example::
>>> from ctypes import Structure
>>> class POINT(Structure):
... _fields_ = ("x", "i"), ("y", "i")
...
>>> class RECT(Structure):
... _fields_ = ("a", POINT), ("b", POINT)
...
>>> p1 = POINT(1, 2)
>>> p2 = POINT(3, 4)
>>> rc = RECT(p1, p2)
>>> print rc.a.x, rc.a.y, rc.b.x, rc.b.y
1 2 3 4
>>> # now swap the two points
>>> rc.a, rc.b = rc.b, rc.a
>>> print rc.a.x, rc.a.y, rc.b.x, rc.b.y
3 4 3 4
Hm. We certainly expected the last statement to print '3 4 1 2'.
What happended? Here are the steps of the 'rc.a, rc.b = rc.b,
rc.a' line above::
>>> temp0, temp1 = rc.b, rc.a
>>> rc.a = temp0
>>> rc.b = temp1
Note that 'temp0' and 'temp1' are objects still using the internal
buffer of the 'rc' object above. So executing 'rc.a = temp0'
copies the buffer contents of 'temp0' into 'rc' 's buffer. This, in turn,
changes the contents of 'temp1'. So, the last assignment 'rc.b = temp1',
doesn't have the expected effect.
Keep in mind that retrieving subobjects from Structure, Unions,
and Arrays doesn't *copy* the subobject, it does more retrieve a
wrapper object accessing the root-object's underlying buffer.
Bugs, ToDo and non-implemented things
Bitfields are not implemented. This probably counts as bug.
Enumeration types are not implemented. I do not consider this as a
bug - they can be implemented as well in pure python (maybe as
'int' subclasses).
What about 'long double'? They exist in MSVC for example, and have
80 bits.
The whole unicode / wchar stuff is not yet implemented - although
it is mentioned above.
C function pointers returning something else than integers (or
void) cannot be constructed. Actually they can return anything
which has sizeof(x) == sizeof(int).