ctypesA foreign function library for PythonPython的外部函数库


ctypes is a foreign function library for Python. 是Python的外部函数库。It provides C compatible data types, and allows calling functions in DLLs or shared libraries. 它提供与C兼容的数据类型,并允许在DLL或共享库中调用函数。It can be used to wrap these libraries in pure Python.它可以用于在纯Python中包装这些库。

ctypes tutorialctypes教程

Note: The code samples in this tutorial use doctest to make sure that they actually work. 注意:本教程中的代码示例使用doctest来确保它们确实有效。Since some code samples behave differently under Linux, Windows, or macOS, they contain doctest directives in comments.由于一些代码示例在Linux、Windows或macOS下的行为不同,因此它们在注释中包含doctest指令。

Note: Some code samples reference the ctypes c_int type. 注意:一些代码示例引用ctypes c_int类型。On platforms where sizeof(long) == sizeof(int) it is an alias to c_long. sizeof(long) == sizeof(int)的平台上,它是c_long的别名。So, you should not be confused if c_long is printed if you would expect c_int — they are actually the same type.因此,如果您希望打印c_int,那么不应该混淆是否打印了c_long-它们实际上是相同的类型。

Accessing functions from loaded dlls从加载的dll访问函数

Functions are accessed as attributes of dll objects:函数作为dll对象的属性进行访问:

>>> from ctypes import *
>>> libc.printf
<_FuncPtr object at 0x...>
>>> print(windll.kernel32.GetModuleHandleA)
<_FuncPtr object at 0x...>
>>> print(windll.kernel32.MyOwnFunction)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "ctypes.py", line 239, in __getattr__
func = _StdcallFuncPtr(name, self)
AttributeError: function 'MyOwnFunction' not found
>>>

Note that win32 system dlls like kernel32 and user32 often export ANSI as well as UNICODE versions of a function. 注意,像kernel32user32这样的win32系统dll通常导出函数的ANSI和UNICODE版本。The UNICODE version is exported with an W appended to the name, while the ANSI version is exported with an A appended to the name. 导出UNICODE版本时,名称后面附加W,而导出ANSI版本时,其名称后面附加AThe win32 GetModuleHandle function, which returns a module handle for a given module name, has the following C prototype, and a macro is used to expose one of them as GetModuleHandle depending on whether UNICODE is defined or not:win32 GetModuleHandle函数返回给定模块名称的模块句柄,该函数具有以下C原型,根据是否定义了UNICODE,使用宏将其中一个原型公开为GetModuleHandle:

/* ANSI version */
HMODULE GetModuleHandleA(LPCSTR lpModuleName);
/* UNICODE version */
HMODULE GetModuleHandleW(LPCWSTR lpModuleName);

windll does not try to select one of them by magic, you must access the version you need by specifying GetModuleHandleA or GetModuleHandleW explicitly, and then call it with bytes or string objects respectively.windll不会尝试通过魔法选择其中一个,您必须通过显式指定GetModuleHandleAGetModuleHandleW来访问所需的版本,然后分别用字节或字符串对象调用它。

Sometimes, dlls export functions with names which aren’t valid Python identifiers, like "??2@YAPAXI@Z". 有时,dll会导出名称不是有效Python标识符的函数,如"??2@YAPAXI@Z"In this case you have to use getattr() to retrieve the function:在这种情况下,您必须使用getattr()来检索函数:

>>> getattr(cdll.msvcrt, "??2@YAPAXI@Z")
<_FuncPtr object at 0x...>
>>>

On Windows, some dlls export functions not by name but by ordinal. 在Windows上,有些dll不是按名称而是按序号导出函数。These functions can be accessed by indexing the dll object with the ordinal number:可以通过使用序号索引dll对象来访问这些函数:

>>> cdll.kernel32[1]
<_FuncPtr object at 0x...>
>>> cdll.kernel32[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "ctypes.py", line 310, in __getitem__
func = _StdcallFuncPtr(name, self)
AttributeError: function ordinal 0 not found
>>>

Calling functions调用函数

You can call these functions like any other Python callable. 您可以像调用任何其他Python可调用函数一样调用这些函数。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.此示例使用time()函数,该函数返回Unix epoch之后的系统时间(以秒为单位),以及GetModuleHandleA()函数(返回win32模块句柄)。

This example calls both functions with a NULL pointer (None should be used as the NULL pointer):此示例使用NULL指针调用这两个函数(应将None用作NULL指针):

>>> print(libc.time(None))
1150640792
>>> print(hex(windll.kernel32.GetModuleHandleA(None)))
0x1d000000
>>>

ValueError is raised when you call an stdcall function with the cdecl calling convention, or vice versa:使用cdecl调用约定调用stdcall函数时,会引发ValueError,反之亦然:

>>> cdll.kernel32.GetModuleHandleA(None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Procedure probably called with not enough arguments (4 bytes missing)
>>>

>>> windll.msvcrt.printf(b"spam")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Procedure probably called with too many arguments (4 bytes in excess)
>>>

To find out the correct calling convention you have to look into the C header file or the documentation for the function you want to call.要找到正确的调用约定,您必须查看C头文件或要调用的函数的文档。

On Windows, ctypes uses win32 structured exception handling to prevent crashes from general protection faults when functions are called with invalid argument values:在Windows上,当使用无效参数值调用函数时,ctypes使用win32结构化异常处理来防止一般保护错误导致的崩溃:

>>> windll.kernel32.GetModuleHandleA(32)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: exception: access violation reading 0x00000020
>>>

There are, however, enough ways to crash Python with ctypes, so you should be careful anyway. 然而,有足够的方法可以用ctypes,使Python崩溃,所以无论如何都应该小心。The faulthandler module can be helpful in debugging crashes (e.g. from segmentation faults produced by erroneous C library calls).faulthandler模块有助于调试崩溃(例如,错误的C库调用产生的分段错误)。

None, integers, bytes objects and (unicode) strings are the only native Python objects that can directly be used as parameters in these function calls. 、整数、字节对象和(unicode)字符串是唯一可以在这些函数调用中直接用作参数的本地Python对象。None is passed as a C NULL pointer, bytes objects and strings are passed as pointer to the memory block that contains their data (char* or wchar_t*). None作为C NULL指针传递,bytes对象和字符串作为指向包含其数据的内存块(char*wchar_t*)的指针传递。Python integers are passed as the platforms default C int type, their value is masked to fit into the C type.Python整数作为平台默认的C int类型传递,它们的值被屏蔽以适应C类型。

Before we move on calling functions with other parameter types, we have to learn more about ctypes data types.在继续使用其他参数类型调用函数之前,我们必须了解更多关于ctypes数据类型的信息。

Fundamental data types基本数据类型

ctypes defines a number of primitive C compatible data types:定义了许多与C兼容的基元数据类型:

ctypes type

C type

Python type

c_bool

_Bool

bool (1)

c_char

char

1-character bytes object

c_wchar

wchar_t

1-character string

c_byte

char

int

c_ubyte

unsigned char

int

c_short

short

int

c_ushort

unsigned short

int

c_int

int

int

c_uint

unsigned int

int

c_long

long

int

c_ulong

unsigned long

int

c_longlong

__int64 or long long

int

c_ulonglong

unsigned __int64 or unsigned long long

int

c_size_t

size_t

int

c_ssize_t

ssize_t or Py_ssize_t

int

c_float

float

float

c_double

double

float

c_longdouble

long double

float

c_char_p

char* (NUL terminated)

bytes object or None

c_wchar_p

wchar_t* (NUL terminated)

string or None

c_void_p

void*

int or None

  1. The constructor accepts any object with a truth value.构造函数接受具有真值的任何对象。

All these types can be created by calling them with an optional initializer of the correct type and value:所有这些类型都可以通过使用正确类型和值的可选初始值设定项来调用它们来创建:

>>> c_int()
c_long(0)
>>> c_wchar_p("Hello, World")
c_wchar_p(140018365411392)
>>> c_ushort(-3)
c_ushort(65533)
>>>

Since these types are mutable, their value can also be changed afterwards:由于这些类型是可变的,因此它们的值也可以在以后更改:

>>> i = c_int(42)
>>> print(i)
c_long(42)
>>> print(i.value)
42
>>> i.value = -99
>>> print(i.value)
-99
>>>

Assigning a new value to instances of the pointer types c_char_p, c_wchar_p, and c_void_p changes the memory location they point to, not the contents of the memory block (of course not, because Python bytes objects are immutable):

>>> s = "Hello, World"
>>> c_s = c_wchar_p(s)
>>> print(c_s)
c_wchar_p(139966785747344)
>>> print(c_s.value)
Hello World
>>> c_s.value = "Hi, there"
>>> print(c_s) # the memory location has changed
c_wchar_p(139966783348904)
>>> print(c_s.value)
Hi, there
>>> print(s) # first object is unchanged
Hello, World
>>>

You should be careful, however, not to pass them to functions expecting pointers to mutable memory. 但是,您应该小心,不要将它们传递给需要指向可变内存的指针的函数。If you need mutable memory blocks, ctypes has a create_string_buffer() function which creates these in various ways. 如果需要可变内存块,ctypes有一个create_string_buffer()函数,可以用各种方式创建这些内存块。The current memory block contents can be accessed (or changed) with the raw property; if you want to access it as NUL terminated string, use the value property:可以使用raw属性访问(或更改)当前内存块内容;如果要将其作为以NUL结尾的字符串进行访问,请使用value属性:

>>> from ctypes import *
>>> p = create_string_buffer(3) # create a 3 byte buffer, initialized to NUL bytes
>>> print(sizeof(p), repr(p.raw))
3 b'\x00\x00\x00'
>>> p = create_string_buffer(b"Hello") # create a buffer containing a NUL terminated string
>>> print(sizeof(p), repr(p.raw))
6 b'Hello\x00'
>>> print(repr(p.value))
b'Hello'
>>> p = create_string_buffer(b"Hello", 10) # create a 10 byte buffer
>>> print(sizeof(p), repr(p.raw))
10 b'Hello\x00\x00\x00\x00\x00'
>>> p.value = b"Hi"
>>> print(sizeof(p), repr(p.raw))
10 b'Hi\x00lo\x00\x00\x00\x00\x00'
>>>

The create_string_buffer() function replaces the c_buffer() function (which is still available as an alias), as well as the c_string() function from earlier ctypes releases. create_string_buffer()函数替换了c_buffers()函数(它仍然作为别名可用),以及早期ctypes发行版中的c_string()函数。To create a mutable memory block containing unicode characters of the C type wchar_t use the create_unicode_buffer() function.要创建包含C类型wchar_t的unicode字符的可变内存块,请使用create_unicode_buffer()函数。

Calling functions, continued调用函数(续)

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:请注意,printf打印到真正的标准输出通道,而不是sys.stdout,因此这些示例只能在控制台提示符下起作用,而不能在IDLEPythonWin中起作用:

>>> printf = libc.printf
>>> printf(b"Hello, %s\n", b"World!")
Hello, World!
14
>>> printf(b"Hello, %S\n", "World!")
Hello, World!
14
>>> printf(b"%d bottles of beer\n", 42)
42 bottles of beer
19
>>> printf(b"%f bottles of beer\n", 42.5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ArgumentError: argument 2: exceptions.TypeError: Don't know how to convert parameter 2
>>>

As has been mentioned before, all Python types except integers, strings, and bytes objects have to be wrapped in their corresponding ctypes type, so that they can be converted to the required C data type:如前所述,除整数、字符串和字节对象之外的所有Python类型都必须包装在相应的ctypes类型中,以便转换为所需的C数据类型:

>>> printf(b"An int %d, a double %f\n", 1234, c_double(3.14))
An int 1234, a double 3.140000
31
>>>

Calling functions with your own custom data types使用您自己的自定义数据类型调用函数

You can also customize ctypes argument conversion to allow instances of your own classes be used as function arguments. 您还可以自定义ctypes参数转换,以允许您自己的类的实例用作函数参数。ctypes looks for an _as_parameter_ attribute and uses this as the function argument. ctypes查找_as_parameter_属性并将其用作函数参数。Of course, it must be one of integer, string, or bytes:当然,它必须是整数、字符串或字节之一:

>>> class Bottles:
... def __init__(self, number):
... self._as_parameter_ = number
...
>>> bottles = Bottles(42)
>>> printf(b"%d bottles of beer\n", bottles)
42 bottles of beer
19
>>>

If you don’t want to store the instance’s data in the _as_parameter_ instance variable, you could define a property which makes the attribute available on request.如果不想将实例的数据存储在_as_parameter_实例变量中,可以定义一个property,使该属性在请求时可用。

Specifying the required argument types (function prototypes)指定所需的参数类型(函数原型)

It is possible to specify the required argument types of functions exported from DLLs by setting the argtypes attribute.通过设置argtypes属性,可以指定从DLL导出的函数所需的参数类型。

argtypes must be a sequence of C data types (the printf function is probably not a good example here, because it takes a variable number and different types of parameters depending on the format string, on the other hand this is quite handy to experiment with this feature):必须是一系列C数据类型(printf函数在这里可能不是一个好例子,因为它需要一个可变的数字和不同类型的参数,这取决于格式字符串,另一方面,这对于试验此功能非常方便):

>>> printf.argtypes = [c_char_p, c_char_p, c_int, c_double]
>>> printf(b"String '%s', Int %d, Double %f\n", b"Hi", 10, 2.2)
String 'Hi', Int 10, Double 2.200000
37
>>>

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:指定格式可以防止不兼容的参数类型(就像C函数的原型一样),并尝试将参数转换为有效类型:

>>> printf(b"%d %d %d", 1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ArgumentError: argument 2: exceptions.TypeError: wrong type
>>> printf(b"%s %d %f\n", b"X", 2, 3)
X 2 3.000000
13
>>>

If you have defined your own classes which you pass to function calls, you have to implement a from_param() class method for them to be able to use them in the argtypes sequence. 如果定义了传递给函数调用的自己的类,则必须实现from_param()类方法,以便它们能够在argtypes序列中使用它们。The from_param() class method receives the Python object passed to the function call, it should do a typecheck or whatever is needed to make sure this object is acceptable, and then return the object itself, its _as_parameter_ attribute, or whatever you want to pass as the C function argument in this case. from_param()类方法接收传递给函数调用的Python对象,它应该进行类型检查或任何必要的操作,以确保该对象是可接受的,然后返回对象本身、其_as_parameter_属性,或者在本例中作为C函数参数传递的任何内容。Again, the result should be an integer, string, bytes, a ctypes instance, or an object with an _as_parameter_ attribute.同样,结果应该是整数、字符串、字节、ctypes实例或具有_as_parameter_属性的对象。

Return types返回类型

By default functions are assumed to return the C int type. 默认情况下,假设函数返回C int类型。Other return types can be specified by setting the restype attribute of the function object.可以通过设置函数对象的restype属性来指定其他返回类型。

Here is a more advanced example, it uses the strchr function, which expects a string pointer and a char, and returns a pointer to a string:下面是一个更高级的示例,它使用strchr函数,该函数需要一个字符串指针和一个字符,并返回一个指向字符串的指针:

>>> strchr = libc.strchr
>>> strchr(b"abcdef", ord("d"))
8059983
>>> strchr.restype = c_char_p # c_char_p is a pointer to a string
>>> strchr(b"abcdef", ord("d"))
b'def'
>>> print(strchr(b"abcdef", ord("x")))
None
>>>

If you want to avoid the ord("x") calls above, you can set the argtypes attribute, and the second argument will be converted from a single character Python bytes object into a C char:如果要避免上述ord("x")调用,可以设置argtypes属性,第二个参数将从单个字符的Python字节对象转换为C字符:

>>> strchr.restype = c_char_p
>>> strchr.argtypes = [c_char_p, c_char]
>>> strchr(b"abcdef", b"d")
'def'
>>> strchr(b"abcdef", b"def")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ArgumentError: argument 2: exceptions.TypeError: one character string expected
>>> print(strchr(b"abcdef", b"x"))
None
>>> strchr(b"abcdef", b"d")
'def'
>>>

You can also use a callable Python object (a function or a class for example) as the restype attribute, if the foreign function returns an integer. 如果外部函数返回整数,还可以使用可调用的Python对象(例如函数或类)作为restype属性。The callable will be called with the integer the C function returns, and the result of this call will be used as the result of your function call. 将使用C函数返回的integer调用可调用函数,此调用的结果将用作函数调用的结果。This is useful to check for error return values and automatically raise an exception:这有助于检查错误返回值并自动引发异常:

>>> 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 "<stdin>", line 1, in <module>
File "<stdin>", line 3, in ValidHandle
OSError: [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, and returns an exception. 是一个函数,它将调用Windows FormatMessage()api来获取错误代码的字符串表示形式,并返回异常。WinError takes an optional error code parameter, if no one is used, it calls GetLastError() to retrieve it.WinError接受一个可选的错误代码参数,如果没有使用该参数,它将调用GetLastError()来检索它。

Please note that a much more powerful error checking mechanism is available through the errcheck attribute; see the reference manual for details.请注意,通过errcheck属性可以使用更强大的错误检查机制;有关详细信息,请参阅参考手册。

Passing pointers (or: passing parameters by reference)传递指针(或:通过引用传递参数)

Sometimes a C api function expects a pointer to a data type as parameter, probably to write into the corresponding location, or if the data is too large to be passed by value. 有时,C api函数需要一个指向数据类型的指针作为参数,可能会写入相应的位置,或者数据太大而无法通过值传递。This is also known as passing parameters by reference.这也称为通过引用传递参数

ctypes exports the byref() function which is used to pass parameters by reference. 导出用于通过引用传递参数的byref()函数。The same effect can be achieved with the pointer() function, although pointer() does a lot more work since it constructs a real pointer object, so it is faster to use byref() if you don’t need the pointer object in Python itself:使用pointer()函数也可以达到同样的效果,尽管pointer()起了很大的作用,因为它构造了一个真实的指针对象,所以使用byref()能更快,如果你不需要Python自身的指针对象的话。

>>> i = c_int()
>>> f = c_float()
>>> s = create_string_buffer(b'\000' * 32)
>>> print(i.value, f.value, repr(s.value))
0 0.0 b''
>>> libc.sscanf(b"1 3.14 Hello", b"%d %f %s",
... byref(i), byref(f), s)
3
>>> print(i.value, f.value, repr(s.value))
1 3.1400001049 b'Hello'
>>>

Structures and unions结构和接头

Structures and unions must derive from the Structure and Union base classes which are defined in the ctypes module. StructureUnion必须派生自ctypes模块中定义的Structure和Union基类。Each subclass must define a _fields_ attribute. 每个子类都必须定义_fields_属性。_fields_ must be a list of 2-tuples, containing a field name and a field type.必须是包含字段名字段类型两元组列表。

The field type must be a ctypes type like c_int, or any other derived ctypes type: structure, union, array, pointer.字段类型必须是类似于c_intctypes类型,或任何其他派生的ctypes类型:structure、union、array、pointer。

Here is a simple example of a POINT structure, which contains two integers named x and y, and also shows how to initialize a structure in the constructor:下面是POINT结构的一个简单示例,它包含两个名为xy的整数,还显示了如何在构造函数中初始化结构:

>>> from ctypes import *
>>> class POINT(Structure):
... _fields_ = [("x", c_int),
... ("y", c_int)]
...
>>> point = POINT(10, 20)
>>> print(point.x, point.y)
10 20
>>> point = POINT(y=5)
>>> print(point.x, point.y)
0 5
>>> POINT(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: too many initializers
>>>

You can, however, build much more complicated structures. 然而,您可以构建更复杂的结构。A structure 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:下面是一个RECT结构,它包含两个名为upperleftlowerright

>>> class RECT(Structure):
... _fields_ = [("upperleft", POINT),
... ("lowerright", POINT)]
...
>>> rc = RECT(point)
>>> print(rc.upperleft.x, rc.upperleft.y)
0 5
>>> print(rc.lowerright.x, rc.lowerright.y)
0 0
>>>

Nested structures can also be initialized in the constructor in several ways:嵌套结构也可以通过以下几种方式在构造函数中初始化:

>>> r = RECT(POINT(1, 2), POINT(3, 4))
>>> r = RECT((1, 2), (3, 4))

Field descriptors can be retrieved from the class, they are useful for debugging because they can provide useful information:字段描述符可以从中检索,它们对于调试很有用,因为它们可以提供有用的信息:

>>> print(POINT.x)
<Field type=c_long, ofs=0, size=4>
>>> print(POINT.y)
<Field type=c_long, ofs=4, size=4>
>>>

Warning

ctypes does not support passing unions or structures with bit-fields to functions by value. 不支持按值将具有位字段的联合或结构传递给函数。While this may work on 32-bit x86, it’s not guaranteed by the library to work in the general case. 虽然这可以在32位x86上工作,但库不能保证在一般情况下工作。Unions and structures with bit-fields should always be passed to functions by pointer.具有位字段的联合和结构应始终通过指针传递给函数。

Structure/union alignment and byte order结构/联合对齐和字节顺序

By default, Structure and Union fields are aligned in the same way the C compiler does it. 默认情况下,Structure和Union字段的对齐方式与C编译器的对齐方式相同。It is possible to override this behavior by specifying a _pack_ class attribute in the subclass definition. 可以通过在子类定义中指定_pack_类属性来覆盖此行为。This must be set to a positive integer and specifies the maximum alignment for the fields. 这必须设置为正整数,并指定字段的最大对齐方式。This is what #pragma pack(n) also does in MSVC.这就是#pragma pack(n)在MSVC中的作用。

ctypes uses the native byte order for Structures and Unions. 对结构和联合使用本机字节顺序。To build structures with non-native byte order, you can use one of the BigEndianStructure, LittleEndianStructure, BigEndianUnion, and LittleEndianUnion base classes. 要构建具有非本机字节顺序的结构,可以使用BigEndianStructureLittleEndianStructureBigEndianUnionLittleEndianUnion基类之一。These classes cannot contain pointer fields.这些类不能包含指针字段。

Bit fields in structures and unions结构和联合中的位字段

It is possible to create structures and unions containing bit fields. 可以创建包含位字段的结构和联合。Bit fields are only possible for integer fields, the bit width is specified as the third item in the _fields_ tuples:位字段只能用于整数字段,位宽度指定为_fields_元组中的第三项:

>>> class Int(Structure):
... _fields_ = [("first_16", c_int, 16),
... ("second_16", c_int, 16)]
...
>>> print(Int.first_16)
<Field type=c_long, ofs=0:0, bits=16>
>>> print(Int.second_16)
<Field type=c_long, ofs=0:16, bits=16>
>>>

Arrays数组

Arrays are sequences, containing a fixed number of instances of the same type.数组是序列,包含固定数量的相同类型的实例。

The recommended way to create array types is by multiplying a data type with a positive integer:创建数组类型的建议方法是将数据类型与正整数相乘:

TenPointsArrayType = POINT * 10

Here is an example of a somewhat artificial data type, a structure containing 4 POINTs among other stuff:下面是一个有点人为的数据类型的示例,该结构包含4个POINT以及其他内容:

>>> from ctypes import *
>>> class POINT(Structure):
... _fields_ = ("x", c_int), ("y", c_int)
...
>>> class MyStruct(Structure):
... _fields_ = [("a", c_int),
... ("b", c_float),
... ("point_array", POINT * 4)]
>>>
>>> print(len(MyStruct().point_array))
4
>>>

Instances are created in the usual way, by calling the class:实例是以通常的方式创建的,方法是调用类:

arr = TenPointsArrayType()
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.上面的代码打印了一系列0 0行,因为数组内容被初始化为零。

Initializers of the correct type can also be specified:还可以指定正确类型的初始值设定项:

>>> from ctypes import *
>>> TenIntegers = c_int * 10
>>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
>>> print(ii)
<c_long_Array_10 object at 0x...>
>>> for i in ii: print(i, end=" ")
...
1 2 3 4 5 6 7 8 9 10
>>>

Pointers指针

Pointer instances are created by calling the pointer() function on a ctypes type:指针实例是通过对ctypes类型调用pointer()函数创建的:

>>> from ctypes import *
>>> i = c_int(42)
>>> pi = pointer(i)
>>>

Pointer instances have a contents attribute which returns the object to which the pointer points, the i object above:指针实例有一个contents属性,它返回指针指向的对象,即上面的i对象:

>>> pi.contents
c_long(42)
>>>

Note that ctypes does not have OOR (original object return), it constructs a new, equivalent object each time you retrieve an attribute:请注意,ctypes没有OOR(原始对象返回),每次检索属性时,它都会构造一个新的等效对象:

>>> pi.contents is i
False
>>> pi.contents is pi.contents
False
>>>

Assigning another c_int instance to the pointer’s contents attribute would cause the pointer to point to the memory location where this is stored:将另一个c_int实例指定给指针的contents属性将导致指针指向存储该实例的内存位置:

>>> i = c_int(99)
>>> pi.contents = i
>>> pi.contents
c_long(99)
>>>

Pointer instances can also be indexed with integers:指针实例也可以用整数进行索引:

>>> pi[0]
99
>>>

Assigning to an integer index changes the pointed to value:分配给整数索引会更改指向的值:

>>> print(i)
c_long(99)
>>> pi[0] = 22
>>> print(i)
c_long(22)
>>>

It is also possible to use indexes different from 0, but you must know what you’re doing, just as in C: You can access or change arbitrary memory locations. 也可以使用不同于0的索引,但您必须知道自己在做什么,就像在C中一样:您可以访问或更改任意内存位置。Generally you only use this feature if you receive a pointer from a C function, and you know that the pointer actually points to an array instead of a single item.通常,只有当您从C函数接收到一个指针,并且您知道该指针实际上指向一个数组而不是单个项时,才使用此功能。

Behind the scenes, the pointer() function does more than simply create pointer instances, it has to create pointer types first. 在幕后,pointer()函数不仅仅是创建指针实例,它还必须首先创建指针类型This is done with the POINTER() function, which accepts any ctypes type, and returns a new type:这是通过POINTER()函数完成的,该函数接受任何ctypes类型,并返回一个新类型:

>>> PI = POINTER(c_int)
>>> PI
<class 'ctypes.LP_c_long'>
>>> PI(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: expected c_long instead of int
>>> PI(c_int(42))
<ctypes.LP_c_long object at 0x...>
>>>

Calling the pointer type without an argument creates a NULL pointer. 不带参数调用指针类型将创建NULL指针。NULL pointers have a False boolean value:NULL指针具有False布尔值:

>>> null_ptr = POINTER(c_int)()
>>> print(bool(null_ptr))
False
>>>

ctypes checks for NULL when dereferencing pointers (but dereferencing invalid non-NULL pointers would crash Python):在取消引用指针时检查NULL(但取消引用无效的非NULL指针会使Python崩溃):

>>> null_ptr[0]
Traceback (most recent call last):
....
ValueError: NULL pointer access
>>>
>>> null_ptr[0] = 1234
Traceback (most recent call last):
....
ValueError: NULL pointer access
>>>

Type conversions类型转换

Usually, ctypes does strict type checking. 通常,ctypes执行严格的类型检查。This means, if you have POINTER(c_int) in the argtypes list of a function or as the type of a member field in a structure definition, only instances of exactly the same type are accepted. 这意味着,如果在函数的argtypes列表中有POINTER(c_int),或者作为结构定义中成员字段的类型,则只接受完全相同类型的实例。There are some exceptions to this rule, where ctypes accepts other objects. 这个规则有一些例外,ctypes接受其他对象。For example, you can pass compatible array instances instead of pointer types. 例如,可以传递兼容的数组实例,而不是指针类型。So, for POINTER(c_int), ctypes accepts an array of c_int:因此,对于POINTER(c_int),ctypes接受c_int数组:

>>> class Bar(Structure):
... _fields_ = [("count", c_int), ("values", POINTER(c_int))]
...
>>> bar = Bar()
>>> bar.values = (c_int * 3)(1, 2, 3)
>>> bar.count = 3
>>> for i in range(bar.count):
... print(bar.values[i])
...
1
2
3
>>>

In addition, if a function argument is explicitly declared to be a pointer type (such as POINTER(c_int)) in argtypes, an object of the pointed type (c_int in this case) can be passed to the function. 此外,如果函数参数在argtypes中显式声明为指针类型(例如POINTER(c_int)),则可以向函数传递一个指针类型的对象(在本例中为c_int)。ctypes will apply the required byref() conversion in this case automatically.在这种情况下,ctypes将自动应用所需的byref()转换。

To set a POINTER type field to NULL, you can assign None:要将POINTER类型字段设置为NULL,可以指定None

>>> bar.values = None
>>>

Sometimes you have instances of incompatible types. 有时您有不兼容类型的实例。In C, you can cast one type into another type. 在C语言中,可以将一种类型转换为另一种类型。ctypes provides a cast() function which can be used in the same way. ctypes提供了一个cast()函数,可以以同样的方式使用。The Bar structure defined above accepts POINTER(c_int) pointers or c_int arrays for its values field, but not instances of other types:上面定义的Bar结构接受POINTER(c_int)指针或c_int数组作为其values字段,但不接受其他类型的实例:

>>> bar.values = (c_byte * 4)()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: incompatible types, c_byte_Array_4 instance instead of LP_c_long instance
>>>

For these cases, the cast() function is handy.对于这些情况,cast()函数很方便。

The cast() function can be used to cast a ctypes instance into a pointer to a different ctypes data type. cast()函数可用于将ctypes实例转换为指向不同ctypes数据类型的指针。cast() takes two parameters, a ctypes object that is or can be converted to a pointer of some kind, and a ctypes pointer type. 接受两个参数,一个是或可以转换为某种类型的指针的ctypes对象,另一个是ctypes指针类型。It returns an instance of the second argument, which references the same memory block as the first argument:它返回第二个参数的实例,该实例引用与第一个参数相同的内存块:

>>> a = (c_byte * 4)()
>>> cast(a, POINTER(c_int))
<ctypes.LP_c_long object at ...>
>>>

So, cast() can be used to assign to the values field of Bar the structure:因此,可以使用cast()将结构分配给Barvalues字段:

>>> bar = Bar()
>>> bar.values = cast((c_byte * 4)(), POINTER(c_int))
>>> print(bar.values[0])
0
>>>

Incomplete Types不完整的类型

Incomplete Types are structures, unions or arrays whose members are not yet specified. 不完整类型是尚未指定其成员的结构、联合或数组。In C, they are specified by forward declarations, which are defined later:在C语言中,它们由forward声明指定,后者稍后定义:

struct cell; /* forward declaration */
struct cell {
char *name;
struct cell *next;
};

The straightforward translation into ctypes code would be this, but it does not work:直接转换为ctypes代码的方法是这样的,但它不起作用:

>>> class cell(Structure):
... _fields_ = [("name", c_char_p),
... ("next", POINTER(cell))]
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in cell
NameError: name 'cell' is not defined
>>>

because the new class cell is not available in the class statement itself. 因为新的class cell在类语句本身中不可用。In ctypes, we can define the cell class and set the _fields_ attribute later, after the class statement:ctypes中,我们可以在类语句之后定义cell类并设置_fields_属性:

>>> from ctypes import *
>>> class cell(Structure):
... pass
...
>>> cell._fields_ = [("name", c_char_p),
... ("next", POINTER(cell))]
>>>

Let’s try it. 让我们试试看。We create two instances of cell, and let them point to each other, and finally follow the pointer chain a few times:我们创建了两个cell实例,让它们相互指向,最后沿着指针链几次:

>>> c1 = cell()
>>> c1.name = b"foo"
>>> c2 = cell()
>>> c2.name = b"bar"
>>> c1.next = pointer(c2)
>>> c2.next = pointer(c1)
>>> p = c1
>>> for i in range(8):
... print(p.name, end=" ")
... p = p.next[0]
...
foo bar foo bar foo bar foo bar
>>>

Callback functions回调函数

ctypes allows creating C callable function pointers from Python callables. 允许从Python可调用函数创建C可调用函数指针。These are sometimes called callback functions.这些有时称为回调函数

First, you must create a class for the callback function. 首先,必须为回调函数创建一个类。The class knows the calling convention, the return type, and the number and types of arguments this function will receive.该类知道调用约定、返回类型以及此函数将接收的参数的数量和类型。

The CFUNCTYPE() factory function creates types for callback functions using the cdecl calling convention. CFUNCTYPE()工厂函数使用cdecl调用约定为回调函数创建类型。On Windows, the WINFUNCTYPE() factory function creates types for callback functions using the stdcall calling convention.在Windows上,WINFUNCTYPE()工厂函数使用stdcall调用约定为回调函数创建类型。

Both of these factory functions are called with the result type as first argument, and the callback functions expected argument types as the remaining arguments.调用这两个工厂函数时,将结果类型作为第一个参数,回调函数将参数类型作为剩余参数。

I will present an example here which uses the standard C library’s qsort() function, that is used to sort items with the help of a callback function. 我将在这里展示一个使用标准C库的qsort()函数的示例,该函数用于在回调函数的帮助下对项目进行排序。qsort() will be used to sort an array of integers:qsort()将用于对整数数组进行排序:

>>> IntArray5 = c_int * 5
>>> ia = IntArray5(5, 1, 7, 33, 99)
>>> qsort = libc.qsort
>>> qsort.restype = None
>>>

qsort() must be called with a pointer to the data to sort, the number of items in the data array, the size of one item, and a pointer to the comparison function, the callback. 必须使用指向要排序的数据的指针、数据数组中的项目数、一个项目的大小以及指向比较函数回调的指针来调用。The callback will then be called with two pointers to items, and it must return a negative integer if the first item is smaller than the second, a zero if they are equal, and a positive integer otherwise.然后将使用两个指向项的指针调用回调,如果第一个项小于第二个项,回调必须返回一个负整数,如果它们相等,则返回一个零,否则返回一个正整数。

So our callback function receives pointers to integers, and must return an integer. 因此,回调函数接收指向整数的指针,并且必须返回整数。First we create the type for the callback function:首先,我们为回调函数创建type

>>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
>>>

To get started, here is a simple callback that shows the values it gets passed:首先,下面是一个简单的回调,它显示了传递的值:

>>> def py_cmp_func(a, b):
... print("py_cmp_func", a[0], b[0])
... return 0
...
>>> cmp_func = CMPFUNC(py_cmp_func)
>>>

The result:结果是:

>>> qsort(ia, len(ia), sizeof(c_int), cmp_func)
py_cmp_func 5 1
py_cmp_func 33 99
py_cmp_func 7 33
py_cmp_func 5 7
py_cmp_func 1 7
>>>

Now we can actually compare the two items and return a useful result:现在我们可以实际比较这两个项目并返回一个有用的结果:

>>> def py_cmp_func(a, b):
... print("py_cmp_func", a[0], b[0])
... return a[0] - b[0]
...
>>>
>>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func))
py_cmp_func 5 1
py_cmp_func 33 99
py_cmp_func 7 33
py_cmp_func 1 7
py_cmp_func 5 7
>>>

As we can easily check, our array is sorted now:正如我们可以轻松检查的那样,数组现在已经排序:

>>> for i in ia: print(i, end=" ")
...
1 5 7 33 99
>>>

The function factories can be used as decorator factories, so we may as well write:函数工厂可以用作装饰工厂,因此我们不妨写下:

>>> @CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
... def py_cmp_func(a, b):
... print("py_cmp_func", a[0], b[0])
... return a[0] - b[0]
...
>>> qsort(ia, len(ia), sizeof(c_int), py_cmp_func)
py_cmp_func 5 1
py_cmp_func 33 99
py_cmp_func 7 33
py_cmp_func 1 7
py_cmp_func 5 7
>>>

Note

Make sure you keep references to CFUNCTYPE() objects as long as they are used from C code. 确保保留对CFUNCTYPE()对象的引用,只要它们是从C代码中使用的。ctypes doesn’t, and if you don’t, they may be garbage collected, crashing your program when a callback is made.如果不这样做,它们可能会被垃圾收集,在回调时会导致程序崩溃。

Also, note that if the callback function is called in a thread created outside of Python’s control (e.g. by the foreign code that calls the callback), ctypes creates a new dummy Python thread on every invocation. 另外,请注意,如果在Python控制之外创建的线程中调用回调函数(例如,由调用回调的外部代码),则ctypes会在每次调用时创建一个新的伪Python-线程。This behavior is correct for most purposes, but it means that values stored with threading.local will not survive across different callbacks, even when those calls are made from the same C thread.这种行为在大多数情况下都是正确的,但这意味着用threading.local存储的值在不同的回调中无法存活,即使这些调用是从同一个C线程进行的。

Accessing values exported from dlls访问从dll导出的值

Some shared libraries not only export functions, they also export variables. 一些共享库不仅导出函数,还导出变量。An example in the Python library itself is the Py_OptimizeFlag, an integer set to 0, 1, or 2, depending on the -O or -OO flag given on startup.Python库本身的一个例子是Py_OptimizeFlag,它是一个设置为0、1或2的整数,具体取决于启动时给定的-O-OO标志。

ctypes can access values like this with the in_dll() class methods of the type. 可以使用该类型的indll()类方法访问类似的值。pythonapi is a predefined symbol giving access to the Python C api:是一个预定义符号,用于访问Python C api:

>>> opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag")
>>> print(opt_flag)
c_long(0)
>>>

If the interpreter would have been started with -O, the sample would have printed c_long(1), or c_long(2) if -OO would have been specified.如果解释器是用-O启动的,那么示例将打印c_long(1),如果指定了-OO,则打印c_leng(2)

An extended example which also demonstrates the use of pointers accesses the PyImport_FrozenModules pointer exported by Python.一个扩展示例还演示了指针的使用,它访问Python导出的PyImport_FrozenModules指针。

Quoting the docs for that value:为该值引用文档:

This pointer is initialized to point to an array of struct _frozen records, terminated by one whose members are all NULL or zero. 该指针被初始化为指向struct _frozen记录数组,由其成员全部为NULL或零的数组终止。When a frozen module is imported, it is searched in this table. 导入冻结模块时,将在此表中搜索该模块。Third-party code could play tricks with this to provide a dynamically created collection of frozen modules.第三方代码可以利用这一点来提供动态创建的冻结模块集合。

So manipulating this pointer could even prove useful. 因此,操纵这个指针甚至可以证明是有用的。To restrict the example size, we show only how this table can be read with ctypes:为了限制示例大小,我们只显示如何使用ctypes读取此表:

>>> from ctypes import *
>>>
>>> class struct_frozen(Structure):
... _fields_ = [("name", c_char_p),
... ("code", POINTER(c_ubyte)),
... ("size", c_int)]
...
>>>

We have defined the struct _frozen data type, so we can get the pointer to the table:我们已经定义了struct _frozen数据类型,因此可以获得指向表的指针:

>>> FrozenTable = POINTER(struct_frozen)
>>> table = FrozenTable.in_dll(pythonapi, "PyImport_FrozenModules")
>>>

Since table is a pointer to the array of struct_frozen records, we can iterate over it, but we just have to make sure that our loop terminates, because pointers have no size. 由于table是指向struct_frozen记录数组的pointer,我们可以对其进行迭代,但我们只需确保循环终止,因为指针没有大小。Sooner or later it would probably crash with an access violation or whatever, so it’s better to break out of the loop when we hit the NULL entry:它迟早会因访问冲突或其他原因而崩溃,因此最好在遇到NULL条目时跳出循环:

>>> for item in table:
... if item.name is None:
... break
... print(item.name.decode("ascii"), item.size)
...
_frozen_importlib 31764
_frozen_importlib_external 41499
__hello__ 161
__phello__ -161
__phello__.spam 161
>>>

The fact that standard Python has a frozen module and a frozen package (indicated by the negative size member) is not well known, it is only used for testing. 标准Python有一个冻结模块和一个冻结包(由负size成员表示)这一事实并不为人所知,它只用于测试。Try it out with import __hello__ for example.例如,尝试使用import__hello__

Surprises惊喜

There are some edges in ctypes where you might expect something other than what actually happens.ctypes中有一些边缘,您可能会期望实际发生的事情以外的事情。

Consider the following example:考虑以下示例:

>>> from ctypes import *
>>> class POINT(Structure):
... _fields_ = ("x", c_int), ("y", c_int)
...
>>> 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 happened? Here are the steps of the rc.a, rc.b = rc.b, rc.a line above:嗯。我们当然希望最后一个语句打印3 4 1 2。发生了什么?下面是上面rc.a, rc.b = rc.b, rc.a行的步骤:

>>> 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. 请注意,temp0temp1是仍在使用上述rc对象的内部缓冲区的对象。So executing rc.a = temp0 copies the buffer contents of temp0 into rc 's buffer. 因此,执行rc.a=temp0会将temp0的缓冲区内容复制到rc的缓冲区中。This, in turn, changes the contents of temp1. 这反过来又改变了temp1的内容。So, the last assignment rc.b = temp1, doesn’t have the expected effect.因此,最后一个赋值rc.b = temp1没有预期的效果。

Keep in mind that retrieving sub-objects from Structure, Unions, and Arrays doesn’t copy the sub-object, instead it retrieves a wrapper object accessing the root-object’s underlying buffer.请记住,从Structure、Unions和Arrays检索子对象不会复制子对象,而是检索访问根对象底层缓冲区的包装器对象。

Another example that may behave differently from what one would expect is this:另一个可能与预期不同的例子是:

>>> s = c_char_p()
>>> s.value = b"abc def ghi"
>>> s.value
b'abc def ghi'
>>> s.value is s.value
False
>>>

Note

Objects instantiated from c_char_p can only have their value set to bytes or integers.c_char_p实例化的对象只能将其值设置为字节或整数。

Why is it printing False? 为什么打印为Falsectypes instances are objects containing a memory block plus some descriptors accessing the contents of the memory. ctypes实例是包含内存块和一些访问内存内容的描述符的对象。Storing a Python object in the memory block does not store the object itself, instead the contents of the object is stored. 在内存块中存储Python对象不会存储对象本身,而是存储对象的contentsAccessing the contents again constructs a new Python object each time!每次再次访问内容都会构造一个新的Python对象!

Variable-sized data types可变大小的数据类型

ctypes provides some support for variable-sized arrays and structures.为可变大小的数组和结构提供了一些支持。

The resize() function can be used to resize the memory buffer of an existing ctypes object. resize()函数的作用是:调整现有ctypes对象的内存缓冲区大小。The function takes the object as first argument, and the requested size in bytes as the second argument. 函数将对象作为第一个参数,将请求的字节大小作为第二个参数。The memory block cannot be made smaller than the natural memory block specified by the objects type, a ValueError is raised if this is tried:内存块不能小于对象类型指定的自然内存块,如果尝试这样做,将引发ValueError

>>> short_array = (c_short * 4)()
>>> print(sizeof(short_array))
8
>>> resize(short_array, 4)
Traceback (most recent call last):
...
ValueError: minimum size is 8
>>> resize(short_array, 32)
>>> sizeof(short_array)
32
>>> sizeof(type(short_array))
8
>>>

This is nice and fine, but how would one access the additional elements contained in this array? 这很好,但是如何访问这个数组中包含的其他元素呢?Since the type still only knows about 4 elements, we get errors accessing other elements:由于类型仍然只知道大约4个元素,因此访问其他元素时会出错:

>>> short_array[:]
[0, 0, 0, 0]
>>> short_array[7]
Traceback (most recent call last):
...
IndexError: invalid index
>>>

Another way to use variable-sized data types with ctypes is to use the dynamic nature of Python, and (re-)define the data type after the required size is already known, on a case by case basis.将可变大小的数据类型与ctypes结合使用的另一种方法是使用Python的动态特性,并在已知所需大小后,根据具体情况重新定义数据类型。

ctypes referencectypes参考

Finding shared libraries查找共享库

When programming in a compiled language, shared libraries are accessed when compiling/linking a program, and when the program is run.当用编译语言编程时,在编译/链接程序以及运行程序时访问共享库。

The purpose of the find_library() function is to locate a library in a way similar to what the compiler or runtime loader does (on platforms with several versions of a shared library the most recent should be loaded), while the ctypes library loaders act like when a program is run, and call the runtime loader directly.find_library()函数的目的是以类似于编译器或运行时加载程序的方式查找库(在具有多个版本的共享库的平台上,应加载最新版本),而ctypes库加载程序的行为类似于程序运行时的行为,并直接调用运行时加载器。

The ctypes.util module provides a function which can help to determine the library to load.ctypes.util模块提供了一个函数,可以帮助确定要加载的库。

ctypes.util.find_library(name)

Try to find a library and return a pathname. 尝试查找库并返回路径名。name is the library name without any prefix like lib, suffix like .so, .dylib or version number (this is the form used for the posix linker option -l). name是没有前缀lib、后缀.so.dylib或版本号的库名称(这是posix链接器选项-l使用的格式)。If no library can be found, returns None.如果找不到库,则返回None

The exact functionality is system dependent.具体功能取决于系统。

On Linux, find_library() tries to run external programs (/sbin/ldconfig, gcc, objdump and ld) to find the library file. It returns the filename of the library file.在Linux上,find_library()尝试运行外部程序(/sbin/ldconfiggccobjdumpld)来查找库文件。它返回库文件的文件名。

Changed in version 3.6:版本3.6中更改: On Linux, the value of the environment variable LD_LIBRARY_PATH is used when searching for libraries, if a library cannot be found by any other means.在Linux上,如果无法通过任何其他方式找到库,则在搜索库时使用环境变量LD_LIBRARY_PATH的值。

Here are some examples:以下是一些示例:

>>> from ctypes.util import find_library
>>> find_library("m")
'libm.so.6'
>>> find_library("c")
'libc.so.6'
>>> find_library("bz2")
'libbz2.so.1.0'
>>>

On macOS, find_library() tries several predefined naming schemes and paths to locate the library, and returns a full pathname if successful:在macOS上,find_library()尝试几个预定义的命名方案和路径来查找库,如果成功,则返回完整的路径名:

>>> from ctypes.util import find_library
>>> find_library("c")
'/usr/lib/libc.dylib'
>>> find_library("m")
'/usr/lib/libm.dylib'
>>> find_library("bz2")
'/usr/lib/libbz2.dylib'
>>> find_library("AGL")
'/System/Library/Frameworks/AGL.framework/AGL'
>>>

On Windows, find_library() searches along the system search path, and returns the full pathname, but since there is no predefined naming scheme a call like find_library("c") will fail and return None.在Windows上,find_library()沿系统搜索路径搜索,并返回完整路径名,但由于没有预定义的命名方案,像find_library("c")这样的调用将失败并返回None

If wrapping a shared library with ctypes, it may be better to determine the shared library name at development time, and hardcode that into the wrapper module instead of using find_library() to locate the library at runtime.

Loading shared libraries加载共享库

There are several ways to load shared libraries into the Python process. 有几种方法可以将共享库加载到Python进程中。One way is to instantiate one of the following classes:一种方法是实例化以下类之一:

classctypes.CDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None)

Instances of this class represent loaded shared libraries. 此类的实例表示加载的共享库。Functions in these libraries use the standard C calling convention, and are assumed to return int.这些库中的函数使用标准的C调用约定,并假定返回int。

On Windows creating a CDLL instance may fail even if the DLL name exists. When a dependent DLL of the loaded DLL is not found, a OSError error is raised with the message “[WinError 126] The specified module could not be found”. This error message does not contain the name of the missing DLL because the Windows API does not return this information making this error hard to diagnose. 此错误消息不包含丢失DLL的名称,因为Windows API不返回此信息,因此很难诊断此错误。To resolve this error and determine which DLL is not found, you need to find the list of dependent DLLs and determine which one is not found using Windows debugging and tracing tools.要解决此错误并确定找不到哪个DLL,您需要查找依赖DLL的列表,并使用Windows调试和跟踪工具确定找不到此DLL。

See also

Microsoft DUMPBIN toolA tool to find DLL dependents.查找DLL依赖项的工具。

classctypes.OleDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None)

Windows only: Instances of this class represent loaded shared libraries, functions in these libraries use the stdcall calling convention, and are assumed to return the windows specific HRESULT code. HRESULT values contain information specifying whether the function call failed or succeeded, together with additional error code. If the return value signals a failure, an OSError is automatically raised.如果返回值表示失败,则会自动引发OSError

Changed in version 3.3:版本3.3中更改: WindowsError used to be raised.

classctypes.WinDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None)

Windows only: Instances of this class represent loaded shared libraries, functions in these libraries use the stdcall calling convention, and are assumed to return int by default.仅限Windows:此类的实例表示加载的共享库,这些库中的函数使用stdcall调用约定,默认情况下假定返回int

On Windows CE only the standard calling convention is used, for convenience the WinDLL and OleDLL use the standard calling convention on this platform.

The Python global interpreter lock is released before calling any function exported by these libraries, and reacquired afterwards.

classctypes.PyDLL(name, mode=DEFAULT_MODE, handle=None)

Instances of this class behave like CDLL instances, except that the Python GIL is not released during the function call, and after the function execution the Python error flag is checked. If the error flag is set, a Python exception is raised.

Thus, this is only useful to call Python C api functions directly.

All these classes can be instantiated by calling them with at least one argument, the pathname of the shared library. If you have an existing handle to an already loaded shared library, it can be passed as the handle named parameter, otherwise the underlying platforms dlopen or LoadLibrary function is used to load the library into the process, and to get a handle to it.

The mode parameter can be used to specify how the library is loaded. For details, consult the dlopen(3) manpage. On Windows, mode is ignored. On posix systems, RTLD_NOW is always added, and is not configurable.

The use_errno parameter, when set to true, enables a ctypes mechanism that allows accessing the system errno error number in a safe way. ctypes maintains a thread-local copy of the systems errno variable; if you call foreign functions created with use_errno=True then the errno value before the function call is swapped with the ctypes private copy, the same happens immediately after the function call.

The function ctypes.get_errno() returns the value of the ctypes private copy, and the function ctypes.set_errno() changes the ctypes private copy to a new value and returns the former value.

The use_last_error parameter, when set to true, enables the same mechanism for the Windows error code which is managed by the GetLastError() and SetLastError() Windows API functions; ctypes.get_last_error() and ctypes.set_last_error() are used to request and change the ctypes private copy of the windows error code.

The winmode parameter is used on Windows to specify how the library is loaded (since mode is ignored). winmode参数在Windows上用于指定如何加载库(因为忽略了mode)。It takes any value that is valid for the Win32 API LoadLibraryEx flags parameter. 它接受对Win32 API LoadLibraryEx标志参数有效的任何值。When omitted, the default is to use the flags that result in the most secure DLL load to avoiding issues such as DLL hijacking. 如果省略,默认设置是使用导致最安全的DLL加载的标志,以避免诸如DLL劫持之类的问题。Passing the full path to the DLL is the safest way to ensure the correct library and dependencies are loaded.将完整路径传递给DLL是确保加载正确库和依赖项的最安全方法。

Changed in version 3.8:版本3.8中更改: Added winmode parameter.

ctypes.RTLD_GLOBAL

Flag to use as mode parameter. 用作mode参数的标志。On platforms where this flag is not available, it is defined as the integer zero.在没有此标志的平台上,它被定义为整数零。

ctypes.RTLD_LOCAL

Flag to use as mode parameter. 用作mode参数的标志。On platforms where this is not available, it is the same as RTLD_GLOBAL.在不可用的平台上,它与RTLD_GLOBAL相同。

ctypes.DEFAULT_MODE

The default mode which is used to load shared libraries. 用于加载共享库的默认模式。On OSX 10.3, this is RTLD_GLOBAL, otherwise it is the same as RTLD_LOCAL.在OSX 10.3上,这是RTLD_GLOBAL,否则它与RTLD_LOCAL相同。

Instances of these classes have no public methods. 这些类的实例没有公共方法。Functions exported by the shared library can be accessed as attributes or by index. 共享库导出的函数可以作为属性或通过索引进行访问。Please note that accessing the function through an attribute caches the result and therefore accessing it repeatedly returns the same object each time. 请注意,通过属性访问函数会缓存结果,因此每次访问它都会重复返回相同的对象。On the other hand, accessing it through an index returns a new object each time:另一方面,每次通过索引访问它都会返回一个新对象:

>>> from ctypes import CDLL
>>> libc = CDLL("libc.so.6") # On Linux
>>> libc.time == libc.time
True
>>> libc['time'] == libc['time']
False

The following public attributes are available, their name starts with an underscore to not clash with exported function names:以下公共属性可用,其名称以下划线开头,以避免与导出的函数名称冲突:

PyDLL._handle

The system handle used to access the library.用于访问库的系统句柄。

PyDLL._name

The name of the library passed in the constructor.传入构造函数的库的名称。

Shared libraries can also be loaded by using one of the prefabricated objects, which are instances of the LibraryLoader class, either by calling the LoadLibrary() method, or by retrieving the library as attribute of the loader instance.

classctypes.LibraryLoader(dlltype)

Class which loads shared libraries. 类,用于加载共享库。dlltype should be one of the CDLL, PyDLL, WinDLL, or OleDLL types.

__getattr__() has special behavior: It allows loading a shared library by accessing it as attribute of a library loader instance. 具有特殊行为:它允许通过作为库加载器实例的属性访问共享库来加载它。The result is cached, so repeated attribute accesses return the same library each time.结果被缓存,因此重复的属性访问每次都返回相同的库。

LoadLibrary(name)

Load a shared library into the process and return it. 将共享库加载到进程中并将其返回。This method always returns a new instance of the library.此方法始终返回库的新实例。

These prefabricated library loaders are available:这些预制库装载机可用:

ctypes.cdll

Creates CDLL instances.

ctypes.windll

Windows only: Creates WinDLL instances.

ctypes.oledll

Windows only: Creates OleDLL instances.

ctypes.pydll

Creates PyDLL instances.

For accessing the C Python api directly, a ready-to-use Python shared library object is available:为了直接访问C Python api,可以使用现成的Pythone共享库对象:

ctypes.pythonapi

An instance of PyDLL that exposes Python C API functions as attributes. Note that all these functions are assumed to return C int, which is of course not always the truth, so you have to assign the correct restype attribute to use these functions.

Loading a library through any of these objects raises an auditing event ctypes.dlopen with string argument name, the name used to load the library.

Accessing a function on a loaded library raises an auditing event ctypes.dlsym with arguments library (the library object) and name (the symbol’s name as a string or integer).

In cases when only the library handle is available rather than the object, accessing a function raises an auditing event ctypes.dlsym/handle with arguments handle (the raw library handle) and name.

Foreign functions外部函数

As explained in the previous section, foreign functions can be accessed as attributes of loaded shared libraries. 如前一节所述,外部函数可以作为加载的共享库的属性进行访问。The function objects created in this way by default accept any number of arguments, accept any ctypes data instances as arguments, and return the default result type specified by the library loader. 默认情况下,以这种方式创建的函数对象接受任意数量的参数,接受任意ctypes数据实例作为参数,并返回库加载器指定的默认结果类型。They are instances of a private class:它们是私有类的实例:

classctypes._FuncPtr

Base class for C callable foreign functions.C可调用外部函数的基类。

Instances of foreign functions are also C compatible data types; they represent C function pointers.外部函数的实例也是C兼容的数据类型;它们表示C函数指针。

This behavior can be customized by assigning to special attributes of the foreign function object.这种行为可以通过指定给外部函数对象的特殊属性来定制。

restype

Assign a ctypes type to specify the result type of the foreign function. 指定ctypes类型以指定外部函数的结果类型。Use None for void, a function not returning anything.使用None表示void,该函数不返回任何内容。

It is possible to assign a callable Python object that is not a ctypes type, in this case the function is assumed to return a C int, and the callable will be called with this integer, allowing further processing or error checking. 可以分配一个不是ctypes类型的可调用Python对象,在这种情况下,假设函数返回一个C int,并用这个整数调用可调用对象,从而允许进一步处理或错误检查。Using this is deprecated, for more flexible post processing or error checking use a ctypes data type as restype and assign a callable to the errcheck attribute.不推荐使用此选项,为了更灵活的后期处理或错误检查,请将ctypes数据类型用作restype,并将可调用项分配给errcheck属性。

argtypes

Assign a tuple of ctypes types to specify the argument types that the function accepts. 分配ctypes类型的元组以指定函数接受的参数类型。Functions using the stdcall calling convention can only be called with the same number of arguments as the length of this tuple; functions using the C calling convention accept additional, unspecified arguments as well.使用stdcall调用约定的函数只能使用与此元组长度相同的参数数进行调用;使用C调用约定的函数也接受其他未指定的参数。

When a foreign function is called, each actual argument is passed to the from_param() class method of the items in the argtypes tuple, this method allows adapting the actual argument to an object that the foreign function accepts. For example, a c_char_p item in the argtypes tuple will convert a string passed as argument into a bytes object using ctypes conversion rules.

New: It is now possible to put items in argtypes which are not ctypes types, but each item must have a from_param() method which returns a value usable as argument (integer, string, ctypes instance). 新增:现在可以将项目放入不是ctypes类型的argtypes中,但每个项目必须有一个from_param()方法,该方法返回一个可用作参数的值(integer、string、ctypes实例)。This allows defining adapters that can adapt custom objects as function parameters.这允许定义可以将自定义对象调整为函数参数的适配器。

errcheck

Assign a Python function or another callable to this attribute. 将Python函数或其他可调用函数分配给该属性。The callable will be called with three or more arguments:将使用三个或更多参数调用可调用项:

callable(result, func, arguments)

result is what the foreign function returns, as specified by the restype attribute.是外部函数返回的内容,由restype属性指定。

func is the foreign function object itself, this allows reusing the same callable object to check or post process the results of several functions.是外部函数对象本身,这允许重用相同的可调用对象来检查或后处理多个函数的结果。

arguments is a tuple containing the parameters originally passed to the function call, this allows specializing the behavior on the arguments used.是一个元组,包含最初传递给函数调用的参数,这允许专门化所用参数的行为。

The object that this function returns will be returned from the foreign function call, but it can also check the result value and raise an exception if the foreign function call failed.此函数返回的对象将从外部函数调用返回,但它也可以检查结果值,并在外部函数调用失败时引发异常。

exceptionctypes.ArgumentError

This exception is raised when a foreign function call cannot convert one of the passed arguments.当外部函数调用无法转换传递的参数之一时,会引发此异常。

On Windows, when a foreign function call raises a system exception (for example, due to an access violation), it will be captured and replaced with a suitable Python exception. 在Windows上,当外部函数调用引发系统异常(例如,由于访问冲突)时,它将被捕获并替换为合适的Python异常。Further, an auditing event ctypes.seh_exception with argument code will be raised, allowing an audit hook to replace the exception with its own.此外,将引发带有参数代码的审计事件ctypes.seh_exception,允许审计钩子将异常替换为自己的异常。

Some ways to invoke foreign function calls may raise an auditing event ctypes.call_function with arguments function pointer and arguments.某些调用外部函数调用的方法可能会引发带有参数function pointerarguments的审核事件ctypes.call_function

Function prototypes功能原型

Foreign functions can also be created by instantiating function prototypes. 还可以通过实例化函数原型来创建外部函数。Function prototypes are similar to function prototypes in C; they describe a function (return type, argument types, calling convention) without defining an implementation. 功能原型类似于C语言中的功能原型;它们描述函数(返回类型、参数类型、调用约定)而不定义实现。The factory functions must be called with the desired result type and the argument types of the function, and can be used as decorator factories, and as such, be applied to functions through the @wrapper syntax. 工厂函数必须使用所需的结果类型和函数的参数类型进行调用,并且可以用作装饰工厂,因此可以通过@wrapper语法应用于函数。See Callback functions for examples.有关示例,请参阅回调函数

ctypes.CFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)

The returned function prototype creates functions that use the standard C calling convention. 返回的函数原型创建使用标准C调用约定的函数。The function will release the GIL during the call. 函数将在调用期间释放GIL。If use_errno is set to true, the ctypes private copy of the system errno variable is exchanged with the real errno value before and after the call; use_last_error does the same for the Windows error code.

ctypes.WINFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)

Windows only: The returned function prototype creates functions that use the stdcall calling convention, except on Windows CE where WINFUNCTYPE() is the same as CFUNCTYPE(). The function will release the GIL during the call. use_errno and use_last_error have the same meaning as above.

ctypes.PYFUNCTYPE(restype, *argtypes)

The returned function prototype creates functions that use the Python calling convention. 返回的函数原型创建使用Python调用约定的函数。The function will not release the GIL during the call.函数在调用期间不会释放GIL。

Function prototypes created by these factory functions can be instantiated in different ways, depending on the type and number of the parameters in the call:根据调用中参数的类型和数量,这些工厂函数创建的函数原型可以以不同的方式进行实例化:

prototype(address)

Returns a foreign function at the specified address which must be an integer.返回指定地址处的外部函数,该函数必须是整数。

prototype(callable)

Create a C callable function (a callback function) from a Python callable.从Pythoncallable创建C可调用函数(回调函数)。

prototype(func_spec[, paramflags])

Returns a foreign function exported by a shared library. 返回共享库导出的外部函数。func_spec must be a 2-tuple (name_or_ordinal, library). 必须是2元组(name_or_ordinal, library)The first item is the name of the exported function as string, or the ordinal of the exported function as small integer. 第一项是作为字符串的导出函数的名称,或作为小整数的导出函数序号。The second item is the shared library instance.第二项是共享库实例。

prototype(vtbl_index, name[, paramflags[, iid]])

Returns a foreign function that will call a COM method. vtbl_index is the index into the virtual function table, a small non-negative integer. name is name of the COM method. iid is an optional pointer to the interface identifier which is used in extended error reporting.

COM methods use a special calling convention: They require a pointer to the COM interface as first argument, in addition to those parameters that are specified in the argtypes tuple.

The optional paramflags parameter creates foreign function wrappers with much more functionality than the features described above.可选的paramflags参数创建的外部函数包装器的功能比上面描述的功能多得多。

paramflags must be a tuple of the same length as argtypes.必须是与argtypes长度相同的元组。

Each item in this tuple contains further information about a parameter, it must be a tuple containing one, two, or three items.此元组中的每个项都包含有关参数的更多信息,它必须是包含一个、两个或三个项的元组。

The first item is an integer containing a combination of direction flags for the parameter:第一项是包含参数方向标志组合的整数:

1

Specifies an input parameter to the function.指定函数的输入参数。

2

Output parameter. 输出参数。The foreign function fills in a value.外部函数填充一个值。

4

Input parameter which defaults to the integer zero.默认为整数零的输入参数。

The optional second item is the parameter name as string. 可选的第二项是字符串形式的参数名。If this is specified, the foreign function can be called with named parameters.如果指定了此选项,则可以使用命名参数调用外部函数。

The optional third item is the default value for this parameter.可选的第三项是此参数的默认值。

This example demonstrates how to wrap the Windows MessageBoxW function so that it supports default parameters and named arguments. 此示例演示如何包装Windows MessageBoxW函数,以便它支持默认参数和命名参数。The C declaration from the windows header file is this:windows头文件中的C声明如下:

WINUSERAPI int WINAPI
MessageBoxW(
HWND hWnd,
LPCWSTR lpText,
LPCWSTR lpCaption,
UINT uType);

Here is the wrapping with ctypes:这是带有ctypes的包装:

>>> from ctypes import c_int, WINFUNCTYPE, windll
>>> from ctypes.wintypes import HWND, LPCWSTR, UINT
>>> prototype = WINFUNCTYPE(c_int, HWND, LPCWSTR, LPCWSTR, UINT)
>>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", "Hello from ctypes"), (1, "flags", 0)
>>> MessageBox = prototype(("MessageBoxW", windll.user32), paramflags)

The MessageBox foreign function can now be called in these ways:现在可以通过以下方式调用MessageBox外部函数:

>>> MessageBox()
>>> MessageBox(text="Spam, spam, spam")
>>> MessageBox(flags=2, text="foo bar")

A second example demonstrates output parameters. 第二个示例演示了输出参数。The win32 GetWindowRect function retrieves the dimensions of a specified window by copying them into RECT structure that the caller has to supply. win32 GetWindowRect函数通过将指定窗口的维度复制到调用程序必须提供的RECT结构中来检索这些维度。Here is the C declaration:以下是C声明:

WINUSERAPI BOOL WINAPI
GetWindowRect(
HWND hWnd,
LPRECT lpRect);

Here is the wrapping with ctypes:这是带有ctypes的包装:

>>> from ctypes import POINTER, WINFUNCTYPE, windll, WinError
>>> from ctypes.wintypes import BOOL, HWND, RECT
>>> prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT))
>>> paramflags = (1, "hwnd"), (2, "lprect")
>>> GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags)
>>>

Functions with output parameters will automatically return the output parameter value if there is a single one, or a tuple containing the output parameter values when there are more than one, so the GetWindowRect function now returns a RECT instance, when called.如果只有一个输出参数值,则带有输出参数的函数将自动返回输出参数值;如果有多个输出参数,则包含输出参数值的元组将自动返回,因此GetWindowRect函数现在在调用时返回RECT实例。

Output parameters can be combined with the errcheck protocol to do further output processing and error checking. The win32 GetWindowRect api function returns a BOOL to signal success or failure, so this function could do the error checking, and raises an exception when the api call failed:

>>> def errcheck(result, func, args):
... if not result:
... raise WinError()
... return args
...
>>> GetWindowRect.errcheck = errcheck
>>>

If the errcheck function returns the argument tuple it receives unchanged, ctypes continues the normal processing it does on the output parameters. 如果errcheck函数返回它收到的参数元组不变,则ctypes将继续它对输出参数所做的正常处理。If you want to return a tuple of window coordinates instead of a RECT instance, you can retrieve the fields in the function and return them instead, the normal processing will no longer take place:如果要返回窗口坐标元组而不是RECT实例,可以检索函数中的字段并返回它们,正常处理将不再发生:

>>> def errcheck(result, func, args):
... if not result:
... raise WinError()
... rc = args[1]
... return rc.left, rc.top, rc.bottom, rc.right
...
>>> GetWindowRect.errcheck = errcheck
>>>

Utility functions实用程序功能

ctypes.addressof(obj)

Returns the address of the memory buffer as integer. 以整数形式返回内存缓冲区的地址。obj must be an instance of a ctypes type.必须是ctypes类型的实例。

Raises an auditing event ctypes.addressof with argument obj.使用参数obj引发审核事件ctypes.addressof

ctypes.alignment(obj_or_type)

Returns the alignment requirements of a ctypes type. 返回ctypes类型的对齐要求。obj_or_type must be a ctypes type or instance.必须是ctypes类型或实例。

ctypes.byref(obj[, offset])

Returns a light-weight pointer to obj, which must be an instance of a ctypes type. 返回指向obj的轻量级指针,该指针必须是ctypes类型的实例。offset defaults to zero, and must be an integer that will be added to the internal pointer value.默认为零,并且必须是将添加到内部指针值的整数。

byref(obj, offset) corresponds to this C code:对应于此C代码:

(((char *)&obj) + offset)

The returned object can only be used as a foreign function call parameter. 返回的对象只能用作外部函数调用参数。It behaves similar to pointer(obj), but the construction is a lot faster.它的行为类似于pointer(obj),但构造速度要快得多。

ctypes.cast(obj, type)

This function is similar to the cast operator in C. 此函数类似于C中的转换运算符。It returns a new instance of type which points to the same memory block as obj. 它返回一个type的新实例,该实例指向与obj相同的内存块。type must be a pointer type, and obj must be an object that can be interpreted as a pointer.必须是指针类型,obj必须是可以解释为指针的对象。

ctypes.create_string_buffer(init_or_size, size=None)

This function creates a mutable character buffer. 此函数用于创建可变字符缓冲区。The returned object is a ctypes array of c_char.返回的对象是c_char的ctypes数组。

init_or_size must be an integer which specifies the size of the array, or a bytes object which will be used to initialize the array items.必须是指定数组大小的整数,或者是将用于初始化数组项的字节对象。

If a bytes object is specified as first argument, the buffer is made one item larger than its length so that the last element in the array is a NUL termination character. 如果将bytes对象指定为第一个参数,则缓冲区将比其长度大一项,以便数组中的最后一个元素是NUL终止字符。An integer can be passed as second argument which allows specifying the size of the array if the length of the bytes should not be used.整数可以作为第二个参数传递,如果不应使用字节长度,则可以指定数组的大小。

Raises an auditing event ctypes.create_string_buffer with arguments init, size.使用参数initsize引发审核事件ctypes.create_string_buffer

ctypes.create_unicode_buffer(init_or_size, size=None)

This function creates a mutable unicode character buffer. 此函数用于创建可变unicode字符缓冲区。The returned object is a ctypes array of c_wchar.返回的对象是c_wchar的ctypes数组。

init_or_size must be an integer which specifies the size of the array, or a string which will be used to initialize the array items.必须是指定数组大小的整数,或将用于初始化数组项的字符串。

If a string is specified as first argument, the buffer is made one item larger than the length of the string so that the last element in the array is a NUL termination character. 如果将字符串指定为第一个参数,则缓冲区将比字符串长度大一项,以便数组中的最后一个元素是NUL终止字符。An integer can be passed as second argument which allows specifying the size of the array if the length of the string should not be used.整数可以作为第二个参数传递,如果不应使用字符串的长度,则可以指定数组的大小。

Raises an auditing event ctypes.create_unicode_buffer with arguments init, size.使用参数initsize引发审核事件ctypes.create_unicode_buffer

ctypes.DllCanUnloadNow()

Windows only: This function is a hook which allows implementing in-process COM servers with ctypes. 仅限Windows:此函数是一个钩子,允许使用ctype实现进程内COM服务器。It is called from the DllCanUnloadNow function that the _ctypes extension dll exports._ctypes扩展dll导出的DllCanUnloadNow函数调用它。

ctypes.DllGetClassObject()

Windows only: This function is a hook which allows implementing in-process COM servers with ctypes. 仅限Windows:此函数是一个钩子,允许使用ctype实现进程内COM服务器。It is called from the DllGetClassObject function that the _ctypes extension dll exports._ctypes扩展dll导出的DllGetClassObject函数调用它。

ctypes.util.find_library(name)

Try to find a library and return a pathname. 尝试查找库并返回路径名。name is the library name without any prefix like lib, suffix like .so, .dylib or version number (this is the form used for the posix linker option -l). If no library can be found, returns None.

The exact functionality is system dependent.具体功能取决于系统。

ctypes.util.find_msvcrt()

Windows only: return the filename of the VC runtime library used by Python, and by the extension modules. 仅限Windows:返回Python和扩展模块使用的VC运行库的文件名。If the name of the library cannot be determined, None is returned.如果无法确定库的名称,则返回None

If you need to free memory, for example, allocated by an extension module with a call to the free(void *), it is important that you use the function in the same library that allocated the memory.如果您需要释放内存,例如,通过调用free(void *)来释放扩展模块分配的内存,请务必使用分配内存的同一库中的函数。

ctypes.FormatError([code])

Windows only: Returns a textual description of the error code code. 仅限Windows:返回错误代码code的文本描述。If no error code is specified, the last error code is used by calling the Windows api function GetLastError.如果未指定错误代码,则通过调用Windows api函数GetLastError使用最后一个错误代码。

ctypes.GetLastError()

Windows only: Returns the last error code set by Windows in the calling thread. 仅限Windows:返回Windows在调用线程中设置的最后一个错误代码。This function calls the Windows GetLastError() function directly, it does not return the ctypes-private copy of the error code.此函数直接调用Windows GetLastError()函数,它不返回错误代码的ctypes私有副本。

ctypes.get_errno()

Returns the current value of the ctypes-private copy of the system errno variable in the calling thread.

Raises an auditing event ctypes.get_errno with no arguments.

ctypes.get_last_error()

Windows only: returns the current value of the ctypes-private copy of the system LastError variable in the calling thread.仅限Windows:返回调用线程中系统LastError变量的ctypes私有副本的当前值。

Raises an auditing event ctypes.get_last_error with no arguments.

ctypes.memmove(dst, src, count)

Same as the standard C memmove library function: copies count bytes from src to dst. dst and src must be integers or ctypes instances that can be converted to pointers.

ctypes.memset(dst, c, count)

Same as the standard C memset library function: fills the memory block at address dst with count bytes of value c. dst must be an integer specifying an address, or a ctypes instance.

ctypes.POINTER(type)

This factory function creates and returns a new ctypes pointer type. 这个工厂函数创建并返回一个新的ctypes指针类型。Pointer types are cached and reused internally, so calling this function repeatedly is cheap. 指针类型在内部被缓存和重用,因此重复调用此函数的成本很低。type must be a ctypes type.必须是ctypes类型。

ctypes.pointer(obj)

This function creates a new pointer instance, pointing to obj. 此函数用于创建一个指向obj的新指针实例。The returned object is of the type POINTER(type(obj)).返回的对象类型为POINTER(type(obj))

Note: If you just want to pass a pointer to an object to a foreign function call, you should use byref(obj) which is much faster.注意:如果您只想将指向对象的指针传递给外部函数调用,那么应该使用byref(obj),这要快得多。

ctypes.resize(obj, size)

This function resizes the internal memory buffer of obj, which must be an instance of a ctypes type. It is not possible to make the buffer smaller than the native size of the objects type, as given by sizeof(type(obj)), but it is possible to enlarge the buffer.

ctypes.set_errno(value)

Set the current value of the ctypes-private copy of the system errno variable in the calling thread to value and return the previous value.

Raises an auditing event ctypes.set_errno with argument errno.

ctypes.set_last_error(value)

Windows only: set the current value of the ctypes-private copy of the system LastError variable in the calling thread to value and return the previous value.

Raises an auditing event ctypes.set_last_error with argument error.

ctypes.sizeof(obj_or_type)

Returns the size in bytes of a ctypes type or instance memory buffer. 返回ctypes类型或实例内存缓冲区的字节大小。Does the same as the C sizeof operator.执行与C sizeof运算符相同的操作。

ctypes.string_at(address, size=- 1)

This function returns the C string starting at memory address address as a bytes object. 此函数将从内存地址address开始的C字符串作为字节对象返回。If size is specified, it is used as size, otherwise the string is assumed to be zero-terminated.如果指定了size,则将其用作size,否则假定字符串以零结尾。

Raises an auditing event ctypes.string_at with arguments address, size.

ctypes.WinError(code=None, descr=None)

Windows only: this function is probably the worst-named thing in ctypes. 仅限Windows:此函数可能是ctypes中命名最差的函数。It creates an instance of OSError. 它创建OSError的实例。If code is not specified, GetLastError is called to determine the error code. If descr is not specified, FormatError() is called to get a textual description of the error.

Changed in version 3.3:版本3.3中更改: An instance of WindowsError used to be created.用于创建WindowsError的实例。

ctypes.wstring_at(address, size=- 1)

This function returns the wide character string starting at memory address address as a string. 此函数将从内存地址address开始的宽字符串作为字符串返回。If size is specified, it is used as the number of characters of the string, otherwise the string is assumed to be zero-terminated.如果指定了size,则将其用作字符串的字符数,否则假定字符串以零结尾。

Raises an auditing event ctypes.wstring_at with arguments address, size.使用参数addresssize引发审核事件ctypes.wstring_at

Data types数据类型

classctypes._CData

This non-public class is the common base class of all ctypes data types. 这个非公共类是所有ctypes数据类型的公共基类。Among other things, all ctypes type instances contain a memory block that hold C compatible data; the address of the memory block is returned by the addressof() helper function. 除此之外,所有ctypes类型实例都包含一个存储C兼容数据的内存块;内存块的地址由addressof()助手函数返回。Another instance variable is exposed as _objects; this contains other Python objects that need to be kept alive in case the memory block contains pointers.另一个实例变量显示为_objects;它包含其他需要保持活动状态的Python对象,以防内存块包含指针。

Common methods of ctypes data types, these are all class methods (to be exact, they are methods of the metaclass):

from_buffer(source[, offset])

This method returns a ctypes instance that shares the buffer of the source object. The source object must support the writeable buffer interface. The optional offset parameter specifies an offset into the source buffer in bytes; the default is zero. If the source buffer is not large enough a ValueError is raised.

Raises an auditing event ctypes.cdata/buffer with arguments pointer, size, offset.

from_buffer_copy(source[, offset])

This method creates a ctypes instance, copying the buffer from the source object buffer which must be readable. The optional offset parameter specifies an offset into the source buffer in bytes; the default is zero. If the source buffer is not large enough a ValueError is raised.

Raises an auditing event ctypes.cdata/buffer with arguments pointer, size, offset.使用参数pointersizeoffset引发审核事件ctypes.cdata/buffer

from_address(address)

This method returns a ctypes type instance using the memory specified by address which must be an integer.此方法使用address指定的内存返回ctypes类型实例,该内存必须是整数。

This method, and others that indirectly call this method, raises an auditing event ctypes.cdata with argument address.此方法以及其他间接调用此方法的方法将引发一个具有参数address审核事件ctypes.cdata

from_param(obj)

This method adapts obj to a ctypes type. 此方法将obj调整为ctypes类型。It is called with the actual object used in a foreign function call when the type is present in the foreign function’s argtypes tuple; it must return an object that can be used as a function call parameter.当类型存在于外部函数的argtypes元组中时,使用外部函数调用中使用的实际对象来调用它;它必须返回一个可以用作函数调用参数的对象。

All ctypes data types have a default implementation of this classmethod that normally returns obj if that is an instance of the type. 所有ctypes数据类型都有这个类方法的默认实现,如果obj是该类型的实例,它通常会返回obj。Some types accept other objects as well.某些类型也接受其他对象。

in_dll(library, name)

This method returns a ctypes type instance exported by a shared library. 此方法返回由共享库导出的ctypes类型实例。name is the name of the symbol that exports the data, library is the loaded shared library.name是导出数据的符号的名称,library是加载的共享库。

Common instance variables of ctypes data types:ctypes数据类型的常见实例变量:

_b_base_

Sometimes ctypes data instances do not own the memory block they contain, instead they share part of the memory block of a base object. 有时ctypes数据实例并不拥有它们包含的内存块,而是共享基本对象的部分内存块。The _b_base_ read-only member is the root ctypes object that owns the memory block._b_base_只读成员是拥有内存块的根ctypes对象。

_b_needsfree_

This read-only variable is true when the ctypes data instance has allocated the memory block itself, false otherwise.当ctypes数据实例已分配内存块本身时,此只读变量为true,否则为false

_objects

This member is either None or a dictionary containing Python objects that need to be kept alive so that the memory block contents is kept valid. 该成员要么是None,要么是包含需要保持活动状态的Python对象的字典,以便内存块内容保持有效。This object is only exposed for debugging; never modify the contents of this dictionary.此对象仅用于调试;永远不要修改这本词典的内容。

Fundamental data types基本数据类型

classctypes._SimpleCData

This non-public class is the base class of all fundamental ctypes data types. 这个非公共类是所有基本ctypes数据类型的基类。It is mentioned here because it contains the common attributes of the fundamental ctypes data types. 这里之所以提到它,是因为它包含基本ctypes数据类型的公共属性。_SimpleCData is a subclass of _CData, so it inherits their methods and attributes. _CData的子类,因此它继承了它们的方法和属性。ctypes data types that are not and do not contain pointers can now be pickled.现在可以对不包含指针和不包含指针的ctypes数据类型进行pickle处理。

Instances have a single attribute:实例具有单个属性:

value

This attribute contains the actual value of the instance. 此属性包含实例的实际值。For integer and pointer types, it is an integer, for character types, it is a single character bytes object or string, for character pointer types it is a Python bytes object or string.对于整数和指针类型,它是一个整数;对于字符类型,它就是一个单字符字节对象或字符串;对于字符指针类型,则是一个Python字节对象或串。

When the value attribute is retrieved from a ctypes instance, usually a new object is returned each time. 从ctypes实例检索value属性时,通常每次都会返回一个新对象。ctypes does not implement original object return, always a new object is constructed. The same is true for all other ctypes object instances.

Fundamental data types, when returned as foreign function call results, or, for example, by retrieving structure field members or array items, are transparently converted to native Python types. 当作为外部函数调用结果返回时,或者例如通过检索结构字段成员或数组项返回时,基本数据类型将透明地转换为本机Python类型。In other words, if a foreign function has a restype of c_char_p, you will always receive a Python bytes object, not a c_char_p instance.

Subclasses of fundamental data types do not inherit this behavior. So, if a foreign functions restype is a subclass of c_void_p, you will receive an instance of this subclass from the function call. Of course, you can get the value of the pointer by accessing the value attribute.

These are the fundamental ctypes data types:以下是基本的ctypes数据类型:

classctypes.c_byte

Represents the C signed char datatype, and interprets the value as small integer. The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。

classctypes.c_char

Represents the C char datatype, and interprets the value as a single character. 表示Cchar数据类型,并将该值解释为单个字符。The constructor accepts an optional string initializer, the length of the string must be exactly one character.构造函数接受可选的字符串初始值设定项,字符串的长度必须正好是一个字符。

classctypes.c_char_p

Represents the C char* datatype when it points to a zero-terminated string. For a general character pointer that may also point to binary data, POINTER(c_char) must be used. 对于也可能指向二进制数据的通用字符指针,必须使用POINTER(c_char)The constructor accepts an integer address, or a bytes object.构造函数接受整数地址或字节对象。

classctypes.c_double

Represents the C double datatype. The constructor accepts an optional float initializer.构造函数接受可选的浮点初始值设定项。

classctypes.c_longdouble

Represents the C long double datatype. The constructor accepts an optional float initializer. 构造函数接受可选的浮点初始值设定项。On platforms where sizeof(long double) == sizeof(double) it is an alias to c_double.

classctypes.c_float

Represents the C float datatype. The constructor accepts an optional float initializer.构造函数接受可选的浮点初始值设定项。

classctypes.c_int

Represents the C signed int datatype. The constructor accepts an optional integer initializer; no overflow checking is done. 构造函数接受可选的整数初始值设定项;没有进行溢出检查。On platforms where sizeof(int) == sizeof(long) it is an alias to c_long.

classctypes.c_int8

Represents the C 8-bit signed int datatype. Usually an alias for c_byte.

classctypes.c_int16

Represents the C 16-bit signed int datatype. Usually an alias for c_short.

classctypes.c_int32

Represents the C 32-bit signed int datatype. Usually an alias for c_int.

classctypes.c_int64

Represents the C 64-bit signed int datatype. Usually an alias for c_longlong.

classctypes.c_long

Represents the C signed long datatype. The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。

classctypes.c_longlong

Represents the C signed long long datatype. The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。

classctypes.c_short

Represents the C signed short datatype. The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。

classctypes.c_size_t

Represents the C size_t datatype.

classctypes.c_ssize_t

Represents the C ssize_t datatype.

New in version 3.2.版本3.2中新增。

classctypes.c_ubyte

Represents the C unsigned char datatype, it interprets the value as small integer. The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。

classctypes.c_uint

Represents the C unsigned int datatype. The constructor accepts an optional integer initializer; no overflow checking is done. 构造函数接受可选的整数初始值设定项;没有进行溢出检查。On platforms where sizeof(int) == sizeof(long) it is an alias for c_ulong.

classctypes.c_uint8

Represents the C 8-bit unsigned int datatype. Usually an alias for c_ubyte.

classctypes.c_uint16

Represents the C 16-bit unsigned int datatype. Usually an alias for c_ushort.

classctypes.c_uint32

Represents the C 32-bit unsigned int datatype. Usually an alias for c_uint.

classctypes.c_uint64

Represents the C 64-bit unsigned int datatype. Usually an alias for c_ulonglong.

classctypes.c_ulong

Represents the C unsigned long datatype. The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。

classctypes.c_ulonglong

Represents the C unsigned long long datatype. The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。

classctypes.c_ushort

Represents the C unsigned short datatype. The constructor accepts an optional integer initializer; no overflow checking is done.构造函数接受可选的整数初始值设定项;没有进行溢出检查。

classctypes.c_void_p

Represents the C void* type. The value is represented as integer. The constructor accepts an optional integer initializer.构造函数接受可选的整数初始值设定项。

classctypes.c_wchar

Represents the C wchar_t datatype, and interprets the value as a single character unicode string. The constructor accepts an optional string initializer, the length of the string must be exactly one character.构造函数接受可选的字符串初始值设定项,字符串的长度必须正好是一个字符。

classctypes.c_wchar_p

Represents the C wchar_t* datatype, which must be a pointer to a zero-terminated wide character string. The constructor accepts an integer address, or a string.构造函数接受整数地址或字符串。

classctypes.c_bool

Represent the C bool datatype (more accurately, _Bool from C99). Its value can be True or False, and the constructor accepts any object that has a truth value.

classctypes.HRESULT

Windows only: Represents a HRESULT value, which contains success or error information for a function or method call.仅限Windows:表示HRESULT值,其中包含函数或方法调用的成功或错误信息。

classctypes.py_object

Represents the C PyObject* datatype. Calling this without an argument creates a NULL PyObject* pointer.

The ctypes.wintypes module provides quite some other Windows specific data types, for example HWND, WPARAM, or DWORD. Some useful structures like MSG or RECT are also defined.

Structured data types结构化数据类型

classctypes.Union(*args, **kw)

Abstract base class for unions in native byte order.按本机字节顺序的联合的抽象基类。

classctypes.BigEndianStructure(*args, **kw)

Abstract base class for structures in big endian byte order.大端字节顺序表示的结构的抽象基类。

classctypes.LittleEndianStructure(*args, **kw)

Abstract base class for structures in little endian byte order.小端字节顺序表示的结构的抽象基类。

Structures with non-native byte order cannot contain pointer type fields, or any other data types containing pointer type fields.具有非本机字节顺序的结构不能包含指针类型字段,也不能包含任何其他含有指针类型字段的数据类型。

classctypes.Structure(*args, **kw)

Abstract base class for structures in native byte order.原生字节顺序的结构的抽象基类。

Concrete structure and union types must be created by subclassing one of these types, and at least define a _fields_ class variable. 具体的结构和联合类型必须通过对其中一个类型进行子类化来创建,并且至少要定义一个_fields_类变量。ctypes will create descriptors which allow reading and writing the fields by direct attribute accesses. 将创建允许通过直接属性访问读取和写入字段的描述符These are the这些是

_fields_

A sequence defining the structure fields. 定义结构字段的序列。The items must be 2-tuples or 3-tuples. 这些项必须是2元组或3元组。The first item is the name of the field, the second item specifies the type of the field; it can be any ctypes data type.第一项是字段的名称,第二项指定字段的类型;它可以是任何ctypes数据类型。

For integer type fields like c_int, a third optional item can be given. 对于像c_int这样的整数类型字段,可以给出第三个可选项。It must be a small positive integer defining the bit width of the field.它必须是一个小的正整数,用于定义字段的位宽度。

Field names must be unique within one structure or union. 字段名在一个结构或联合中必须唯一。This is not checked, only one field can be accessed when names are repeated.未选中此选项,重复名称时只能访问一个字段。

It is possible to define the _fields_ class variable after the class statement that defines the Structure subclass, this allows creating data types that directly or indirectly reference themselves:

class List(Structure):
pass
List._fields_ = [("pnext", POINTER(List)),
...
]

The _fields_ class variable must, however, be defined before the type is first used (an instance is created, sizeof() is called on it, and so on). Later assignments to the _fields_ class variable will raise an AttributeError.

It is possible to define sub-subclasses of structure types, they inherit the fields of the base class plus the _fields_ defined in the sub-subclass, if any.可以定义结构类型的子子类,它们继承基类的字段加上子类中定义的_fields_(如果有的话)。

_pack_

An optional small integer that allows overriding the alignment of structure fields in the instance. 一个可选的小整数,允许重写实例中结构字段的对齐方式。_pack_ must already be defined when _fields_ is assigned, otherwise it will have no effect.

_anonymous_

An optional sequence that lists the names of unnamed (anonymous) fields. _anonymous_ must be already defined when _fields_ is assigned, otherwise it will have no effect.

The fields listed in this variable must be structure or union type fields. 此变量中列出的字段必须是结构或联合类型字段。ctypes will create descriptors in the structure type that allows accessing the nested fields directly, without the need to create the structure or union field.将以允许直接访问嵌套字段的结构类型创建描述符,而无需创建结构或联合字段。

Here is an example type (Windows):

class _U(Union):
_fields_ = [("lptdesc", POINTER(TYPEDESC)),
("lpadesc", POINTER(ARRAYDESC)),
("hreftype", HREFTYPE)]
class TYPEDESC(Structure):
_anonymous_ = ("u",)
_fields_ = [("u", _U),
("vt", VARTYPE)]

The TYPEDESC structure describes a COM data type, the vt field specifies which one of the union fields is valid. Since the u field is defined as anonymous field, it is now possible to access the members directly off the TYPEDESC instance. td.lptdesc and td.u.lptdesc are equivalent, but the former is faster since it does not need to create a temporary union instance:

td = TYPEDESC()
td.vt = VT_PTR
td.lptdesc = POINTER(some_type)
td.u.lptdesc = POINTER(some_type)

It is possible to define sub-subclasses of structures, they inherit the fields of the base class. 可以定义结构的子子类,它们继承基类的字段。If the subclass definition has a separate _fields_ variable, the fields specified in this are appended to the fields of the base class.如果子类定义有一个单独的_fields_变量,则其中指定的字段将附加到基类的字段中。

Structure and union constructors accept both positional and keyword arguments. 结构构造函数和联合构造函数都接受位置参数和关键字参数。Positional arguments are used to initialize member fields in the same order as they are appear in _fields_. Keyword arguments in the constructor are interpreted as attribute assignments, so they will initialize _fields_ with the same name, or create new attributes for names not present in _fields_.

Arrays and pointers数组和指针

classctypes.Array(*args)

Abstract base class for arrays.数组的抽象基类。

The recommended way to create concrete array types is by multiplying any ctypes data type with a non-negative integer. 创建具体数组类型的推荐方法是将任何ctypes数据类型与非负整数相乘。Alternatively, you can subclass this type and define _length_ and _type_ class variables. Array elements can be read and written using standard subscript and slice accesses; for slice reads, the resulting object is not itself an Array.数组元素可以使用标准下标和切片访问进行读写;对于切片读取,生成的对象本身不是Array

_length_

A positive integer specifying the number of elements in the array. 一个正整数,指定数组中的元素数。Out-of-range subscripts result in an IndexError. 下标超出范围会导致IndexErrorWill be returned by len().将由len()返回。

_type_

Specifies the type of each element in the array.指定阵列中每个元素的类型。

Array subclass constructors accept positional arguments, used to initialize the elements in order.数组子类构造函数接受位置参数,用于按顺序初始化元素。

classctypes._Pointer

Private, abstract base class for pointers.指针的rivate抽象基类。

Concrete pointer types are created by calling POINTER() with the type that will be pointed to; this is done automatically by pointer().

If a pointer points to an array, its elements can be read and written using standard subscript and slice accesses. 如果指针指向数组,则可以使用标准下标和切片访问来读取和写入其元素。Pointer objects have no size, so len() will raise TypeError. 指针对象没有大小,因此len()将引发TypeErrorNegative subscripts will read from the memory before the pointer (as in C), and out-of-range subscripts will probably crash with an access violation (if you’re lucky).负下标将在指针之前从内存中读取(如C中所示),超出范围的下标可能会因访问冲突而崩溃(如果幸运的话)。

_type_

Specifies the type pointed to.指定指向的类型。

contents

Returns the object to which to pointer points. 返回指针指向的对象。Assigning to this attribute changes the pointer to point to the assigned object.指定给该属性会将指针更改为指向指定的对象。