ctypes — Eine Fremdfunktionsbibliothek für Python

Quellcode: Lib/ctypes


ctypes ist eine Fremdfunktionsbibliothek für Python. Sie stellt C-kompatible Datentypen bereit und ermöglicht das Aufrufen von Funktionen in DLLs oder Shared Libraries. Sie kann verwendet werden, um diese Bibliotheken in reinem Python einzubinden.

ctypes Tutorial

Hinweis: Die Codebeispiele in diesem Tutorial verwenden doctest, um sicherzustellen, dass sie tatsächlich funktionieren. Da einige Codebeispiele unter Linux, Windows oder macOS unterschiedlich verhalten, enthalten sie doctest-Direktiven in Kommentaren.

Hinweis: Einige Codebeispiele beziehen sich auf den c_int Typ von ctypes. Auf Plattformen, auf denen sizeof(long) == sizeof(int) ist, ist er ein Alias für c_long. Daher sollten Sie nicht verwirrt sein, wenn c_long ausgegeben wird, wenn Sie c_int erwarten – es handelt sich tatsächlich um denselben Typ.

Zugriff auf Funktionen aus geladenen DLLs

Funktionen werden als Attribute von DLL-Objekten abgerufen.

>>> 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
>>>

Beachten Sie, dass win32-System-DLLs wie kernel32 und user32 oft sowohl ANSI- als auch UNICODE-Versionen einer Funktion exportieren. Die UNICODE-Version wird mit einem angehängten W benannt, während die ANSI-Version mit einem angehängten A benannt wird. Die win32-Funktion GetModuleHandle, die ein *Modulhandle* für einen gegebenen Modulnamen zurückgibt, hat den folgenden C-Prototyp, und ein Makro wird verwendet, um eine davon als GetModuleHandle verfügbar zu machen, je nachdem, ob UNICODE definiert ist oder nicht.

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

windll versucht nicht, eine davon magisch auszuwählen; Sie müssen auf die benötigte Version zugreifen, indem Sie explizit GetModuleHandleA oder GetModuleHandleW angeben und sie dann mit Byte- oder Zeichenkettenobjekten bzw. aufrufen.

Manchmal exportieren DLLs Funktionen mit Namen, die keine gültigen Python-Bezeichner sind, wie z. B. "??2@YAPAXI@Z". In diesem Fall müssen Sie getattr() verwenden, um die Funktion abzurufen.

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

Unter Windows exportieren einige DLLs Funktionen nicht nach Namen, sondern nach Ordinalzahl. Diese Funktionen können durch Indizierung des DLL-Objekts mit der Ordinalzahl abgerufen werden.

>>> 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
>>>

Aufrufen von Funktionen

Sie können diese Funktionen wie jede andere Python-Funktion aufrufen. Dieses Beispiel verwendet die Funktion rand(), die keine Argumente nimmt und eine Pseudozufallszahl zurückgibt.

>>> print(libc.rand())
1804289383

Unter Windows können Sie die Funktion GetModuleHandleA() aufrufen, die ein win32-Modulhandle zurückgibt (wobei None als einziges Argument übergeben wird, um sie mit einem NULL-Zeiger aufzurufen).

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

ValueError wird ausgelöst, wenn Sie eine stdcall-Funktion mit der cdecl-Aufrufkonvention oder umgekehrt aufrufen.

>>> 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)
>>>

Um die korrekte Aufrufkonvention herauszufinden, müssen Sie die C-Headerdatei oder die Dokumentation der aufzurufenden Funktion konsultieren.

Unter Windows verwendet ctypes die win32-Strukturierte Ausnahmebehandlung, um Abstürze durch allgemeine Schutzfehler zu verhindern, wenn Funktionen mit ungültigen Argumentwerten aufgerufen werden.

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

Es gibt jedoch genügend Möglichkeiten, Python mit ctypes zum Absturz zu bringen, sodass Sie trotzdem vorsichtig sein sollten. Das Modul faulthandler kann bei der Fehlersuche (z. B. bei Segmentierungsfehlern, die durch fehlerhafte C-Bibliotheksaufrufe verursacht werden) hilfreich sein.

None, Ganzzahlen, Bytes-Objekte und (Unicode-)Strings sind die einzigen nativen Python-Objekte, die direkt als Parameter in diesen Funktionsaufrufen verwendet werden können. None wird als C NULL-Zeiger übergeben, Bytes-Objekte und Strings werden als Zeiger auf den Speicherblock übergeben, der ihre Daten enthält (char* oder wchar_t*). Python-Ganzzahlen werden als Standard-C-int-Typ der Plattform übergeben, ihr Wert wird maskiert, um in den C-Typ zu passen.

Bevor wir uns dem Aufrufen von Funktionen mit anderen Parametertypen zuwenden, müssen wir mehr über die Datentypen von ctypes erfahren.

Grundlegende Datentypen

ctypes definiert eine Reihe von primitiven C-kompatiblen Datentypen.

ctypes-Typ

C-Typ

Python Typ

c_bool

_Bool

bool (1)

c_char

char

1-Zeichen Bytes-Objekt

c_wchar

wchar_t

1-Zeichen String

c_byte

char

int

c_ubyte

unsigned char

int

c_short

short

int

c_ushort

unsigned short

int

c_int

int

int

c_int8

int8_t

int

c_int16

int16_t

int

c_int32

int32_t

int

c_int64

int64_t

int

c_uint

unsigned int

int

c_uint8

uint8_t

int

c_uint16

uint16_t

int

c_uint32

uint32_t

int

c_uint64

uint64_t

int

c_long

long

int

c_ulong

unsigned long

int

c_longlong

__int64 oder long long

int

c_ulonglong

unsigned __int64 oder unsigned long long

int

c_size_t

size_t

int

c_ssize_t

ssize_t oder Py_ssize_t

int

c_time_t

time_t

int

c_float

float

float

c_double

double

float

c_longdouble

long double

float

c_char_p

char* (NUL-terminiert)

Bytes-Objekt oder None

c_wchar_p

wchar_t* (NUL-terminiert)

String oder None

c_void_p

void*

Ganzzahl oder None

  1. Der Konstruktor akzeptiert jedes Objekt mit einem Wahrheitswert.

Zusätzlich, wenn IEC 60559-kompatible komplexe Arithmetik (Anhang G) sowohl in C als auch in libffi unterstützt wird, sind die folgenden komplexen Typen verfügbar:

ctypes-Typ

C-Typ

Python Typ

c_float_complex

float complex

komplex

c_double_complex

double complex

komplex

c_longdouble_complex

long double complex

komplex

Alle diese Typen können durch Aufruf mit einem optionalen Initialisierer des richtigen Typs und Werts erstellt werden.

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

Da diese Typen veränderlich sind, kann ihr Wert auch nachträglich geändert werden.

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

Das Zuweisen eines neuen Werts zu Instanzen der Zeigertypen c_char_p, c_wchar_p und c_void_p ändert den *Speicherort*, auf den sie zeigen, *nicht den Inhalt* des Speicherblocks (natürlich nicht, da Python-String-Objekte unveränderlich sind).

>>> 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
>>>

Sie sollten jedoch vorsichtig sein, diese nicht an Funktionen zu übergeben, die Zeiger auf veränderlichen Speicher erwarten. Wenn Sie veränderliche Speicherblöcke benötigen, verfügt ctypes über eine Funktion create_string_buffer(), die diese auf verschiedene Arten erstellt. Der aktuelle Inhalt des Speicherblocks kann über die Eigenschaft raw abgerufen (oder geändert) werden; wenn Sie darauf als NUL-terminierten String zugreifen möchten, verwenden Sie die Eigenschaft 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'
>>>

Die Funktion create_string_buffer() ersetzt die alte Funktion c_buffer() (die noch als Alias verfügbar ist). Um einen veränderlichen Speicherblock zu erstellen, der Unicode-Zeichen vom C-Typ wchar_t enthält, verwenden Sie die Funktion create_unicode_buffer().

Aufrufen von Funktionen, Fortsetzung

Beachten Sie, dass printf auf den tatsächlichen Standardausgabekanal schreibt, *nicht* auf sys.stdout. Diese Beispiele funktionieren daher nur an der Konsolenaufforderung, nicht innerhalb von *IDLE* oder *PythonWin*.

>>> 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>
ctypes.ArgumentError: argument 2: TypeError: Don't know how to convert parameter 2
>>>

Wie bereits erwähnt, müssen alle Python-Typen außer Ganzzahlen, Strings und Bytes-Objekten in ihren entsprechenden ctypes-Typen eingepackt werden, damit sie in den erforderlichen C-Datentyp konvertiert werden können.

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

Aufrufen von variadischen Funktionen

Auf vielen Plattformen ist das Aufrufen variadischer Funktionen über ctypes genau dasselbe wie das Aufrufen von Funktionen mit einer festen Anzahl von Parametern. Auf einigen Plattformen, insbesondere ARM64 für Apple Platforms, ist die Aufrufkonvention für variadische Funktionen anders als für reguläre Funktionen.

Auf diesen Plattformen ist es erforderlich, das Attribut argtypes für die regulären, nicht-variadischen Funktionsargumente anzugeben.

libc.printf.argtypes = [ctypes.c_char_p]

Da die Angabe des Attributs die Portabilität nicht beeinträchtigt, wird empfohlen, argtypes immer für alle variadischen Funktionen anzugeben.

Aufrufen von Funktionen mit eigenen benutzerdefinierten Datentypen

Sie können auch die Argumentkonvertierung von ctypes anpassen, um Instanzen Ihrer eigenen Klassen als Funktionsargumente zu verwenden. ctypes sucht nach einem Attribut _as_parameter_ und verwendet dieses als Funktionsargument. Das Attribut muss eine Ganzzahl, ein String, Bytes, eine ctypes-Instanz oder ein Objekt mit einem Attribut _as_parameter_ sein.

>>> 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
>>>

Wenn Sie die Daten der Instanz nicht in der Instanzvariable _as_parameter_ speichern möchten, könnten Sie eine property definieren, die das Attribut bei Bedarf verfügbar macht.

Angabe der erforderlichen Argumenttypen (Funktionsprototypen)

Es ist möglich, die erforderlichen Argumenttypen von Funktionen, die aus DLLs exportiert werden, anzugeben, indem das Attribut argtypes gesetzt wird.

argtypes muss eine Sequenz von C-Datentypen sein (die Funktion printf() ist hier wahrscheinlich kein gutes Beispiel, da sie je nach Format-String eine variable Anzahl und unterschiedliche Typen von Parametern annimmt, andererseits ist dies praktisch zum Experimentieren mit dieser Funktion).

>>> 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
>>>

Die Angabe eines Formats schützt vor inkompatiblen Argumenttypen (genauso wie ein Prototyp für eine C-Funktion) und versucht, die Argumente in gültige Typen zu konvertieren.

>>> printf(b"%d %d %d", 1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ctypes.ArgumentError: argument 2: TypeError: 'int' object cannot be interpreted as ctypes.c_char_p
>>> printf(b"%s %d %f\n", b"X", 2, 3)
X 2 3.000000
13
>>>

Wenn Sie eigene Klassen definiert haben, die Sie an Funktionsaufrufe übergeben, müssen Sie eine Klassenmethode from_param() für sie implementieren, um sie in der Sequenz argtypes verwenden zu können. Die Klassenmethode from_param() empfängt das Python-Objekt, das an den Funktionsaufruf übergeben wird; sie sollte eine Typüberprüfung oder alles Notwendige durchführen, um sicherzustellen, dass dieses Objekt akzeptabel ist, und dann das Objekt selbst, sein Attribut _as_parameter_ oder was auch immer Sie in diesem Fall als C-Funktionsargument übergeben möchten, zurückgeben. Auch hier sollte das Ergebnis eine Ganzzahl, ein String, Bytes, eine ctypes-Instanz oder ein Objekt mit einem Attribut _as_parameter_ sein.

Rückgabetypen

Standardmäßig wird davon ausgegangen, dass Funktionen den C-int-Typ zurückgeben. Andere Rückgabetypen können durch Setzen des Attributs restype des Funktionsergebnisses angegeben werden.

Der C-Prototyp von time() lautet time_t time(time_t *). Da time_t möglicherweise einen anderen Typ als der Standardrückgabetyp int hat, sollten Sie das Attribut restype angeben.

>>> libc.time.restype = c_time_t

Die Argumenttypen können mit argtypes angegeben werden.

>>> libc.time.argtypes = (POINTER(c_time_t),)

Um die Funktion mit einem NULL-Zeiger als erstes Argument aufzurufen, verwenden Sie None.

>>> print(libc.time(None))
1150640792

Hier ist ein fortgeschritteneres Beispiel: Es verwendet die Funktion strchr(), die einen String-Zeiger und ein Zeichen erwartet und einen Zeiger auf einen String zurückgibt.

>>> 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
>>>

Wenn Sie die ord("x")-Aufrufe oben vermeiden möchten, können Sie das Attribut argtypes setzen, und das zweite Argument wird von einem Python-Byteobjekt mit einem Zeichen in ein C-Zeichen konvertiert.

>>> strchr.restype = c_char_p
>>> strchr.argtypes = [c_char_p, c_char]
>>> strchr(b"abcdef", b"d")
b'def'
>>> strchr(b"abcdef", b"def")
Traceback (most recent call last):
ctypes.ArgumentError: argument 2: TypeError: one character bytes, bytearray or integer expected
>>> print(strchr(b"abcdef", b"x"))
None
>>> strchr(b"abcdef", b"d")
b'def'
>>>

Sie können auch ein aufrufbares Python-Objekt (z. B. eine Funktion oder eine Klasse) als Attribut restype verwenden, wenn die Fremdfunktion eine Ganzzahl zurückgibt. Das aufrufbare Objekt wird mit der *Ganzzahl* aufgerufen, die die C-Funktion zurückgibt, und das Ergebnis dieses Aufrufs wird als Ergebnis Ihres Funktionsaufrufs verwendet. Dies ist nützlich, um Rückgabewerte auf Fehler zu prüfen und automatisch eine Ausnahme auszulösen.

>>> 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 ist eine Funktion, die die Windows-API FormatMessage() aufruft, um die Zeichenfolgendarstellung eines Fehlercodes zu erhalten, und eine Ausnahme *zurückgibt*. WinError nimmt einen optionalen Fehlercode-Parameter entgegen; wenn keiner verwendet wird, ruft sie GetLastError() auf, um ihn abzurufen.

Bitte beachten Sie, dass über das Attribut errcheck ein weitaus leistungsfähigerer Mechanismus zur Fehlerprüfung verfügbar ist; siehe das Referenzhandbuch für Details.

Übergeben von Zeigern (oder: Übergeben von Parametern per Referenz)

Manchmal erwartet eine C-API-Funktion einen *Zeiger* auf einen Datentyp als Parameter, wahrscheinlich um in den entsprechenden Speicherort zu schreiben, oder wenn die Daten zu groß sind, um per Wert übergeben zu werden. Dies wird auch als *Übergeben von Parametern per Referenz* bezeichnet.

ctypes exportiert die Funktion byref(), die zum Übergeben von Parametern per Referenz verwendet wird. Der gleiche Effekt kann mit der Funktion pointer() erzielt werden, obwohl pointer() viel mehr Arbeit leistet, da sie ein echtes Zeigerobjekt erstellt. Daher ist es schneller, byref() zu verwenden, wenn Sie das Zeigerobjekt nicht selbst in Python benötigen.

>>> 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'
>>>

Strukturen und Unions

Strukturen und Unions müssen von den Basisklassen Structure und Union ableiten, die im Modul ctypes definiert sind. Jede Unterklasse muss ein Attribut _fields_ definieren. _fields_ muss eine Liste von *2-Tupeln* sein, die einen *Feldnamen* und einen *Feldtyp* enthalten.

Der Feldtyp muss ein ctypes-Typ sein, wie z. B. c_int, oder ein anderer abgeleiteter ctypes-Typ: Struktur, Union, Array, Zeiger.

Hier ist ein einfaches Beispiel für eine POINT-Struktur, die zwei Ganzzahlen namens *x* und *y* enthält und auch zeigt, wie eine Struktur im Konstruktor initialisiert wird.

>>> 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
>>>

Sie können jedoch wesentlich komplexere Strukturen aufbauen. Eine Struktur kann selbst andere Strukturen enthalten, indem sie eine Struktur als Feldtyp verwendet.

Hier ist eine RECT-Struktur, die zwei POINTs namens *upperleft* und *lowerright* enthält.

>>> 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
>>>

Verschachtelte Strukturen können auch auf verschiedene Weise im Konstruktor initialisiert werden.

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

Feld-***Deskriptoren*** können von der *Klasse* abgerufen werden; sie sind nützlich zur Fehlersuche, da sie nützliche Informationen liefern können. Siehe CField.

>>> POINT.x
<ctypes.CField 'x' type=c_int, ofs=0, size=4>
>>> POINT.y
<ctypes.CField 'y' type=c_int, ofs=4, size=4>
>>>

Warnung

ctypes unterstützt nicht das Übergeben von Unions oder Strukturen mit Bitfeldern per Wert an Funktionen. Während dies auf 32-Bit-x86 funktionieren mag, ist es nicht garantiert, dass es im Allgemeinen funktioniert. Unions und Strukturen mit Bitfeldern sollten immer per Zeiger an Funktionen übergeben werden.

Struktur-/Union-Layout, Ausrichtung und Byte-Reihenfolge

Standardmäßig werden Struktur- und Union-Felder so angeordnet, wie es der C-Compiler tut. Es ist möglich, dieses Verhalten vollständig zu überschreiben, indem ein Klassenattribut _layout_ in der Unterklassendefinition angegeben wird; siehe die Attributdokumentation für Details.

Es ist möglich, die maximale Ausrichtung für die Felder und/oder die Struktur selbst anzugeben, indem die Klassenattribute _pack_ und/oder _align_ gesetzt werden, bzw. Siehe die Attributdokumentation für Details.

ctypes verwendet die native Byte-Reihenfolge für Strukturen und Unions. Um Strukturen mit nicht-nativer Byte-Reihenfolge zu erstellen, können Sie eine der Basisklassen BigEndianStructure, LittleEndianStructure, BigEndianUnion und LittleEndianUnion verwenden. Diese Klassen dürfen keine Zeigerfelder enthalten.

Bitfelder in Strukturen und Unions

Es ist möglich, Strukturen und Unions zu erstellen, die Bitfelder enthalten. Bitfelder sind nur für Ganzzahlfelder möglich; die Bitbreite wird als drittes Element in den _fields_-Tupeln angegeben.

>>> class Int(Structure):
...     _fields_ = [("first_16", c_int, 16),
...                 ("second_16", c_int, 16)]
...
>>> print(Int.first_16)
<ctypes.CField 'first_16' type=c_int, ofs=0, bit_size=16, bit_offset=0>
>>> print(Int.second_16)
<ctypes.CField 'second_16' type=c_int, ofs=0, bit_size=16, bit_offset=16>

Es ist wichtig zu beachten, dass die Zuweisung und das Layout von Bitfeldern im Speicher nicht als C-Standard definiert sind; ihre Implementierung ist compilerabhängig. Standardmäßig versucht Python, das Verhalten eines „nativen“ Compilers für die aktuelle Plattform nachzuahmen. Einzelheiten zum Standardverhalten und wie man es ändert, finden Sie im Attribut _layout_.

Arrays

Arrays sind Sequenzen, die eine feste Anzahl von Instanzen desselben Typs enthalten.

Der empfohlene Weg zur Erstellung von Array-Typen ist die Multiplikation eines Datentyps mit einer positiven Ganzzahl.

TenPointsArrayType = POINT * 10

Hier ist ein Beispiel für einen etwas künstlichen Datentyp, eine Struktur, die 4 POINTs neben anderem enthält.

>>> 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
>>>

Instanzen werden auf die übliche Weise erstellt, indem die Klasse aufgerufen wird.

arr = TenPointsArrayType()
for pt in arr:
    print(pt.x, pt.y)

Der obige Code druckt eine Reihe von Zeilen mit 0 0, da der Array-Inhalt mit Nullen initialisiert wird.

Initialisierer des richtigen Typs können ebenfalls angegeben werden.

>>> 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
>>>

Zeiger

Zeigerinstanzen werden durch Aufrufen der Funktion pointer() auf einen ctypes-Typ erstellt.

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

Zeigerinstanzen haben ein Attribut contents, das das Objekt zurückgibt, auf das der Zeiger zeigt, also das `i`-Objekt von oben.

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

Beachten Sie, dass ctypes keine OOR (Original Object Return) hat; es konstruiert bei jedem Abruf eines Attributs ein neues, gleichwertiges Objekt.

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

Das Zuweisen einer anderen c_int-Instanz zum `contents`-Attribut des Zeigers würde dazu führen, dass der Zeiger auf die Speicherstelle zeigt, an der diese gespeichert ist.

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

Zeigerinstanzen können auch mit ganzen Zahlen indiziert werden.

>>> pi[0]
99
>>>

Das Zuweisen zu einem ganzzahligen Index ändert den Wert, auf den gezeigt wird.

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

Es ist auch möglich, andere Indizes als 0 zu verwenden, aber man muss wissen, was man tut, genau wie in C: Man kann auf beliebige Speicherstellen zugreifen oder diese ändern. Im Allgemeinen verwendet man diese Funktion nur, wenn man einen Zeiger von einer C-Funktion erhält und *weiß*, dass der Zeiger tatsächlich auf ein Array und nicht auf ein einzelnes Element zeigt.

Hinter den Kulissen tut die Funktion pointer() mehr als nur Zeigerinstanzen zu erstellen; sie muss zuerst Zeiger-*Typen* erstellen. Dies geschieht mit der Funktion POINTER(), die jeden ctypes-Typ akzeptiert und einen neuen Typ zurückgibt.

>>> 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...>
>>>

Das Aufrufen des Zeigertyps ohne Argument erstellt einen NULL-Zeiger. NULL-Zeiger haben einen Wahrheitswert von False.

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

ctypes prüft auf NULL beim Dereferenzieren von Zeigern (aber das Dereferenzieren ungültiger, nicht-NULL-Zeiger würde Python zum Absturz bringen).

>>> 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
>>>

Thread-Sicherheit ohne den GIL

Ab Python 3.13 kann der GIL in freethreaded Builds deaktiviert werden. In ctypes sind Lese- und Schreibzugriffe auf ein einzelnes Objekt gleichzeitig sicher, aber nicht über mehrere Objekte hinweg.

>>> number = c_int(42)
>>> pointer_a = pointer(number)
>>> pointer_b = pointer(number)

Im obigen Beispiel ist es nur dann sicher, wenn ein Objekt gleichzeitig von mehreren Threads gelesen und geschrieben wird, wenn der GIL deaktiviert ist. Daher kann pointer_a zwischen mehreren Threads geteilt und beschrieben werden, aber nur, wenn pointer_b nicht dasselbe versucht. Wenn dies ein Problem darstellt, sollten Sie eine threading.Lock zur Synchronisierung des Speicherzugriffs verwenden.

>>> import threading
>>> lock = threading.Lock()
>>> # Thread 1
>>> with lock:
...    pointer_a.contents = 24
>>> # Thread 2
>>> with lock:
...    pointer_b.contents = 42

Typkonvertierungen

Normalerweise führt ctypes eine strenge Typenprüfung durch. Das bedeutet, wenn Sie POINTER(c_int) in der argtypes-Liste einer Funktion oder als Typ eines Mitglieds in einer Strukturdefinition haben, werden nur Instanzen genau desselben Typs akzeptiert. Es gibt einige Ausnahmen von dieser Regel, bei denen ctypes andere Objekte akzeptiert. Sie können beispielsweise kompatible Array-Instanzen anstelle von Zeigertypen übergeben. Für POINTER(c_int) akzeptiert ctypes also ein Array von 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
>>>

Wenn ein Funktionsargument in argtypes explizit als Zeigertyp deklariert ist (z. B. POINTER(c_int)), kann ein Objekt des referenzierten Typs (in diesem Fall c_int) an die Funktion übergeben werden. ctypes wendet in diesem Fall automatisch die erforderliche byref()-Konvertierung an.

Um ein POINTER-Typfeld auf NULL zu setzen, können Sie None zuweisen.

>>> bar.values = None
>>>

Manchmal hat man Instanzen inkompatibler Typen. In C kann man einen Typ in einen anderen Typ umwandeln. ctypes stellt eine Funktion cast() bereit, die auf die gleiche Weise verwendet werden kann. Die oben definierte Struktur Bar akzeptiert POINTER(c_int)-Zeiger oder c_int-Arrays für ihr values-Feld, aber keine Instanzen anderer Typen.

>>> 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
>>>

Für diese Fälle ist die Funktion cast() nützlich.

Die Funktion cast() kann verwendet werden, um eine ctypes-Instanz in einen Zeiger auf einen anderen ctypes-Datentyp umzuwandeln. cast() nimmt zwei Parameter entgegen: ein ctypes-Objekt, das ein Zeiger irgendeiner Art ist oder in einen solchen umgewandelt werden kann, und einen ctypes-Zeigertyp. Sie gibt eine Instanz des zweiten Arguments zurück, die denselben Speicherblock wie das erste Argument referenziert.

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

Somit kann cast() verwendet werden, um das Feld values der Struktur Bar zuzuweisen.

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

Unvollständige Typen

Unvollständige Typen sind Strukturen, Unions oder Arrays, deren Mitglieder noch nicht spezifiziert sind. In C werden sie durch Vorwärtsdeklarationen spezifiziert, die später definiert werden.

struct cell; /* forward declaration */

struct cell {
    char *name;
    struct cell *next;
};

Die direkte Übersetzung in ctypes-Code wäre diese, aber sie funktioniert nicht.

>>> 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
>>>

da die neue Klasse class cell in der Klassendefinition selbst nicht verfügbar ist. In ctypes können wir die Klasse cell definieren und das Attribut _fields_ später, nach der Klassendefinition, setzen.

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

Versuchen wir es. Wir erstellen zwei Instanzen von cell, lassen sie aufeinander zeigen und folgen dann ein paar Mal der Zeigerkette.

>>> 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-Funktionen

ctypes ermöglicht die Erstellung von C-aufrufbaren Funktionszeigern aus Python-Aufrufbaren. Diese werden manchmal als Callback-Funktionen bezeichnet.

Zuerst müssen Sie eine Klasse für die Callback-Funktion erstellen. Die Klasse kennt die Aufrufkonvention, den Rückgabetyp sowie die Anzahl und die Typen der Argumente, die diese Funktion empfangen wird.

Die Factory-Funktion CFUNCTYPE() erstellt Typen für Callback-Funktionen mit der cdecl-Aufrufkonvention. Unter Windows erstellt die Factory-Funktion WINFUNCTYPE() Typen für Callback-Funktionen mit der stdcall-Aufrufkonvention.

Beide dieser Factory-Funktionen werden mit dem Ergebnistyp als erstem Argument und den erwarteten Argumenttypen der Callback-Funktion als restlichen Argumenten aufgerufen.

Ich werde hier ein Beispiel präsentieren, das die Standard-C-Bibliotheksfunktion qsort() verwendet, die zum Sortieren von Elementen mithilfe einer Callback-Funktion dient. qsort() wird zum Sortieren eines Arrays von Ganzzahlen verwendet.

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

qsort() muss mit einem Zeiger auf die zu sortierenden Daten, der Anzahl der Elemente im Datenarray, der Größe eines Elements und einem Zeiger auf die Vergleichsfunktion (den Callback) aufgerufen werden. Der Callback wird dann mit zwei Zeigern auf Elemente aufgerufen und muss eine negative Ganzzahl zurückgeben, wenn das erste Element kleiner als das zweite ist, Null, wenn sie gleich sind, und andernfalls eine positive Ganzzahl.

Unser Callback-Funktion empfängt also Zeiger auf Ganzzahlen und muss eine Ganzzahl zurückgeben. Zuerst erstellen wir den Typ für die Callback-Funktion.

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

Zur Einführung hier ein einfacher Callback, der die übergebenen Werte anzeigt.

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

Das Ergebnis

>>> 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
>>>

Jetzt können wir die beiden Elemente tatsächlich vergleichen und ein sinnvolles Ergebnis zurückgeben.

>>> 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
>>>

Wie wir leicht überprüfen können, ist unser Array jetzt sortiert.

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

Die Funktions-Factories können als Decorator-Factories verwendet werden, daher können wir auch Folgendes schreiben:

>>> @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
>>>

Hinweis

Stellen Sie sicher, dass Sie Referenzen auf CFUNCTYPE()-Objekte behalten, solange sie aus C-Code verwendet werden. ctypes tut dies nicht, und wenn Sie es nicht tun, könnten sie vom Garbage Collector eingesammelt werden, was Ihr Programm zum Absturz bringt, wenn ein Callback erfolgt.

Beachten Sie außerdem, dass, wenn die Callback-Funktion in einem Thread aufgerufen wird, der außerhalb der Kontrolle von Python erstellt wurde (z. B. durch den Fremdcode, der den Callback aufruft), ctypes bei jeder Invokation einen neuen Dummy-Python-Thread erstellt. Dieses Verhalten ist für die meisten Zwecke korrekt, bedeutet aber, dass Werte, die mit threading.local gespeichert werden, über verschiedene Callbacks hinweg *nicht* erhalten bleiben, selbst wenn diese Aufrufe vom selben C-Thread aus erfolgen.

Zugriff auf aus DLLs exportierte Werte

Einige Shared Libraries exportieren nicht nur Funktionen, sondern auch Variablen. Ein Beispiel in der Python-Bibliothek selbst ist Py_Version, die Versionsnummer der Python-Laufzeit, kodiert in einer einzigen Konstanten Ganzzahl.

ctypes kann solche Werte mit den Klassenmethoden in_dll() des Typs abrufen. *pythonapi* ist ein vordefiniertes Symbol, das Zugriff auf die Python C API bietet.

>>> version = ctypes.c_int.in_dll(ctypes.pythonapi, "Py_Version")
>>> print(hex(version.value))
0x30c00a0

Ein erweitertes Beispiel, das auch die Verwendung von Zeigern demonstriert, greift auf den von Python exportierten Zeiger PyImport_FrozenModules zu.

Zitieren der Dokumentation für diesen Wert.

Dieser Zeiger wird initialisiert, um auf ein Array von _frozen-Datensätzen zu zeigen, die durch einen Datensatz abgeschlossen werden, dessen Member alle NULL oder Null sind. Wenn ein "eingefrorenes" Modul importiert wird, wird es in dieser Tabelle gesucht. Drittanbietercode könnte damit Tricks machen, um eine dynamisch erstellte Sammlung von "eingefrorenen" Modulen bereitzustellen.

Die Manipulation dieses Zeigers könnte also sogar nützlich sein. Um die Beispielgröße zu begrenzen, zeigen wir nur, wie diese Tabelle mit ctypes gelesen werden kann.

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

Wir haben den Datentyp _frozen definiert, sodass wir den Zeiger auf die Tabelle erhalten können.

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

Da table ein pointer auf das Array von struct_frozen-Datensätzen ist, können wir es durchlaufen, aber wir müssen sicherstellen, dass unsere Schleife endet, da Zeiger keine Größe haben. Früher oder später würde es wahrscheinlich mit einer Zugriffsverletzung oder Ähnlichem abstürzen, daher ist es besser, die Schleife zu beenden, wenn wir auf den NULL-Eintrag stoßen.

>>> for item in table:
...     if item.name is None:
...         break
...     print(item.name.decode("ascii"), item.size)
...
_frozen_importlib 31764
_frozen_importlib_external 41499
zipimport 12345
>>>

Die Tatsache, dass das Standard-Python ein "eingefrorenes" Modul und ein "eingefrorenes" Paket hat (angezeigt durch das negative size-Mitglied), ist nicht gut bekannt; es wird nur zum Testen verwendet. Probieren Sie es mit import __hello__ aus, zum Beispiel.

Überraschungen

Es gibt einige Kanten in ctypes, bei denen Sie etwas anderes erwarten als das, was tatsächlich passiert.

Betrachten Sie das folgende Beispiel.

>>> 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. Wir hätten sicherlich erwartet, dass die letzte Anweisung 3 4 1 2 ausgibt. Was ist passiert? Hier sind die Schritte der Zeile rc.a, rc.b = rc.b, rc.a oben:

>>> temp0, temp1 = rc.b, rc.a
>>> rc.a = temp0
>>> rc.b = temp1
>>>

Beachten Sie, dass temp0 und temp1 Objekte sind, die immer noch den internen Puffer des obigen rc-Objekts verwenden. Das Ausführen von rc.a = temp0 kopiert den Pufferinhalt von temp0 in den Puffer von rc. Dies wiederum ändert den Inhalt von temp1. Die letzte Zuweisung rc.b = temp1 hat also nicht den erwarteten Effekt.

Denken Sie daran, dass das Abrufen von Unterobjekten aus Strukturen, Unions und Arrays das Unterobjekt nicht *kopiert*, sondern ein Wrapper-Objekt abruft, das auf den Puffer des Stammobjekts zugreift.

Ein weiteres Beispiel, das sich anders verhalten kann als erwartet, ist dieses:

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

Hinweis

Objekte, die von c_char_p instanziiert werden, können nur ihren Wert auf Bytes oder Ganzzahlen setzen.

Warum gibt es False aus? ctypes-Instanzen sind Objekte, die einen Speicherblock plus einige Deskriptoren enthalten, die auf den Inhalt des Speichers zugreifen. Das Speichern eines Python-Objekts im Speicherblock speichert nicht das Objekt selbst, stattdessen werden die contents des Objekts gespeichert. Der Abruf der Inhalte konstruiert jedes Mal ein neues Python-Objekt!

Datentypen variabler Größe

ctypes bietet einige Unterstützung für Arrays und Strukturen variabler Größe.

Die Funktion resize() kann verwendet werden, um den Speicherpuffer eines vorhandenen ctypes-Objekts zu ändern. Die Funktion nimmt das Objekt als erstes Argument und die gewünschte Größe in Bytes als zweites Argument entgegen. Der Speicherblock kann nicht kleiner als der natürliche Speicherblock gemacht werden, der durch den Typ des Objekts spezifiziert ist; wenn dies versucht wird, wird ein ValueError ausgelöst.

>>> 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
>>>

Das ist nett und in Ordnung, aber wie greift man auf die zusätzlichen Elemente zu, die in diesem Array enthalten sind? Da der Typ immer noch nur über 4 Elemente Bescheid weiß, erhalten wir Fehler beim Zugriff auf andere Elemente.

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

Eine andere Möglichkeit, Datentypen variabler Größe mit ctypes zu verwenden, ist die Nutzung der dynamischen Natur von Python und die (Neu-)Definition des Datentyps, nachdem die erforderliche Größe bereits bekannt ist, von Fall zu Fall.

ctypes Referenz

Finden von Shared Libraries

Beim Programmieren in einer kompilierten Sprache werden Shared Libraries beim Kompilieren/Linken eines Programms und beim Ausführen des Programms zugegriffen.

Der Zweck der Funktion find_library() ist es, eine Bibliothek ähnlich wie der Compiler oder der Laufzeit-Loader zu finden (auf Plattformen mit mehreren Versionen einer Shared Library sollte die neueste geladen werden), während die ctypes-Bibliothekslader wie beim Ausführen eines Programms agieren und den Laufzeit-Loader direkt aufrufen.

Das Modul ctypes.util bietet eine Funktion, die beim Bestimmen der zu ladenden Bibliothek helfen kann.

ctypes.util.find_library(name)

Versucht, eine Bibliothek zu finden und gibt einen Pfadnamen zurück. *name* ist der Bibliotheksname ohne Präfixe wie *lib*, Suffixe wie .so, .dylib oder Versionsnummern (dies ist die Form, die für die POSIX-Linkeroption -l verwendet wird). Wenn keine Bibliothek gefunden werden kann, wird None zurückgegeben.

Die genaue Funktionalität ist systemabhängig.

Unter Linux versucht find_library(), externe Programme auszuführen (/sbin/ldconfig, gcc, objdump und ld), um die Bibliotheksdatei zu finden. Es gibt den Dateinamen der Bibliotheksdatei zurück.

Geändert in Version 3.6: Unter Linux wird der Wert der Umgebungsvariable LD_LIBRARY_PATH beim Suchen nach Bibliotheken verwendet, wenn eine Bibliothek mit anderen Mitteln nicht gefunden werden kann.

Hier sind einige Beispiele

>>> 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'
>>>

Unter macOS und Android verwendet find_library() die Standardbenennungsschemata und Pfade des Systems, um die Bibliothek zu lokalisieren, und gibt bei Erfolg einen vollständigen Pfadnamen zurück.

>>> 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'
>>>

Unter Windows durchsucht find_library() den System-Suchpfad und gibt den vollständigen Pfadnamen zurück, aber da es kein vordefiniertes Benennungsschema gibt, schlägt ein Aufruf wie find_library("c") fehl und gibt None zurück.

Beim Einbinden einer Shared Library mit ctypes ist es *möglicherweise* besser, den Shared-Library-Namen zur Entwicklungszeit zu bestimmen und ihn in das Wrapper-Modul zu codieren, anstatt find_library() zur Laufzeit zu verwenden, um die Bibliothek zu lokalisieren.

Auflisten geladener Shared Libraries

Beim Schreiben von Code, der auf aus Shared Libraries geladenen Code angewiesen ist, kann es nützlich sein zu wissen, welche Shared Libraries bereits in den aktuellen Prozess geladen wurden.

Das Modul ctypes.util stellt die Funktion dllist() bereit, die die verschiedenen APIs aufruft, die von den verschiedenen Plattformen bereitgestellt werden, um zu bestimmen, welche Shared Libraries bereits in den aktuellen Prozess geladen wurden.

Die genaue Ausgabe dieser Funktion ist systemabhängig. Auf den meisten Plattformen repräsentiert der erste Eintrag dieser Liste den aktuellen Prozess selbst, was ein leerer String sein kann. Unter Linux, das auf glibc basiert, könnte die Rückgabe beispielsweise wie folgt aussehen:

>>> from ctypes.util import dllist
>>> dllist()
['', 'linux-vdso.so.1', '/lib/x86_64-linux-gnu/libm.so.6', '/lib/x86_64-linux-gnu/libc.so.6', ... ]

Laden von Shared Libraries

Es gibt mehrere Möglichkeiten, Shared Libraries in den Python-Prozess zu laden. Eine Möglichkeit ist die Instanziierung einer der folgenden Klassen:

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

Instanzen dieser Klasse repräsentieren geladene Shared Libraries. Funktionen in diesen Bibliotheken verwenden die Standard-C-Aufrufkonvention und geben angenommen int zurück.

Unter Windows kann die Erstellung einer CDLL-Instanz fehlschlagen, auch wenn der DLL-Name existiert. Wenn eine abhängige DLL der geladenen DLL nicht gefunden wird, wird ein OSError-Fehler mit der Meldung *„[WinError 126] Das angegebene Modul konnte nicht gefunden werden“* ausgelöst. Diese Fehlermeldung enthält nicht den Namen der fehlenden DLL, da die Windows-API diese Information nicht zurückgibt, was diesen Fehler schwer zu diagnostizieren macht. Um diesen Fehler zu beheben und festzustellen, welche DLL fehlt, müssen Sie die Liste der abhängigen DLLs ermitteln und mit Windows-Debugging- und Tracing-Tools feststellen, welche fehlt.

Geändert in Version 3.12: Der Parameter *name* kann jetzt ein pfadähnliches Objekt sein.

Siehe auch

Microsoft DUMPBIN tool – Ein Werkzeug zum Auffinden von DLL-Abhängigkeiten.

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

Instanzen dieser Klasse repräsentieren geladene Shared Libraries. Funktionen in diesen Bibliotheken verwenden die stdcall Aufrufkonvention und es wird angenommen, dass sie den windowspezifischen HRESULT-Code zurückgeben. HRESULT-Werte enthalten Informationen darüber, ob der Funktionsaufruf fehlgeschlagen ist oder erfolgreich war, zusammen mit zusätzlichen Fehlercodes. Wenn der Rückgabewert einen Fehler signalisiert, wird automatisch eine OSError ausgelöst.

Verfügbarkeit: Windows

Changed in version 3.3: WindowsError wurde früher ausgelöst, ist aber jetzt ein Alias für OSError.

Geändert in Version 3.12: Der Parameter *name* kann jetzt ein pfadähnliches Objekt sein.

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

Instanzen dieser Klasse repräsentieren geladene Shared Libraries. Funktionen in diesen Bibliotheken verwenden die stdcall Aufrufkonvention und es wird angenommen, dass sie standardmäßig int zurückgeben.

Verfügbarkeit: Windows

Geändert in Version 3.12: Der Parameter *name* kann jetzt ein pfadähnliches Objekt sein.

Der Python global interpreter lock wird vor dem Aufruf einer von diesen Bibliotheken exportierten Funktion freigegeben und danach wieder erworben.

class ctypes.PyDLL(name, mode=DEFAULT_MODE, handle=None)

Instanzen dieser Klasse verhalten sich wie CDLL-Instanzen, mit der Ausnahme, dass der Python GIL während des Funktionsaufrufs *nicht* freigegeben wird und nach der Ausführung der Funktion die Python-Fehlermarkierung geprüft wird. Wenn die Fehlermarkierung gesetzt ist, wird eine Python-Ausnahme ausgelöst.

Daher ist dies nur nützlich, um Python C API-Funktionen direkt aufzurufen.

Geändert in Version 3.12: Der Parameter *name* kann jetzt ein pfadähnliches Objekt sein.

Alle diese Klassen können instanziiert werden, indem sie mit mindestens einem Argument, dem Pfadnamen der Shared Library, aufgerufen werden. Wenn Sie bereits ein Handle zu einer bereits geladenen Shared Library haben, kann dieses als benannter Parameter handle übergeben werden, andernfalls wird die zugrunde liegende dlopen()- oder LoadLibrary()-Funktion der Plattform verwendet, um die Bibliothek in den Prozess zu laden und ein Handle dazu zu erhalten.

Der Parameter mode kann verwendet werden, um anzugeben, wie die Bibliothek geladen wird. Konsultieren Sie für Details das Handbuch dlopen(3). Unter Windows wird mode ignoriert. Auf POSIX-Systemen wird RTLD_NOW immer hinzugefügt und ist nicht konfigurierbar.

Der Parameter use_errno, wenn er auf true gesetzt ist, aktiviert einen ctypes-Mechanismus, der einen sicheren Zugriff auf die systemeigene errno-Fehlernummer ermöglicht. ctypes verwaltet eine Thread-lokale Kopie der systemeigenen errno-Variable; wenn Sie externe Funktionen aufrufen, die mit use_errno=True erstellt wurden, wird der errno-Wert vor dem Funktionsaufruf mit der privaten Kopie von ctypes vertauscht, dasselbe geschieht unmittelbar nach dem Funktionsaufruf.

Die Funktion ctypes.get_errno() gibt den Wert der privaten Kopie von ctypes zurück, und die Funktion ctypes.set_errno() ändert die private Kopie von ctypes auf einen neuen Wert und gibt den vorherigen Wert zurück.

Der Parameter use_last_error, wenn er auf true gesetzt ist, aktiviert denselben Mechanismus für den Windows-Fehlercode, der von den Windows-API-Funktionen GetLastError() und SetLastError() verwaltet wird; ctypes.get_last_error() und ctypes.set_last_error() werden verwendet, um die private Kopie des Windows-Fehlercodes von ctypes anzufordern und zu ändern.

Der Parameter winmode wird unter Windows verwendet, um anzugeben, wie die Bibliothek geladen wird (da mode ignoriert wird). Er nimmt jeden Wert an, der für den Flag-Parameter der Win32-API-Funktion LoadLibraryEx gültig ist. Wenn er weggelassen wird, wird standardmäßig die sicherste DLL-Lade-Option verwendet, die Probleme wie DLL-Hijacking vermeidet. Die Übergabe des vollständigen Pfads zur DLL ist der sicherste Weg, um sicherzustellen, dass die richtige Bibliothek und deren Abhängigkeiten geladen werden.

Changed in version 3.8: Der Parameter winmode wurde hinzugefügt.

ctypes.RTLD_GLOBAL

Flag, das als Parameter mode verwendet wird. Auf Plattformen, auf denen dieses Flag nicht verfügbar ist, wird es als Ganzzahl Null definiert.

ctypes.RTLD_LOCAL

Flag, das als Parameter mode verwendet wird. Auf Plattformen, auf denen dies nicht verfügbar ist, ist es dasselbe wie RTLD_GLOBAL.

ctypes.DEFAULT_MODE

Der Standardmodus, der zum Laden von Shared Libraries verwendet wird. Unter OSX 10.3 ist dies RTLD_GLOBAL, andernfalls ist es dasselbe wie RTLD_LOCAL.

Instanzen dieser Klassen haben keine öffentlichen Methoden. Von der Shared Library exportierte Funktionen können als Attribute oder per Index zugegriffen werden. Beachten Sie, dass der Zugriff auf die Funktion über ein Attribut das Ergebnis zwischenspeichert und daher wiederholter Zugriff jedes Mal dasselbe Objekt zurückgibt. Auf der anderen Seite gibt der Zugriff per Index jedes Mal ein neues Objekt zurück.

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

Die folgenden öffentlichen Attribute sind verfügbar, ihre Namen beginnen mit einem Unterstrich, um Namenskonflikte mit exportierten Funktionsnamen zu vermeiden.

PyDLL._handle

Das System-Handle, das zum Zugriff auf die Bibliothek verwendet wird.

PyDLL._name

Der Name der im Konstruktor übergebenen Bibliothek.

Shared Libraries können auch geladen werden, indem eine der vordefinierten Objekte verwendet wird, die Instanzen der Klasse LibraryLoader sind, entweder durch Aufruf der Methode LoadLibrary() oder durch Abrufen der Bibliothek als Attribut des Loader-Instanz.

class ctypes.LibraryLoader(dlltype)

Klasse zum Laden von Shared Libraries. dlltype sollte einer der Typen CDLL, PyDLL, WinDLL oder OleDLL sein.

__getattr__() hat ein spezielles Verhalten: Es ermöglicht das Laden einer Shared Library, indem auf sie als Attribut einer Library-Loader-Instanz zugegriffen wird. Das Ergebnis wird zwischengespeichert, sodass wiederholte Attributzugriffe jedes Mal dieselbe Bibliothek zurückgeben.

LoadLibrary(name)

Lädt eine Shared Library in den Prozess und gibt sie zurück. Diese Methode gibt immer eine neue Instanz der Bibliothek zurück.

Diese vorgefertigten Bibliothekslader sind verfügbar.

ctypes.cdll

Erstellt CDLL-Instanzen.

ctypes.windll

Erstellt WinDLL-Instanzen.

Verfügbarkeit: Windows

ctypes.oledll

Erstellt OleDLL-Instanzen.

Verfügbarkeit: Windows

ctypes.pydll

Erstellt PyDLL-Instanzen.

Für den direkten Zugriff auf die C Python API ist ein gebrauchsfertiges Python Shared Library-Objekt verfügbar.

ctypes.pythonapi

Eine Instanz von PyDLL, die Python C API-Funktionen als Attribute exponiert. Beachten Sie, dass von allen diesen Funktionen standardmäßig angenommen wird, dass sie C int zurückgeben, was natürlich nicht immer der Fall ist. Daher müssen Sie das korrekte Attribut restype zuweisen, um diese Funktionen zu verwenden.

Das Laden einer Bibliothek über eines dieser Objekte löst ein Auditing-Ereignis ctypes.dlopen mit dem String-Argument name aus, dem Namen, der zum Laden der Bibliothek verwendet wurde.

Der Zugriff auf eine Funktion in einer geladenen Bibliothek löst ein Auditing-Ereignis ctypes.dlsym mit den Argumenten library (das Bibliotheks-Objekt) und name (dem Namen des Symbols als String oder Integer) aus.

Wenn nur das Bibliotheks-Handle anstelle des Objekts verfügbar ist, löst der Zugriff auf eine Funktion ein Auditing-Ereignis ctypes.dlsym/handle mit den Argumenten handle (dem rohen Bibliotheks-Handle) und name aus.

Externe Funktionen

Wie im vorherigen Abschnitt erläutert, kann auf externe Funktionen als Attribute geladener Shared Libraries zugegriffen werden. Die auf diese Weise erstellten Funktions-Objekte akzeptieren standardmäßig eine beliebige Anzahl von Argumenten, akzeptieren beliebige ctypes-Dateninstanzen als Argumente und geben den vom Bibliothekslader spezifizierten Standard-Ergebnistyp zurück.

Sie sind Instanzen einer privaten lokalen Klasse _FuncPtr (nicht in ctypes exponiert), die von der privaten Klasse _CFuncPtr erbt.

>>> import ctypes
>>> lib = ctypes.CDLL(None)
>>> issubclass(lib._FuncPtr, ctypes._CFuncPtr)
True
>>> lib._FuncPtr is ctypes._CFuncPtr
False
class ctypes._CFuncPtr

Basisklasse für C-aufrufbare externe Funktionen.

Instanzen von externen Funktionen sind ebenfalls C-kompatible Datentypen; sie repräsentieren C-Funktionszeiger.

Dieses Verhalten kann durch Zuweisung zu speziellen Attributen des externen Funktions-Objekts angepasst werden.

restype

Weisen Sie einen ctypes-Typ zu, um den Ergebnistyp der externen Funktion anzugeben. Verwenden Sie None für void, eine Funktion, die nichts zurückgibt.

Es ist möglich, ein aufrufbares Python-Objekt zuzuweisen, das kein ctypes-Typ ist. In diesem Fall wird angenommen, dass die Funktion eine C int zurückgibt, und das aufrufbare Objekt wird mit dieser Ganzzahl aufgerufen, was eine weitere Verarbeitung oder Fehlerprüfung ermöglicht. Die Verwendung ist veraltet. Für flexiblere Nachbearbeitung oder Fehlerprüfung verwenden Sie einen ctypes-Datentyp als restype und weisen Sie ein aufrufbares Objekt dem Attribut errcheck zu.

argtypes

Weisen Sie ein Tupel von ctypes-Typen zu, um die Argumenttypen anzugeben, die die Funktion akzeptiert. Funktionen, die die stdcall Aufrufkonvention verwenden, können nur mit der gleichen Anzahl von Argumenten wie die Länge dieses Tupels aufgerufen werden; Funktionen, die die C-Aufrufkonvention verwenden, akzeptieren auch zusätzliche, nicht spezifizierte Argumente.

Wenn eine externe Funktion aufgerufen wird, wird jedes tatsächliche Argument an die Klassenmethode from_param() der Elemente im argtypes-Tupel übergeben. Diese Methode ermöglicht die Anpassung des tatsächlichen Arguments an ein Objekt, das die externe Funktion akzeptiert. Beispielsweise konvertiert ein c_char_p-Element im argtypes-Tupel einen als Argument übergebenen String gemäß den ctypes-Konvertierungsregeln in ein Bytes-Objekt.

Neu: Es ist jetzt möglich, Elemente in argtypes aufzunehmen, die keine ctypes-Typen sind. Jedes Element muss jedoch eine from_param()-Methode haben, die einen als Argument verwendbaren Wert (Ganzzahl, String, ctypes-Instanz) zurückgibt. Dies ermöglicht die Definition von Adaptern, die benutzerdefinierte Objekte als Funktionsparameter adaptieren können.

errcheck

Weisen Sie eine Python-Funktion oder ein anderes aufrufbares Objekt diesem Attribut zu. Das aufrufbare Objekt wird mit drei oder mehr Argumenten aufgerufen

callable(result, func, arguments)

result ist das, was die externe Funktion zurückgibt, wie durch das Attribut restype spezifiziert.

func ist das externe Funktions-Objekt selbst, dies ermöglicht die Wiederverwendung desselben aufrufbaren Objekts zur Prüfung oder Nachbearbeitung der Ergebnisse mehrerer Funktionen.

arguments ist ein Tupel, das die Parameter enthält, die ursprünglich an den Funktionsaufruf übergeben wurden. Dies ermöglicht die Spezialisierung des Verhaltens auf die verwendeten Argumente.

Das Objekt, das diese Funktion zurückgibt, wird vom externen Funktionsaufruf zurückgegeben, aber sie kann auch den Ergebniswert prüfen und eine Ausnahme auslösen, wenn der externe Funktionsaufruf fehlgeschlagen ist.

Unter Windows werden Systemausnahmen, die von einem externen Funktionsaufruf ausgelöst werden (z. B. aufgrund einer Zugriffsverletzung), abgefangen und durch eine geeignete Python-Ausnahme ersetzt. Des Weiteren wird ein Auditing-Ereignis ctypes.set_exception mit dem Argument code ausgelöst, was einem Audit-Hook ermöglicht, die Ausnahme durch seine eigene zu ersetzen.

Einige Möglichkeiten, externe Funktionsaufrufe aufzurufen, sowie einige der Funktionen in diesem Modul, können ein Auditing-Ereignis ctypes.call_function mit den Argumenten function pointer und arguments auslösen.

Funktionsprototypen

Externe Funktionen können auch durch Instanziierung von Funktionsprototypen erstellt werden. Funktionsprototypen ähneln Funktionsprototypen in C; sie beschreiben eine Funktion (Rückgabetyp, Argumenttypen, Aufrufkonvention), ohne eine Implementierung zu definieren. Die Factory-Funktionen müssen mit dem gewünschten Rückgabetyp und den Argumenttypen der Funktion aufgerufen werden und können als Dekorator-Fabriken verwendet werden, und als solche auf Funktionen über die @wrapper-Syntax angewendet werden. Beispiele finden Sie unter Callback-Funktionen.

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

Der zurückgegebene Funktionsprototyp erstellt Funktionen, die die Standard-C-Aufrufkonvention verwenden. Die Funktion gibt den GIL während des Aufrufs frei. Wenn use_errno auf true gesetzt ist, wird die private Kopie der Systemvariable errno von ctypes mit dem tatsächlichen Wert von errno vor und nach dem Aufruf vertauscht. use_last_error tut dasselbe für den Windows-Fehlercode.

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

Der zurückgegebene Funktionsprototyp erstellt Funktionen, die die stdcall Aufrufkonvention verwenden. Die Funktion gibt den GIL während des Aufrufs frei. use_errno und use_last_error haben die gleiche Bedeutung wie oben.

Verfügbarkeit: Windows

ctypes.PYFUNCTYPE(restype, *argtypes)

Der zurückgegebene Funktionsprototyp erstellt Funktionen, die die Python-Aufrufkonvention verwenden. Die Funktion gibt den GIL während des Aufrufs *nicht* frei.

Funktionsprototypen, die von diesen Factory-Funktionen erstellt wurden, können auf verschiedene Weise instanziiert werden, abhängig vom Typ und der Anzahl der Parameter im Aufruf.

prototype(address)

Gibt eine externe Funktion an der angegebenen Adresse zurück, die eine Ganzzahl sein muss.

prototype(callable)

Erstellt eine C-aufrufbare Funktion (eine Callback-Funktion) aus einem Python-callable.

prototype(func_spec[, paramflags])

Gibt eine externe Funktion zurück, die von einer Shared Library exportiert wird. func_spec muss ein 2-Tupel sein (name_or_ordinal, library). Das erste Element ist der Name der exportierten Funktion als String oder die Ordinalzahl der exportierten Funktion als kleine Ganzzahl. Das zweite Element ist die Shared Library-Instanz.

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

Gibt eine externe Funktion zurück, die eine COM-Methode aufruft. vtbl_index ist der Index in der virtuellen Funktionstabelle, eine kleine nicht-negative Ganzzahl. name ist der Name der COM-Methode. iid ist ein optionaler Zeiger auf die Schnittstellenkennung, die in der erweiterten Fehlerberichterstattung verwendet wird.

Wenn iid nicht angegeben ist, wird eine OSError ausgelöst, wenn der COM-Methodenaufruf fehlschlägt. Wenn iid angegeben ist, wird stattdessen eine COMError ausgelöst.

COM-Methoden verwenden eine spezielle Aufrufkonvention: Sie erfordern zusätzlich zu den im Tupel argtypes spezifizierten Parametern einen Zeiger auf die COM-Schnittstelle als erstes Argument.

Verfügbarkeit: Windows

Der optionale Parameter paramflags erstellt externe Funktions-Wrapper mit viel mehr Funktionalität als die oben beschriebenen Features.

paramflags muss ein Tupel gleicher Länge wie argtypes sein.

Jeder Eintrag in diesem Tupel enthält weitere Informationen zu einem Parameter und muss ein Tupel aus einem, zwei oder drei Elementen sein.

Das erste Element ist eine Ganzzahl, die eine Kombination von Richtungsflags für den Parameter enthält.

1

Spezifiziert einen Eingabeparameter für die Funktion.

2

Ausgabeparameter. Die externe Funktion füllt einen Wert ein.

4

Eingabeparameter, der standardmäßig auf die Ganzzahl Null gesetzt ist.

Das optionale zweite Element ist der Parametername als String. Wenn dies angegeben ist, kann die externe Funktion mit benannten Parametern aufgerufen werden.

Das optionale dritte Element ist der Standardwert für diesen Parameter.

Das folgende Beispiel zeigt, wie die Windows-Funktion MessageBoxW so gekapselt wird, dass sie Standardparameter und benannte Argumente unterstützt. Die C-Deklaration aus der Windows-Header-Datei lautet:

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

Hier ist die Kapselung mit 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)

Die externe Funktion MessageBox kann jetzt auf folgende Weise aufgerufen werden.

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

Ein zweites Beispiel demonstriert Ausgabeparameter. Die Win32-Funktion GetWindowRect ruft die Abmessungen eines angegebenen Fensters ab, indem sie diese in eine RECT-Struktur kopiert, die vom Aufrufer bereitgestellt werden muss. Hier ist die C-Deklaration.

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

Hier ist die Kapselung mit 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)
>>>

Funktionen mit Ausgabeparametern geben automatisch den Wert des Ausgabeparameters zurück, wenn es einen einzelnen gibt, oder ein Tupel, das die Werte der Ausgabeparameter enthält, wenn es mehrere gibt. Daher gibt die Funktion GetWindowRect nun eine RECT-Instanz zurück, wenn sie aufgerufen wird.

Ausgabeparameter können mit dem errcheck-Protokoll kombiniert werden, um weitere Ausgabeverarbeitung und Fehlerprüfung durchzuführen. Die Win32-API-Funktion GetWindowRect gibt ein BOOL zurück, um Erfolg oder Misserfolg zu signalisieren. Diese Funktion könnte also die Fehlerprüfung durchführen und eine Ausnahme auslösen, wenn der API-Aufruf fehlschlägt.

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

Wenn die errcheck-Funktion das empfangene Argument-Tupel unverändert zurückgibt, setzt ctypes die normale Verarbeitung der Ausgabeparameter fort. Wenn Sie ein Tupel von Fensterkoordinaten anstelle einer RECT-Instanz zurückgeben möchten, können Sie die Felder in der Funktion abrufen und stattdessen zurückgeben; die normale Verarbeitung findet dann nicht mehr statt.

>>> 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
>>>

Hilfsfunktionen

ctypes.addressof(obj)

Gibt die Adresse des Speicherpuffers als Ganzzahl zurück. obj muss eine Instanz eines ctypes-Typs sein.

Löst ein Auditing-Ereignis ctypes.addressof mit dem Argument obj aus.

ctypes.alignment(obj_or_type)

Gibt die Ausrichtungsvoraussetzungen eines ctypes-Typs zurück. obj_or_type muss ein ctypes-Typ oder eine Instanz sein.

ctypes.byref(obj[, offset])

Gibt einen leichtgewichtigen Zeiger auf obj zurück, der eine Instanz eines ctypes-Typs sein muss. offset ist standardmäßig Null und muss eine Ganzzahl sein, die zum internen Zeigerwert addiert wird.

byref(obj, offset) entspricht diesem C-Code.

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

Das zurückgegebene Objekt kann nur als Parameter für einen Fremdfunktionsaufruf verwendet werden. Es verhält sich ähnlich wie pointer(obj), aber die Konstruktion ist wesentlich schneller.

ctypes.CopyComPointer(src, dst)

Kopiert einen COM-Zeiger von src nach dst und gibt den Windows-spezifischen HRESULT-Wert zurück.

Wenn src nicht NULL ist, wird seine AddRef-Methode aufgerufen, wodurch der Referenzzähler erhöht wird.

Im Gegensatz dazu wird der Referenzzähler von dst vor der Zuweisung des neuen Wertes nicht dekrementiert. Sofern dst nicht NULL ist, ist der Aufrufer dafür verantwortlich, den Referenzzähler durch Aufrufen seiner Release-Methode zu dekrementieren, wenn dies erforderlich ist.

Verfügbarkeit: Windows

Hinzugefügt in Version 3.14.

ctypes.cast(obj, type)

Diese Funktion ähnelt dem Cast-Operator in C. Sie gibt eine neue Instanz von type zurück, die auf denselben Speicherblock wie obj zeigt. type muss ein Zeigertyp sein und obj muss ein Objekt sein, das als Zeiger interpretiert werden kann.

ctypes.create_string_buffer(init, size=None)
ctypes.create_string_buffer(size)

Diese Funktion erstellt einen modifizierbaren Zeichenpuffer. Das zurückgegebene Objekt ist ein ctypes-Array von c_char.

Wenn size angegeben ist (und nicht None), muss es eine int sein. Es gibt die Größe des zurückgegebenen Arrays an.

Wenn das Argument init angegeben ist, muss es bytes sein. Es wird verwendet, um die Array-Elemente zu initialisieren. Bytes, die auf diese Weise nicht initialisiert wurden, werden auf Null (NUL) gesetzt.

Wenn size nicht angegeben ist (oder wenn es None ist), wird der Puffer um ein Element größer als init gemacht, wodurch effektiv ein NUL-Terminator hinzugefügt wird.

Wenn beide Argumente angegeben sind, darf size nicht kleiner als len(init) sein.

Warnung

Wenn size gleich len(init) ist, wird kein NUL-Terminator hinzugefügt. Behandeln Sie einen solchen Puffer nicht als C-String.

Zum Beispiel

>>> bytes(create_string_buffer(2))
b'\x00\x00'
>>> bytes(create_string_buffer(b'ab'))
b'ab\x00'
>>> bytes(create_string_buffer(b'ab', 2))
b'ab'
>>> bytes(create_string_buffer(b'ab', 4))
b'ab\x00\x00'
>>> bytes(create_string_buffer(b'abcdef', 2))
Traceback (most recent call last):
   ...
ValueError: byte string too long

Löst ein Auditing-Ereignis ctypes.create_string_buffer mit den Argumenten init, size aus.

ctypes.create_unicode_buffer(init, size=None)
ctypes.create_unicode_buffer(size)

Diese Funktion erstellt einen modifizierbaren Unicode-Zeichenpuffer. Das zurückgegebene Objekt ist ein ctypes-Array von c_wchar.

Die Funktion nimmt dieselben Argumente wie create_string_buffer(), außer dass init ein String sein muss und size die Anzahl der c_wchar zählt.

Löst ein Auditing-Ereignis ctypes.create_unicode_buffer mit den Argumenten init, size aus.

ctypes.DllCanUnloadNow()

Diese Funktion ist ein Hook, der die Implementierung von In-Process-COM-Servern mit ctypes ermöglicht. Sie wird von der DllCanUnloadNow-Funktion aufgerufen, die die _ctypes-Erweiterungs-DLL exportiert.

Verfügbarkeit: Windows

ctypes.DllGetClassObject()

Diese Funktion ist ein Hook, der die Implementierung von In-Process-COM-Servern mit ctypes ermöglicht. Sie wird von der DllGetClassObject-Funktion aufgerufen, die die _ctypes-Erweiterungs-DLL exportiert.

Verfügbarkeit: Windows

ctypes.util.find_library(name)

Versucht, eine Bibliothek zu finden und gibt einen Pfadnamen zurück. name ist der Bibliotheksname ohne Präfix wie lib, Suffix wie .so, .dylib oder Versionsnummer (dies ist die Form, die für die POSIX-Linker-Option -l verwendet wird). Wenn keine Bibliothek gefunden werden kann, wird None zurückgegeben.

Die genaue Funktionalität ist systemabhängig.

ctypes.util.find_msvcrt()

Gibt den Dateinamen der VC-Laufzeitbibliothek zurück, die von Python und den Erweiterungsmodulen verwendet wird. Wenn der Name der Bibliothek nicht ermittelt werden kann, wird None zurückgegeben.

Wenn Sie Speicher freigeben müssen, der beispielsweise von einem Erweiterungsmodul mit einem Aufruf von free(void *) zugewiesen wurde, ist es wichtig, dass Sie die Funktion in derselben Bibliothek verwenden, die den Speicher zugewiesen hat.

Verfügbarkeit: Windows

ctypes.util.dllist()

Versucht, eine Liste von Pfaden der im aktuellen Prozess geladenen Shared Libraries bereitzustellen. Diese Pfade werden nicht normalisiert oder anderweitig verarbeitet. Die Funktion kann OSError auslösen, wenn die zugrunde liegenden Plattform-APIs fehlschlagen. Die genaue Funktionalität ist systemabhängig.

Auf den meisten Plattformen repräsentiert das erste Element der Liste die aktuelle ausführbare Datei. Es kann ein leerer String sein.

Verfügbarkeit: Windows, macOS, iOS, glibc, BSD libc, musl

Hinzugefügt in Version 3.14.

ctypes.FormatError([code])

Gibt eine textuelle Beschreibung des Fehlercodes code zurück. Wenn kein Fehlercode angegeben ist, wird der letzte Fehlercode durch Aufrufen der Windows-API-Funktion GetLastError() verwendet.

Verfügbarkeit: Windows

ctypes.GetLastError()

Gibt den letzten Fehlercode zurück, der von Windows im aufrufenden Thread gesetzt wurde. Diese Funktion ruft die Windows-Funktion GetLastError() direkt auf, sie gibt nicht die private Kopie des Fehlercodes von ctypes zurück.

Verfügbarkeit: Windows

ctypes.get_errno()

Gibt den aktuellen Wert der privaten Kopie der Systemvariable errno von ctypes im aufrufenden Thread zurück.

Löst ein Auditing-Ereignis ctypes.get_errno mit keinen Argumenten aus.

ctypes.get_last_error()

Gibt den aktuellen Wert der privaten Kopie der Systemvariable LastError von ctypes im aufrufenden Thread zurück.

Verfügbarkeit: Windows

Löst ein Auditing-Ereignis ctypes.get_last_error mit keinen Argumenten aus.

ctypes.memmove(dst, src, count)

Entspricht der Standard-C-Bibliotheksfunktion memmove: kopiert count Bytes von src nach dst. dst und src müssen ganze Zahlen oder ctypes-Instanzen sein, die in Zeiger konvertiert werden können.

ctypes.memset(dst, c, count)

Entspricht der Standard-C-Bibliotheksfunktion memset: füllt den Speicherblock an der Adresse dst mit count Bytes des Werts c. dst muss eine ganze Zahl sein, die eine Adresse angibt, oder eine ctypes-Instanz.

ctypes.POINTER(type, /)

Erstellt oder gibt einen ctypes-Zeigertyp zurück. Zeigertypen werden zwischengespeichert und intern wiederverwendet, daher ist der wiederholte Aufruf dieser Funktion kostengünstig. type muss ein ctypes-Typ sein.

CPython-Implementierungsdetail: Der resultierende Zeigertyp wird im Attribut __pointer_type__ von type zwischengespeichert. Es ist möglich, dieses Attribut vor dem ersten Aufruf von POINTER festzulegen, um einen benutzerdefinierten Zeigertyp festzulegen. Dies wird jedoch nicht empfohlen: Manuelles Erstellen eines geeigneten Zeigertyps ist ohne Rückgriff auf Implementierungsdetails, die sich in zukünftigen Python-Versionen ändern können, schwierig.

ctypes.pointer(obj, /)

Erstellt eine neue Zeigerinstanz, die auf obj zeigt. Das zurückgegebene Objekt hat den Typ POINTER(type(obj)).

Hinweis: Wenn Sie lediglich einen Zeiger auf ein Objekt an einen Fremdfunktionsaufruf übergeben möchten, sollten Sie byref(obj) verwenden, was wesentlich schneller ist.

ctypes.resize(obj, size)

Diese Funktion ändert die Größe des internen Speicherpuffers von obj, das eine Instanz eines ctypes-Typs sein muss. Es ist nicht möglich, den Puffer kleiner zu machen als die native Größe des Typs des Objekts, wie durch sizeof(type(obj)) gegeben, aber es ist möglich, den Puffer zu vergrößern.

ctypes.set_errno(value)

Setzt den aktuellen Wert der privaten Kopie der Systemvariable errno von ctypes im aufrufenden Thread auf value und gibt den vorherigen Wert zurück.

Löst ein Auditing-Ereignis ctypes.set_errno mit dem Argument errno aus.

ctypes.set_last_error(value)

Setzt den aktuellen Wert der privaten Kopie der Systemvariable LastError von ctypes im aufrufenden Thread auf value und gibt den vorherigen Wert zurück.

Verfügbarkeit: Windows

Löst ein Auditing-Ereignis ctypes.set_last_error mit dem Argument error aus.

ctypes.sizeof(obj_or_type)

Gibt die Größe in Bytes eines ctypes-Typs oder einer Instanz eines Speicherpuffers zurück. Funktioniert wie der C-sizeof-Operator.

ctypes.string_at(ptr, size=-1)

Gibt den Byte-String an void *ptr zurück. Wenn size angegeben ist, wird es als Größe verwendet, andernfalls wird angenommen, dass der String nullterminiert ist.

Löst ein Auditing-Ereignis ctypes.string_at mit den Argumenten ptr, size aus.

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

Erstellt eine Instanz von OSError. Wenn code nicht angegeben ist, wird GetLastError() aufgerufen, um den Fehlercode zu ermitteln. Wenn descr nicht angegeben ist, wird FormatError() aufgerufen, um eine textuelle Beschreibung des Fehlers zu erhalten.

Verfügbarkeit: Windows

Geändert in Version 3.3: Es wurde früher eine Instanz von WindowsError erstellt, die jetzt ein Alias für OSError ist.

ctypes.wstring_at(ptr, size=-1)

Gibt den Wide-Character-String an void *ptr zurück. Wenn size angegeben ist, wird es als Anzahl der Zeichen des Strings verwendet, andernfalls wird angenommen, dass der String nullterminiert ist.

Löst ein Auditing-Ereignis ctypes.wstring_at mit den Argumenten ptr, size aus.

ctypes.memoryview_at(ptr, size, readonly=False)

Gibt ein memoryview-Objekt der Länge size zurück, das auf Speicher verweist, der bei void *ptr beginnt.

Wenn readonly wahr ist, kann das zurückgegebene memoryview-Objekt nicht verwendet werden, um den zugrunde liegenden Speicher zu ändern. (Änderungen, die auf andere Weise vorgenommen wurden, werden weiterhin im zurückgegebenen Objekt reflektiert.)

Diese Funktion ähnelt string_at() mit dem wesentlichen Unterschied, dass der angegebene Speicher nicht kopiert wird. Sie ist eine semantisch äquivalente (aber effizientere) Alternative zu memoryview((c_byte * size).from_address(ptr)). (Während from_address() nur ganze Zahlen akzeptiert, kann ptr auch als ctypes.POINTER oder als byref()-Objekt übergeben werden.)

Löst ein Auditing-Ereignis ctypes.memoryview_at mit den Argumenten address, size, readonly aus.

Hinzugefügt in Version 3.14.

Datentypen

class ctypes._CData

Diese nicht-öffentliche Klasse ist die gemeinsame Basisklasse aller ctypes-Datentypen. Unter anderem enthalten alle Instanzen von ctypes-Typen einen Speicherblock, der C-kompatible Daten enthält. Die Adresse des Speicherblocks wird von der Hilfsfunktion addressof() zurückgegeben. Eine weitere Instanzvariable wird als _objects exponiert; diese enthält andere Python-Objekte, die am Leben erhalten werden müssen, falls der Speicherblock Zeiger enthält.

Gängige Methoden von ctypes-Datentypen, dies sind alles Klassenmethoden (genauer gesagt sind es Methoden der Metaklasse)

from_buffer(source[, offset])

Diese Methode gibt eine ctypes-Instanz zurück, die den Puffer des source-Objekts teilt. Das source-Objekt muss die schreibbare Puffer-Schnittstelle unterstützen. Der optionale Parameter offset gibt einen Offset im Quellpuffer in Bytes an; der Standardwert ist null. Wenn der Quellpuffer nicht groß genug ist, wird ein ValueError ausgelöst.

Löst ein Auditing-Ereignis ctypes.cdata/buffer mit den Argumenten pointer, size, offset aus.

from_buffer_copy(source[, offset])

Diese Methode erstellt eine ctypes-Instanz, indem der Puffer aus dem source-Objekt kopiert wird, der lesbar sein muss. Der optionale Parameter offset gibt einen Offset im Quellpuffer in Bytes an; der Standardwert ist null. Wenn der Quellpuffer nicht groß genug ist, wird ein ValueError ausgelöst.

Löst ein Auditing-Ereignis ctypes.cdata/buffer mit den Argumenten pointer, size, offset aus.

from_address(address)

Diese Methode gibt eine ctypes-Typinstanz zurück, die den von address angegebenen Speicher verwendet, der eine ganze Zahl sein muss.

Diese Methode und andere, die diese Methode indirekt aufrufen, lösen ein Auditing-Ereignis ctypes.cdata mit dem Argument address aus.

from_param(obj)

Diese Methode passt obj an einen ctypes-Typ an. Sie wird mit dem tatsächlichen Objekt aufgerufen, das in einem Fremdfunktionsaufruf verwendet wird, wenn der Typ im Tupel argtypes der Fremdfunktion vorhanden ist; sie muss ein Objekt zurückgeben, das als Funktionsaufrufparameter verwendet werden kann.

Alle ctypes-Datentypen haben eine Standardimplementierung dieser Klassenmethode, die normalerweise obj zurückgibt, wenn es sich um eine Instanz des Typs handelt. Einige Typen akzeptieren auch andere Objekte.

in_dll(library, name)

Diese Methode gibt eine ctypes-Typinstanz zurück, die von einer Shared Library exportiert wird. name ist der Name des Symbols, das die Daten exportiert, library ist die geladene Shared Library.

Gängige Klassenvariablen von ctypes-Datentypen

__pointer_type__

Der Zeigertyp, der durch Aufrufen von POINTER() für den entsprechenden ctypes-Datentyp erstellt wurde. Wenn noch kein Zeigertyp erstellt wurde, fehlt das Attribut.

Hinzugefügt in Version 3.14.

Gängige Instanzvariablen von ctypes-Datentypen

_b_base_

Manchmal besitzen ctypes-Dateninstanzen den von ihnen enthaltenen Speicherblock nicht, sondern teilen sich einen Teil des Speicherblocks eines Basisobjekts. Das schreibgeschützte Mitglied _b_base_ ist das Wurzel-ctypes-Objekt, das den Speicherblock besitzt.

_b_needsfree_

Diese schreibgeschützte Variable ist wahr, wenn die ctypes-Dateninstanz den Speicherblock selbst zugewiesen hat, andernfalls falsch.

_objects

Dieses Mitglied ist entweder None oder ein Wörterbuch, das Python-Objekte enthält, die am Leben erhalten werden müssen, damit der Inhalt des Speicherblocks gültig bleibt. Dieses Objekt wird nur zur Fehlersuche bereitgestellt; ändern Sie niemals den Inhalt dieses Wörterbuchs.

Grundlegende Datentypen

class ctypes._SimpleCData

Diese nicht-öffentliche Klasse ist die Basisklasse aller grundlegenden ctypes-Datentypen. Sie wird hier erwähnt, weil sie die gemeinsamen Attribute der grundlegenden ctypes-Datentypen enthält. _SimpleCData ist eine Unterklasse von _CData und erbt daher deren Methoden und Attribute. ctypes-Datentypen, die keine Zeiger sind und keine Zeiger enthalten, können nun serialisiert werden.

Instanzen haben ein einziges Attribut

value

Dieses Attribut enthält den tatsächlichen Wert der Instanz. Für Ganzzahl- und Zeigertypen ist es eine Ganzzahl, für Zeichentypen ist es ein einzelnes Zeichen als Bytes-Objekt oder String, für Zeichenzeigertypen ist es ein Python-Bytes-Objekt oder ein String.

Wenn das Attribut value von einer ctypes-Instanz abgerufen wird, wird normalerweise jedes Mal ein neues Objekt zurückgegeben. ctypes implementiert **keine** Rückgabe des Originalobjekts, es wird immer ein neues Objekt konstruiert. Dasselbe gilt für alle anderen ctypes-Objektinstanzen.

Grundlegende Datentypen, wenn sie als Ergebnisse eines Fremdfunktionsaufrufs zurückgegeben werden oder z. B. durch Abrufen von Strukturfeldmitgliedern oder Array-Elementen, werden transparent in native Python-Typen konvertiert. Anders ausgedrückt: Wenn eine Fremdfunktion einen restype von c_char_p hat, erhalten Sie immer ein Python-Bytes-Objekt, **nicht** eine Instanz von c_char_p.

Unterklassen von grundlegenden Datentypen erben dieses Verhalten **nicht**. Wenn also der restype einer Fremdfunktion eine Unterklasse von c_void_p ist, erhalten Sie von dem Funktionsaufruf eine Instanz dieser Unterklasse. Natürlich können Sie den Wert des Zeigers abrufen, indem Sie auf das Attribut value zugreifen.

Dies sind die grundlegenden ctypes-Datentypen

class ctypes.c_byte

Stellt den C-Datentyp signed char dar und interpretiert den Wert als kleine Ganzzahl. Der Konstruktor akzeptiert einen optionalen Ganzzahl-Initialisierer; es wird keine Überlaufprüfung durchgeführt.

class ctypes.c_char

Stellt den C-Datentyp char dar und interpretiert den Wert als einzelnes Zeichen. Der Konstruktor akzeptiert einen optionalen String-Initialisierer; die Länge des Strings muss genau ein Zeichen betragen.

class ctypes.c_char_p

Stellt den C-Datentyp char* dar, wenn er auf einen nullterminierten String zeigt. Für einen allgemeinen Zeichenzeiger, der auch auf binäre Daten zeigen kann, muss POINTER(c_char) verwendet werden. Der Konstruktor akzeptiert eine Ganzzahladresse oder ein Bytes-Objekt.

class ctypes.c_double

Stellt den C-Datentyp double dar. Der Konstruktor akzeptiert einen optionalen Float-Initialisierer.

class ctypes.c_longdouble

Stellt den C-Datentyp long double dar. Der Konstruktor akzeptiert einen optionalen Float-Initialisierer. Auf Plattformen, auf denen sizeof(long double) == sizeof(double) ist, ist er ein Alias für c_double.

class ctypes.c_float

Stellt den C-Datentyp float dar. Der Konstruktor akzeptiert einen optionalen Float-Initialisierer.

class ctypes.c_double_complex

Stellt den C-Datentyp double complex dar, falls verfügbar. Der Konstruktor akzeptiert einen optionalen complex-Initialisierer.

Hinzugefügt in Version 3.14.

class ctypes.c_float_complex

Stellt den C-Datentyp float complex dar, falls verfügbar. Der Konstruktor akzeptiert einen optionalen complex-Initialisierer.

Hinzugefügt in Version 3.14.

class ctypes.c_longdouble_complex

Stellt den C-Datentyp long double complex dar, falls verfügbar. Der Konstruktor akzeptiert einen optionalen complex-Initialisierer.

Hinzugefügt in Version 3.14.

class ctypes.c_int

Stellt den C-Datentyp signed int dar. Der Konstruktor akzeptiert einen optionalen Ganzzahl-Initialisierer; es wird keine Überlaufprüfung durchgeführt. Auf Plattformen, auf denen sizeof(int) == sizeof(long) ist, ist er ein Alias für c_long.

class ctypes.c_int8

Stellt den C 8-Bit-Datentyp signed int dar. Er ist ein Alias für c_byte.

class ctypes.c_int16

Stellt den C 16-Bit-Datentyp signed int dar. Normalerweise ein Alias für c_short.

class ctypes.c_int32

Stellt den C 32-Bit-Datentyp signed int dar. Normalerweise ein Alias für c_int.

class ctypes.c_int64

Stellt den C 64-Bit-Datentyp signed int dar. Normalerweise ein Alias für c_longlong.

class ctypes.c_long

Stellt den C-Datentyp signed long dar. Der Konstruktor akzeptiert einen optionalen Ganzzahl-Initialisierer; es wird keine Überlaufprüfung durchgeführt.

class ctypes.c_longlong

Stellt den C-Datentyp signed long long dar. Der Konstruktor akzeptiert einen optionalen Ganzzahl-Initialisierer; es wird keine Überlaufprüfung durchgeführt.

class ctypes.c_short

Stellt den C-Datentyp signed short dar. Der Konstruktor akzeptiert einen optionalen Ganzzahl-Initialisierer; es wird keine Überlaufprüfung durchgeführt.

class ctypes.c_size_t

Stellt den C-Datentyp size_t dar.

class ctypes.c_ssize_t

Stellt den C-Datentyp ssize_t dar.

Hinzugefügt in Version 3.2.

class ctypes.c_time_t

Stellt den C-Datentyp time_t dar.

Hinzugefügt in Version 3.12.

class ctypes.c_ubyte

Stellt den C-Datentyp unsigned char dar und interpretiert den Wert als kleine Ganzzahl. Der Konstruktor akzeptiert einen optionalen Ganzzahl-Initialisierer; es wird keine Überlaufprüfung durchgeführt.

class ctypes.c_uint

Stellt den C-Datentyp unsigned int dar. Der Konstruktor akzeptiert einen optionalen Ganzzahl-Initialisierer; es wird keine Überlaufprüfung durchgeführt. Auf Plattformen, auf denen sizeof(int) == sizeof(long) ist, ist er ein Alias für c_ulong.

class ctypes.c_uint8

Stellt den C 8-Bit-Datentyp unsigned int dar. Er ist ein Alias für c_ubyte.

class ctypes.c_uint16

Stellt den C 16-Bit-Datentyp unsigned int dar. Normalerweise ein Alias für c_ushort.

class ctypes.c_uint32

Stellt den C 32-Bit-Datentyp unsigned int dar. Normalerweise ein Alias für c_uint.

class ctypes.c_uint64

Stellt den C 64-Bit-Datentyp unsigned int dar. Normalerweise ein Alias für c_ulonglong.

class ctypes.c_ulong

Stellt den C-Datentyp unsigned long dar. Der Konstruktor akzeptiert einen optionalen Ganzzahl-Initialisierer; es wird keine Überlaufprüfung durchgeführt.

class ctypes.c_ulonglong

Stellt den C-Datentyp unsigned long long dar. Der Konstruktor akzeptiert einen optionalen Ganzzahl-Initialisierer; es wird keine Überlaufprüfung durchgeführt.

class ctypes.c_ushort

Stellt den C-Datentyp unsigned short dar. Der Konstruktor akzeptiert einen optionalen Ganzzahl-Initialisierer; es wird keine Überlaufprüfung durchgeführt.

class ctypes.c_void_p

Stellt den C-Typ void* dar. Der Wert wird als Ganzzahl repräsentiert. Der Konstruktor akzeptiert einen optionalen Ganzzahl-Initialisierer.

class ctypes.c_wchar

Stellt den C-Datentyp wchar_t dar und interpretiert den Wert als Unicode-String mit einem einzelnen Zeichen. Der Konstruktor akzeptiert einen optionalen String-Initialisierer; die Länge des Strings muss genau ein Zeichen betragen.

class ctypes.c_wchar_p

Stellt den C-Datentyp wchar_t* dar, der ein Zeiger auf einen nullterminierten Wide-Character-String sein muss. Der Konstruktor akzeptiert eine Ganzzahladresse oder einen String.

class ctypes.c_bool

Stellt den C-Datentyp bool dar (genauer gesagt _Bool aus C99). Sein Wert kann True oder False sein, und der Konstruktor akzeptiert jedes Objekt, das einen Wahrheitswert hat.

class ctypes.HRESULT

Stellt einen HRESULT-Wert dar, der Erfolgs- oder Fehlerinformationen für einen Funktions- oder Methodenaufruf enthält.

Verfügbarkeit: Windows

class ctypes.py_object

Stellt den C-Datentyp PyObject* dar. Das Aufrufen ohne Argument erstellt einen NULL PyObject*-Zeiger.

Geändert in Version 3.14: py_object ist jetzt ein generischer Typ.

Das Modul ctypes.wintypes bietet einige weitere Windows-spezifische Datentypen, z. B. HWND, WPARAM oder DWORD. Einige nützliche Strukturen wie MSG oder RECT sind ebenfalls definiert.

Strukturierte Datentypen

class ctypes.Union(*args, **kw)

Abstrakte Basisklasse für Unions in nativer Byte-Reihenfolge.

Unions teilen gemeinsame Attribute und Verhalten mit Strukturen; siehe Dokumentation von Structure für Details.

class ctypes.BigEndianUnion(*args, **kw)

Abstrakte Basisklasse für Unions in *Big-Endian*-Byte-Reihenfolge.

Hinzugefügt in Version 3.11.

class ctypes.LittleEndianUnion(*args, **kw)

Abstrakte Basisklasse für Unions in *Little-Endian*-Byte-Reihenfolge.

Hinzugefügt in Version 3.11.

class ctypes.BigEndianStructure(*args, **kw)

Abstrakte Basisklasse für Strukturen in *Big-Endian*-Byte-Reihenfolge.

class ctypes.LittleEndianStructure(*args, **kw)

Abstrakte Basisklasse für Strukturen in *Little-Endian*-Byte-Reihenfolge.

Strukturen und Unions mit nicht-nativer Byte-Reihenfolge können keine Zeigertyp-Felder oder andere Datentypen enthalten, die Zeigertyp-Felder enthalten.

class ctypes.Structure(*args, **kw)

Abstrakte Basisklasse für Strukturen in *nativer* Byte-Reihenfolge.

Konkrete Struktur- und Union-Typen müssen durch Unterklassenbildung einer dieser Typen erstellt werden, und es muss mindestens eine Klassenvariable _fields_ definiert werden. ctypes erstellt Deskriptoren, die das Lesen und Schreiben der Felder durch direkten Attributzugriff ermöglichen. Dies sind die

_fields_

Eine Sequenz, die die Felder der Struktur definiert. Die Elemente müssen 2-Tupel oder 3-Tupel sein. Das erste Element ist der Name des Feldes, das zweite Element gibt den Typ des Feldes an; es kann jeder ctypes-Datentyp sein.

Für Ganzzahltyp-Felder wie c_int kann ein drittes optionales Element angegeben werden. Es muss eine kleine positive Ganzzahl sein, die die Bitbreite des Feldes definiert.

Feldnamen müssen innerhalb einer Struktur oder Union eindeutig sein. Dies wird nicht überprüft; bei wiederholten Namen kann nur ein Feld zugegriffen werden.

Es ist möglich, die Klassenvariable _fields_ *nach* der Klassendefinition der Struktur-Unterklasse zu definieren. Dies ermöglicht die Erstellung von Datentypen, die sich direkt oder indirekt auf sich selbst beziehen.

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

Die Klassenvariable _fields_ kann nur einmal zugewiesen werden. Spätere Zuweisungen führen zu einem AttributeError.

Zusätzlich muss die Klassenvariable _fields_ vor der ersten Verwendung des Struktur- oder Union-Typs definiert werden: eine Instanz oder Unterklasse wird erstellt, sizeof() darauf aufgerufen wird, usw. Spätere Zuweisungen zu _fields_ lösen einen AttributeError aus. Wenn _fields_ vor einer solchen Verwendung nicht gesetzt wurde, hat die Struktur oder Union keine eigenen Felder, als ob _fields_ leer wäre.

Unter-Unterklassen von Strukturtypen erben die Felder der Basisklasse zuzüglich der in der Unter-Unterklasse definierten _fields_, falls vorhanden.

_pack_

Eine optionale kleine Ganzzahl, die die Ausrichtung von Strukturfeldern in der Instanz überschreiben kann.

Dies ist nur für das MSVC-kompatible Speicherlayout implementiert (siehe _layout_).

Das Setzen von _pack_ auf 0 ist dasselbe wie das Nicht-Setzen. Andernfalls muss der Wert eine positive Zweierpotenz sein. Die Auswirkung ist äquivalent zu #pragma pack(N) in C, außer dass ctypes möglicherweise größere *n* zulässt, als der Compiler akzeptiert.

_pack_ muss bereits definiert sein, wenn _fields_ zugewiesen wird, andernfalls hat es keine Auswirkung.

Seit Version 3.14 veraltet, wird in Version 3.19 entfernt: Aus historischen Gründen wird das MSVC-kompatible Layout standardmäßig verwendet, wenn _pack_ ungleich Null ist. Auf Nicht-Windows-Plattformen ist dieser Standard veraltet und wird in Python 3.19 zu einem Fehler. Wenn dies beabsichtigt ist, setzen Sie _layout_ explizit auf 'ms'.

_align_

Eine optionale kleine Ganzzahl, die die Ausrichtung der Struktur beim Packen oder Entpacken von/in Speicher erhöht.

Der Wert darf nicht negativ sein. Die Wirkung ist äquivalent zu __attribute__((aligned(N))) auf GCC oder #pragma align(N) auf MSVC, mit der Ausnahme, dass ctypes möglicherweise Werte zulässt, die der Compiler ablehnen würde.

_align_ kann die Ausrichtungsanforderungen einer Struktur nur *erhöhen*. Ein Wert von 0 oder 1 hat keine Auswirkung.

Die Verwendung von Werten, die keine Zweierpotenzen sind, wird nicht empfohlen und kann zu überraschenden Ergebnissen führen.

_align_ muss bereits definiert sein, wenn _fields_ zugewiesen wird, andernfalls hat dies keine Auswirkung.

Hinzugefügt in Version 3.13.

_layout_

Ein optionaler String, der das Layout von Struktur/Union benennt. Er kann derzeit gesetzt werden auf

  • "ms": das Layout, das vom Microsoft-Compiler (MSVC) verwendet wird. Auf GCC und Clang kann dieses Layout mit __attribute__((ms_struct)) ausgewählt werden.

  • "gcc-sysv": das Layout, das von GCC mit dem System V oder „SysV-ähnlichen“ Datenmodell verwendet wird, wie es unter Linux und macOS verwendet wird. Mit diesem Layout muss _pack_ nicht gesetzt oder Null sein.

Wenn nicht explizit gesetzt, verwendet ctypes einen Standardwert, der den Konventionen der Plattform entspricht. Dieser Standardwert kann sich in zukünftigen Python-Versionen ändern (z. B. wenn eine neue Plattform offiziellen Support erhält oder wenn ein Unterschied zwischen ähnlichen Plattformen festgestellt wird). Derzeit ist der Standardwert:

  • Unter Windows: "ms"

  • Wenn _pack_ angegeben ist: "ms". (Dies ist veraltet; siehe Dokumentation zu _pack_.)

  • Andernfalls: "gcc-sysv"

_layout_ muss bereits definiert sein, wenn _fields_ zugewiesen wird, andernfalls hat dies keine Auswirkung.

Hinzugefügt in Version 3.14.

_anonymous_

Eine optionale Sequenz, die die Namen von unbenannten (anonymen) Feldern auflistet. _anonymous_ muss bereits definiert sein, wenn _fields_ zugewiesen wird, andernfalls hat dies keine Auswirkung.

Die in dieser Variablen aufgeführten Felder müssen Felder vom Typ Struktur oder Union sein. ctypes erstellt Deskriptoren im Strukturtyp, die den direkten Zugriff auf die verschachtelten Felder ermöglichen, ohne dass die Struktur oder das Union-Feld erstellt werden muss.

Hier ist ein Beispieltyp (Windows)

class _U(Union):
    _fields_ = [("lptdesc", POINTER(TYPEDESC)),
                ("lpadesc", POINTER(ARRAYDESC)),
                ("hreftype", HREFTYPE)]

class TYPEDESC(Structure):
    _anonymous_ = ("u",)
    _fields_ = [("u", _U),
                ("vt", VARTYPE)]

Die Struktur TYPEDESC beschreibt einen COM-Datentyp, das Feld vt gibt an, welches der Union-Felder gültig ist. Da das Feld u als anonymes Feld definiert ist, ist es nun möglich, direkt auf die Member der TYPEDESC-Instanz zuzugreifen. td.lptdesc und td.u.lptdesc sind äquivalent, aber ersteres ist schneller, da keine temporäre Union-Instanz erstellt werden muss.

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

Es ist möglich, Unterklassen von Strukturen zu definieren, diese erben die Felder der Basisklasse. Wenn die Unterklassendefinition eine separate Variable _fields_ hat, werden die darin angegebenen Felder an die Felder der Basisklasse angehängt.

Struktur- und Union-Konstruktoren akzeptieren sowohl Positions- als auch Schlüsselwortargumente. Positionsargumente werden verwendet, um Mitgliedsfelder in derselben Reihenfolge zu initialisieren, in der sie in _fields_ erscheinen. Schlüsselwortargumente im Konstruktor werden als Attributzuweisungen interpretiert, sodass sie _fields_ mit demselben Namen initialisieren oder neue Attribute für Namen erstellen, die nicht in _fields_ vorhanden sind.

class ctypes.CField(*args, **kw)

Deskriptor für Felder einer Structure und Union. Zum Beispiel

>>> class Color(Structure):
...     _fields_ = (
...         ('red', c_uint8),
...         ('green', c_uint8),
...         ('blue', c_uint8),
...         ('intense', c_bool, 1),
...         ('blinking', c_bool, 1),
...    )
...
>>> Color.red
<ctypes.CField 'red' type=c_ubyte, ofs=0, size=1>
>>> Color.green.type
<class 'ctypes.c_ubyte'>
>>> Color.blue.byte_offset
2
>>> Color.intense
<ctypes.CField 'intense' type=c_bool, ofs=3, bit_size=1, bit_offset=0>
>>> Color.blinking.bit_offset
1

Alle Attribute sind schreibgeschützt.

CField Objekte werden über _fields_ erstellt; instanziieren Sie die Klasse nicht direkt.

Hinzugefügt in Version 3.14: Zuvor hatten Deskriptoren nur Attribute offset und size und eine lesbare Zeichenkettenrepräsentation; die Klasse CField war nicht direkt verfügbar.

name

Name des Feldes, als Zeichenkette.

type

Typ des Feldes, als ctypes-Klasse.

offset
byte_offset

Offset des Feldes in Bytes.

Bei Bitfeldern ist dies der Offset der zugrundeliegenden Byte-ausgerichteten *Speichereinheit*; siehe bit_offset.

byte_size

Größe des Feldes in Bytes.

Bei Bitfeldern ist dies die Größe der zugrundeliegenden *Speichereinheit*. Typischerweise hat sie die gleiche Größe wie der Typ des Bitfeldes.

size

Für Nicht-Bitfelder äquivalent zu byte_size.

Für Bitfelder enthält dies einen abwärtskompatiblen, bitgepackten Wert, der bit_size und bit_offset kombiniert. Es ist vorzuziehen, die expliziten Attribute zu verwenden.

is_bitfield

True, wenn dies ein Bitfeld ist.

bit_offset
bit_size

Die Position eines Bitfeldes innerhalb seiner *Speichereinheit*, d.h. innerhalb von byte_size Bytes Speicher, beginnend bei byte_offset.

Um den Wert des Feldes zu erhalten, lesen Sie die Speichereinheit als Ganzzahl, verschieben Sie sie nach links um bit_offset und nehmen Sie die bit_size niedrigstwertigen Bits.

Für Nicht-Bitfelder ist bit_offset Null und bit_size ist gleich byte_size * 8.

is_anonymous

True, wenn dieses Feld anonym ist, d.h. es enthält verschachtelte Unterfelder, die in eine enthaltende Struktur oder Union zusammengeführt werden sollten.

Arrays und Zeiger

class ctypes.Array(*args)

Abstrakte Basisklasse für Arrays.

Der empfohlene Weg zur Erstellung konkreter Array-Typen ist die Multiplikation eines beliebigen ctypes-Datentyps mit einer nicht-negativen Ganzzahl. Alternativ können Sie diese Klasse unterklassifizieren und die Klassenvariablen _length_ und _type_ definieren. Array-Elemente können über standardmäßige Subskript- und Slice-Zugriffe gelesen und geschrieben werden; für Slice-Lesevorgänge ist das resultierende Objekt *nicht* selbst ein Array.

_length_

Eine positive Ganzzahl, die die Anzahl der Elemente im Array angibt. Außerhalb des Bereichs liegende Indizes führen zu einem IndexError. Wird von len() zurückgegeben.

_type_

Gibt den Typ jedes Elements im Array an.

Array-Unterklassen-Konstruktoren akzeptieren Positionsargumente, die zur Initialisierung der Elemente in der Reihenfolge verwendet werden.

ctypes.ARRAY(type, length)

Erstellt ein Array. Äquivalent zu type * length, wobei *type* ein ctypes-Datentyp und *length* eine Ganzzahl ist.

Diese Funktion ist zugunsten der Multiplikation soft deprecated. Es gibt keine Pläne, sie zu entfernen.

class ctypes._Pointer

Private, abstrakte Basisklasse für Zeiger.

Konkrete Zeigertypen werden durch Aufruf von POINTER() mit dem Typ, auf den gezeigt wird, erstellt; dies geschieht automatisch durch pointer().

Wenn ein Zeiger auf ein Array zeigt, können dessen Elemente über standardmäßige Subskript- und Slice-Zugriffe gelesen und geschrieben werden. Zeigerobjekte haben keine Größe, daher löst len() einen TypeError aus. Negative Indizes lesen aus dem Speicher *vor* dem Zeiger (wie in C), und außerhalb des Bereichs liegende Indizes führen wahrscheinlich zu einem Absturz mit Zugriffsverletzung (wenn Sie Glück haben).

_type_

Gibt den Typ an, auf den gezeigt wird.

contents

Gibt das Objekt zurück, auf das der Zeiger zeigt. Eine Zuweisung zu diesem Attribut ändert den Zeiger, sodass er auf das zugewiesene Objekt zeigt.

Ausnahmen

exception ctypes.ArgumentError

Diese Ausnahme wird ausgelöst, wenn ein Aufruf einer fremden Funktion eines der übergebenen Argumente nicht konvertieren kann.

exception ctypes.COMError(hresult, text, details)

Diese Ausnahme wird ausgelöst, wenn ein COM-Methodenaufruf fehlschlägt.

hresult

Der ganzzahlige Wert, der den Fehlercode darstellt.

text

Die Fehlermeldung.

details

Das 5-Tupel (descr, source, helpfile, helpcontext, progid).

descr ist die textuelle Beschreibung. source ist die sprachabhängige ProgID für die Klasse oder Anwendung, die den Fehler ausgelöst hat. helpfile ist der Pfad zur Hilfedatei. helpcontext ist die ID des Hilfe-Kontextes. progid ist die ProgID der Schnittstelle, die den Fehler definiert hat.

Verfügbarkeit: Windows

Hinzugefügt in Version 3.14.