"ctypes" --- Una biblioteca de funciones foráneas para Python
*************************************************************

======================================================================

"ctypes" es una biblioteca de funciones foráneas para Python.
Proporciona tipos de datos compatibles con C y permite llamar a
funciones en archivos DLL o bibliotecas compartidas. Se puede utilizar
para envolver estas bibliotecas en Python puro.


tutorial de ctypes
==================

Note: The code samples in this tutorial use "doctest" to make sure
that they actually work.  Since some code samples behave differently
under Linux, Windows, or macOS, they contain doctest directives in
comments.

Nota: Algunos ejemplos de código hacen referencia al tipo ctypes
"c_int". En las plataformas donde "sizeof(long) == sizeof(int)" es un
alias de "c_long". Por lo tanto, no debe confundirse si "c_long" se
imprime si espera "c_int" --- son en realidad del mismo tipo.


Carga de bibliotecas de enlaces dinámicos
-----------------------------------------

"ctypes" exporta los objetos *cdll* y en Windows *windll* y *oledll*,
para cargar bibliotecas de enlaces dinámicos.

Las bibliotecas se cargan accediendo a ellas como atributos de estos
objetos. *cdll* carga bibliotecas que exportan funciones utilizando la
convención de llamada estándar "cdecl", mientras que las bibliotecas
*windll* llaman a funciones mediante la convención de llamada
"stdcall". *oledll* también utiliza la convención de llamada "stdcall"
y asume que las funciones retornan un código de error Windows
"HRESULT". El código de error se utiliza para generar automáticamente
una excepción "OSError" cuando se produce un error en la llamada a la
función.

Distinto en la versión 3.3: Los errores de Windows solían generar
"WindowsError", que ahora es un alias de "OSError".

Estos son algunos ejemplos para Windows. Tener en cuenta que
''msvcrt'' es la biblioteca estándar de MS C que contiene la mayoría
de las funciones C estándar y utiliza la convención de llamada cdecl:

   >>> from ctypes import *
   >>> print(windll.kernel32)  
   <WinDLL 'kernel32', handle ... at ...>
   >>> print(cdll.msvcrt)      
   <CDLL 'msvcrt', handle ... at ...>
   >>> libc = cdll.msvcrt      
   >>>

Windows agrega automáticamente la extensión común ".dll".

Nota:

  Acceder a la biblioteca estándar de C a través de "cdll.msvcrt"
  utilizará una versión obsoleta de la biblioteca que puede ser
  incompatible con la utilizada por Python. Cuando sea posible, use la
  funcionalidad nativa de Python, o bien importe y use el módulo
  "msvcrt".

En Linux, se requiere especificar el nombre de archivo *incluyendo* la
extensión para cargar una biblioteca, por lo que no se puede utilizar
el acceso por atributos para cargar las bibliotecas. Se debe usar el
método "LoadLibrary()" de los cargadores de dll, o se debe cargar la
biblioteca creando una instancia de CDLL llamando al constructor:

   >>> cdll.LoadLibrary("libc.so.6")  
   <CDLL 'libc.so.6', handle ... at ...>
   >>> libc = CDLL("libc.so.6")       
   >>> libc                           
   <CDLL 'libc.so.6', handle ... at ...>
   >>>


Acceder a las funciones de los dll cargados
-------------------------------------------

Las funciones se acceden como atributos de los objetos dll:

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

Nótese que las dlls del sistema win32 como "kernel32" y "user32" a
menudo exportan versiones ANSI y UNICODE de una función. La versión
UNICODE se exporta con una "W" añadida al nombre, mientras que la
versión ANSI se exporta con una "A" añadida al nombre. La función
"GetModuleHandle" de win32, que retorna un *manejador de módulo* para
un nombre de módulo dado, tiene el siguiente prototipo de C, y se usa
una macro para exponer uno de ellos como "GetModuleHandle" dependiendo
de si UNICODE está definido o no:

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

*windll* no intenta seleccionar una de ellas por arte de magia, se
debe acceder a la versión que se necesita especificando
"GetModuleHandleA" o "GetModuleHandleW" explícitamente, y luego
llamarlo con bytes u objetos de cadena respectivamente.

A veces, las dlls exportan funciones con nombres que no son
identificadores válidos de Python, como ""??2@YAPAXI@Z"". En este caso
tienes que usar "getattr()" para recuperar la función:

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

En Windows, algunas dlls exportan funciones no por nombre sino por
ordinal. Se pueden acceder a estas funciones indexando el objeto dll
con el número ordinal:

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


Funciones de llamada
--------------------

Puedes llamar a estas funciones como cualquier otra función en Python.
Este ejemplo utiliza la función "time()", que retorna el tiempo del
sistema en segundos desde la época de Unix, y la función
"GetModuleHandleA()", que retorna un manejador de módulo de win32.

Este ejemplo llama a ambas funciones con un puntero "NULL" ("None"
debe ser usado como el puntero "NULL"):

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

"ValueError" es lanzado cuando se llama a una función "stdcall" con la
convención de llamada "cdecl", o viceversa:

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

Para saber la convención de llamada correcta, hay que mirar en el
archivo de encabezado C o en la documentación de la función que se
quiere llamar.

En Windows, "ctypes" utiliza la gestión de excepciones estructurada de
win32 para evitar que se produzcan fallos de protección general cuando
se llaman funciones con valores de argumento inválidos:

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

Sin embargo, hay suficientes maneras de bloquear Python con "ctypes",
así que debes tener cuidado de todos modos. El módulo "faulthandler"
puede ser útil para depurar bloqueos (por ejemplo, provenientes de
fallos de segmentación producidos por llamadas erróneas a la
biblioteca C).

Los objetos "None", enteros, bytes y cadenas (unicode) son los únicos
objetos nativos de Python que pueden ser usados directamente como
parámetros en estas llamadas a funciones. "None" se pasa como puntero
de C "NULL", los objetos bytes y las cadenas se pasan como puntero al
bloque de memoria que contiene sus datos ("char *" o "wchar_t *"). Los
enteros de Python se pasan como por defecto en la plataforma como tipo
"int" de C, su valor se enmascara para que encuadre en el tipo C.

Antes de pasar a llamar funciones con otros tipos de parámetros,
tenemos que aprender más sobre los tipos de datos "ctypes".


Tipos de datos fundamentales
----------------------------

"ctypes" define un número de tipos de datos primitivos compatibles con
C:

+------------------------+--------------------------------------------+------------------------------+
| tipo ctypes            | Tipo C                                     | Tipo Python                  |
|========================|============================================|==============================|
| "c_bool"               | "_Bool"                                    | bool (1)                     |
+------------------------+--------------------------------------------+------------------------------+
| "c_char"               | "char"                                     | Un objeto bytes de           |
|                        |                                            | 1-caracter                   |
+------------------------+--------------------------------------------+------------------------------+
| "c_wchar"              | "wchar_t"                                  | Una cadena de 1-caracter     |
+------------------------+--------------------------------------------+------------------------------+
| "c_byte"               | "char"                                     | entero                       |
+------------------------+--------------------------------------------+------------------------------+
| "c_ubyte"              | "unsigned char"                            | entero                       |
+------------------------+--------------------------------------------+------------------------------+
| "c_short"              | "short"                                    | entero                       |
+------------------------+--------------------------------------------+------------------------------+
| "c_ushort"             | "unsigned short"                           | entero                       |
+------------------------+--------------------------------------------+------------------------------+
| "c_int"                | "int"                                      | entero                       |
+------------------------+--------------------------------------------+------------------------------+
| "c_uint"               | "unsigned int"                             | entero                       |
+------------------------+--------------------------------------------+------------------------------+
| "c_long"               | "long"                                     | entero                       |
+------------------------+--------------------------------------------+------------------------------+
| "c_ulong"              | "unsigned long"                            | entero                       |
+------------------------+--------------------------------------------+------------------------------+
| "c_longlong"           | "__int64" o "long long"                    | entero                       |
+------------------------+--------------------------------------------+------------------------------+
| "c_ulonglong"          | "unsigned __int64" o "unsigned long long"  | entero                       |
+------------------------+--------------------------------------------+------------------------------+
| "c_size_t"             | "size_t"                                   | entero                       |
+------------------------+--------------------------------------------+------------------------------+
| "c_ssize_t"            | "ssize_t" o "Py_ssize_t"                   | entero                       |
+------------------------+--------------------------------------------+------------------------------+
| "c_float"              | "float"                                    | flotante                     |
+------------------------+--------------------------------------------+------------------------------+
| "c_double"             | "double"                                   | flotante                     |
+------------------------+--------------------------------------------+------------------------------+
| "c_longdouble"         | "long double"                              | flotante                     |
+------------------------+--------------------------------------------+------------------------------+
| "c_char_p"             | "char *" (NUL terminated)                  | objecto de bytes o "None"    |
+------------------------+--------------------------------------------+------------------------------+
| "c_wchar_p"            | "wchar_t *" (NUL terminated)               | cadena o "None"              |
+------------------------+--------------------------------------------+------------------------------+
| "c_void_p"             | "void *"                                   | entero o "None"              |
+------------------------+--------------------------------------------+------------------------------+

1. El constructor acepta cualquier objeto con valor verdadero.

Todos estos tipos pueden ser creados llamándolos con un inicializador
opcional del tipo y valor correctos:

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

Dado que estos tipos son mutables, su valor también puede ser cambiado
después:

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

Asignando un nuevo valor a las instancias de los tipos de punteros
"c_char_p", "c_wchar_p", y "c_void_p" cambia el *lugar de memoria* al
que apuntan, *no el contenido* del bloque de memoria (por supuesto que
no, porque los objetos de bytes de Python son inmutables):

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

Sin embargo, debe tener cuidado de no pasarlos a funciones que esperan
punteros a la memoria mutable. Si necesitas bloques de memoria
mutables, ctypes tiene una función "create_string_buffer()" que los
crea de varias maneras. El contenido actual del bloque de memoria
puede ser accedido (o cambiado) con la propiedad "raw"; si quieres
acceder a él como cadena terminada NUL, usa la propiedad "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'
   >>>

La función "create_string_buffer()" reemplaza a la función
"c_buffer()" (que todavía está disponible como un alias), así como a
la función "c_string()" de versiones anteriores de ctypes. Para crear
un bloque de memoria mutable que contenga caracteres unicode del tipo
C "wchar_t" utilice la función "create_unicode_buffer()".


Funciones de llamada, continuación
----------------------------------

Note que printf imprime al canal de salida estándar real, *no* a
"sys.stdout", por lo que estos ejemplos sólo funcionarán en el prompt
de la consola, no desde dentro de *IDLE* o *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>
   ArgumentError: argument 2: exceptions.TypeError: Don't know how to convert parameter 2
   >>>

Como se ha mencionado antes, todos los tipos de Python, excepto los
enteros, cadenas y objetos bytes, tienen que ser envueltos en su
correspondiente tipo "ctypes", para que puedan ser convertidos al tipo
de datos C requerido:

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


Funciones de llamada con sus propios tipos de datos personalizados
------------------------------------------------------------------

También puedes personalizar la conversión de argumentos de "ctypes"
para permitir que las instancias de tus propias clases se usen como
argumentos de función. "ctypes" busca un atributo "_as_parameter_" y
lo usa como argumento de función. Por supuesto, debe ser uno de
entero, cadena o bytes:

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

Si no quieres almacenar los datos de la instancia en la variable de
instancia "_as_parameter_", puedes definir una "property" que haga que
el atributo esté disponible a petición.


Especificar los tipos de argumentos requeridos (prototipos de funciones)
------------------------------------------------------------------------

Es posible especificar los tipos de argumentos necesarios de las
funciones exportadas desde las DLL estableciendo el atributo
"argtypes".

"argtypes" debe ser una secuencia de tipos de datos de C (la función
"printf" probablemente no es un buen ejemplo aquí, porque toma un
número variable y diferentes tipos de parámetros dependiendo del
formato de la cadena, por otro lado esto es bastante útil para
experimentar con esta característica):

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

La especificación de un formato protege contra los tipos de argumentos
incompatibles (al igual que un prototipo para una función C), e
intenta convertir los argumentos en tipos válidos:

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

Si has definido tus propias clases las cuales pasas a las llamadas a
funciones, tienes que implementar un método de clase "from_param()"
para que puedan ser usadas en la secuencia "argtypes". El método de
clase "from_param()" recibe el objeto Python que se le pasa a la
llamada a función, debería hacer una comprobación de tipo o lo que sea
necesario para asegurarse de que este objeto es aceptable, y luego
retornar el objeto en sí, su atributo "_as_parameter_", o lo que se
quiera pasar como argumento de la función C en este caso. De nuevo, el
resultado debe ser un entero, una cadena, unos bytes, una instancia
"ctypes", o un objeto con el atributo "_as_parameter_".


Tipos de retorno
----------------

Por defecto, se supone que las funciones retornan el tipo C "int". Se
pueden especificar otros tipos de retorno estableciendo el atributo
"restype" del objeto de la función.

Aquí hay un ejemplo más avanzado, utiliza la función "strchr", que
espera un puntero de cadena y un carácter, y retorna un puntero a una
cadena:

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

Si quieres evitar las llamadas "ord("x")" de arriba, puedes establecer
el atributo "argtypes", y el segundo argumento se convertirá de un
objeto de un solo carácter de bytes de Python a un char:

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

También puedes usar un objeto Python invocable (una función o una
clase, por ejemplo) como el atributo "restype", si la función foránea
retorna un número entero. El objeto invocable será llamado con el
*entero* que la función C retorna, y el resultado de esta llamada será
utilizado como resultado de la llamada a la función. Esto es útil para
comprobar si hay valores de retorno de error y plantear
automáticamente una excepción:

   >>> 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" es una función que llamará a la api Windows "FormatMessage"
para obtener la representación de la cadena de un código de error, y
retornará una excepción. "WinError" toma un parámetro de código de
error opcional, si no se usa ninguno, llama a "GetLastError`()" para
recuperarlo.

Tenga en cuenta que un mecanismo de comprobación de errores mucho más
potente está disponible a través del atributo "errcheck"; consulte el
manual de referencia para obtener más detalles.


Pasar los punteros (o: pasar los parámetros por referencia)
-----------------------------------------------------------

A veces una función api C espera un *puntero* a un tipo de datos como
parámetro, probablemente para escribir en el lugar correspondiente, o
si los datos son demasiado grandes para ser pasados por valor. Esto
también se conoce cómo *pasar parámetros por referencia*.

"ctypes" exporta la función "byref()" que se utiliza para pasar
parámetros por referencia. El mismo efecto se puede conseguir con la
función "pointer()", aunque "pointer()" hace mucho más trabajo ya que
construye un objeto puntero real, por lo que es más rápido usar
"byref()" si no se necesita el objeto puntero en el propio Python:

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


Estructuras y uniones
---------------------

Las estructuras y uniones deben derivar de las clases base "Structure"
y "Union" que se definen en el módulo "ctypes". Cada subclase debe
definir un atributo "_fields_". "_fields_" debe ser una lista de
*2-tuplas*, que contenga un *nombre de campo* y un *tipo de campo*.

El tipo de campo debe ser un tipo "ctypes" como "c_int", o cualquier
otro tipo "ctypes" derivado: estructura, unión, matriz, puntero.

Aquí hay un ejemplo simple de una estructura POINT, que contiene dos
enteros llamados *x* y *y*, y también muestra cómo inicializar una
estructura en el constructor:

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

Sin embargo, se pueden construir estructuras mucho más complicadas.
Una estructura puede contener por sí misma otras estructuras usando
una estructura como tipo de campo.

Aquí hay una estructura RECT que contiene dos POINTs llamados
*upperleft* (superior izquierda)y *lowerright* (abajo a la derecha):

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

Las estructuras anidadas también pueden ser inicializadas en el
constructor de varias maneras:

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

El campo *descriptor* puede ser recuperado de la *class*, son útiles
para la depuración porque pueden proporcionar información útil:

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

Advertencia:

  "ctypes" no soporta el paso de uniones o estructuras con campos de
  bits a funciones por valor. Aunque esto puede funcionar en 32-bit
  x86, la biblioteca no garantiza que funcione en el caso general. Las
  uniones y estructuras con campos de bits siempre deben pasarse a las
  funciones por puntero.


Alineación de estructura/unión y orden de bytes
-----------------------------------------------

Por defecto, los campos de Estructura y Unión están alineados de la
misma manera que lo hace el compilador C. Es posible anular este
comportamiento especificando un atributo de clase "_pack_" en la
definición de la subclase. Este debe ser establecido como un entero
positivo y especifica la alineación máxima de los campos. Esto es lo
que "#pragma pack(n)" también hace en MSVC.

"ctypes" utiliza el orden de bytes nativos para las Estructuras y
Uniones. Para construir estructuras con un orden de bytes no nativo,
puedes usar una de las clases base "BigEndianStructure",
"LittleEndianStructure", "BigEndianUnion", y "LittleEndianUnion".
Estas clases no pueden contener campos puntero.


Campos de bits en estructuras y uniones
---------------------------------------

Es posible crear estructuras y uniones que contengan campos de bits.
Los campos de bits sólo son posibles para campos enteros, el ancho de
bit se especifica como el tercer ítem en las tuplas "_fields_":

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


Arreglos
--------

Los arreglos son secuencias, que contienen un número fijo de
instancias del mismo tipo.

La forma recomendada de crear tipos de arreglos es multiplicando un
tipo de dato por un entero positivo:

   TenPointsArrayType = POINT * 10

Aquí hay un ejemplo de un tipo de datos algo artificial, una
estructura que contiene 4 POINTs entre otras cosas:

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

Las instancias se crean de la manera habitual, llamando a la clase:

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

El código anterior imprime una serie de líneas "0 0", porque el
contenido del arreglos se inicializa con ceros.

También se pueden especificar inicializadores del tipo correcto:

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


Punteros
--------

Las instancias de puntero se crean llamando a la función "pointer()"
en un tipo "ctypes":

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

Las instancias del puntero tienen un atributo "contents" que retorna
el objeto al que apunta el puntero, el objeto "i" arriba:

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

Ten en cuenta que "ctypes" no tiene OOR (original object return),
construye un nuevo objeto equivalente cada vez que recuperas un
atributo:

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

Asignar otra instancia "c_int" al atributo de contenido del puntero
causaría que el puntero apunte al lugar de memoria donde se almacena:

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

Las instancias de puntero también pueden ser indexadas con números
enteros:

   >>> pi[0]
   99
   >>>

Asignando a un índice entero cambia el valor señalado:

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

También es posible usar índices diferentes de 0, pero debes saber lo
que estás haciendo, al igual que en C: Puedes acceder o cambiar
arbitrariamente las ubicaciones de memoria. Generalmente sólo usas
esta característica si recibes un puntero de una función C, y *sabes*
que el puntero en realidad apunta a un arreglo en lugar de a un solo
elemento.

Entre bastidores, la función "pointer()" hace más que simplemente
crear instancias de puntero, tiene que crear primero punteros *tipos*.
Esto se hace con la función "POINTER()", que acepta cualquier tipo de
"ctypes", y retorna un nuevo tipo:

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

Llamar al tipo de puntero sin un argumento crea un puntero "NULL". Los
punteros "NULL" tienen un valor booleano falso..:

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

"ctypes" comprueba si hay "NULL" cuando los punteros de referencia
(pero los punteros no válidos de referencia no-"NULL" se romperán en
Python):

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

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


Conversiones de tipos
---------------------

Por lo general, los ctypes hacen un control estricto de los tipos.
Esto significa que si tienes "POINTER(c_int)" en la lista "argtypes"
de una función o como el tipo de un campo miembro en una definición de
estructura, sólo se aceptan instancias exactamente del mismo tipo. Hay
algunas excepciones a esta regla, en las que ctypes acepta otros
objetos. Por ejemplo, se pueden pasar instancias de arreglo
compatibles en lugar de tipos de puntero. Así, para "POINTER(c_int)",
ctypes acepta un arreglo de *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
   >>>

Además, si se declara explícitamente que un argumento de función es de
tipo puntero (como "POINTER(c_int)") en "argtypes", se puede pasar un
objeto de tipo puntero ("c_int" en este caso) a la función. ctypes
aplicará la conversión "byref()" requerida en este caso
automáticamente.

Para poner un campo de tipo POINTER a "NULL", puedes asignar "None":

   >>> bar.values = None
   >>>

A veces se tienen instancias de tipos incompatibles. En C, puedes
cambiar un tipo por otro tipo. "ctypes" proporciona una función
"cast()" qué puede ser usada de la misma manera. La estructura "Bar"
definida arriba acepta punteros "POINTER(c_int)" o arreglos "c_int`"
para su campo "values", pero no instancias de otros tipos:

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

Para estos casos, la función "cast()" es muy útil.

La función "cast()" puede ser usada para lanzar una instancia ctypes
en un puntero a un tipo de datos ctypes diferente. "cast()" toma dos
parámetros, un objeto ctypes que es o puede ser convertido en un
puntero de algún tipo, y un tipo de puntero ctypes. retorna una
instancia del segundo argumento, que hace referencia al mismo bloque
de memoria que el primer argumento:

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

Así, "cast()" puede ser usado para asignar al campo "values" de "Bar"
la estructura:

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


Tipos incompletos
-----------------

*Los Tipos Incompletos* son estructuras, uniones o matrices cuyos
miembros aún no están especificados. En C, se especifican mediante
declaraciones a futuro, que se definen más adelante:

   struct cell; /* forward declaration */

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

La traducción directa al código de ctypes sería esta, pero no
funciona:

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

porque la nueva "class cell" no está disponible en la propia
declaración de clase. En "ctypes", podemos definir la clase "cell" y
establecer el atributo "_fields_" más tarde, después de la declaración
de clase:

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

Vamos a intentarlo. Creamos dos instancias de "cell", y dejamos que se
apunten una a la otra, y finalmente seguimos la cadena de punteros
unas cuantas veces:

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


Funciones de retrollamadas (*callback*)
---------------------------------------

"ctypes" permite crear punteros de función invocables C a partir de
los invocables de Python. A veces se llaman *funciones de
retrollamada*.

Primero, debes crear una clase para la función de retrollamada. La
clase conoce la convención de llamada, el tipo de retorno, y el número
y tipos de argumentos que esta función recibirá.

La función de fábrica "CFUNCTYPE`()" crea tipos para las funciones de
retrollamada usando la convención de llamada "cdecl". En Windows, la
función de fábrica "WINFUNCTYPE()" crea tipos para funciones de
retrollamadas usando la convención de llamadas "stdcall".

Ambas funciones de fábrica se llaman con el tipo de resultado como
primer argumento, y las funciones de llamada de retorno con los tipos
de argumentos esperados como los argumentos restantes.

Presentaré un ejemplo aquí que utiliza la función "qsort()" de la
biblioteca estándar de C, que se utiliza para ordenar los elementos
con la ayuda de una función de retrollamada. "qsort()" se utilizará
para ordenar un conjunto de números enteros:

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

"qsort()" debe ser llamada con un puntero a los datos a ordenar, el
número de elementos en el array de datos, el tamaño de un elemento, y
un puntero a la función de comparación, la llamada de retorno. La
llamada de retorno se llamará entonces con dos punteros a los ítems, y
debe retornar un entero negativo si el primer ítem es más pequeño que
el segundo, un cero si son iguales, y un entero positivo en caso
contrario.

Así que nuestra función de retrollamada recibe punteros a números
enteros, y debe retornar un número entero. Primero creamos el "tipo"
para la función de retrollamada:

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

Para empezar, aquí hay una simple llamada que muestra los valores que
se pasan:

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

El resultado:

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

Ahora podemos comparar los dos artículos y obtener un resultado útil:

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

Como podemos comprobar fácilmente, nuestro arreglo está ordenado
ahora:

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

Las funciones de fabrica pueden ser usadas como decoradores de
fabrica, así que podemos escribir:

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

Nota:

  Asegúrate de mantener las referencias a los objetos "CFUNCTYPE()"
  mientras se usen desde el código C. "ctypes" no lo hace, y si no lo
  haces, pueden ser basura recolectada, colapsando tu programa cuando
  se hace una llamada.Además, nótese que sí se llama a la función de
  retrollamada en un hilo creado fuera del control de Python (por
  ejemplo, por el código foráneo que llama a la retrollamada), ctypes
  crea un nuevo hilo Python tonto en cada invocación. Este
  comportamiento es correcto para la mayoría de los propósitos, pero
  significa que los valores almacenados con "threading.local" *no*
  sobreviven a través de diferentes llamadas de retorno, incluso
  cuando esas llamadas se hacen desde el mismo hilo C.


Acceder a los valores exportados de los dlls
--------------------------------------------

Algunas bibliotecas compartidas no sólo exportan funciones, sino
también variables. Un ejemplo en la propia biblioteca de Python es el
"Py_OptimizeFlag", un entero establecido en 0, 1, o 2, dependiendo del
flag "-O" o "-OO" dado en el inicio.

"ctypes" puede acceder a valores como este con los métodos de la clase
"in_dll()" del tipo. *pythonapi* es un símbolo predefinido que da
acceso a la API de Python C:

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

Si el intérprete se hubiera iniciado con "-O", el ejemplo habría
impreso "c_long(1)", o "c_long(2)" si "-OO" se hubiera especificado.

Un ejemplo extendido que también demuestra el uso de punteros
accediendo al puntero "PyImport_FrozenModules" exportado por Python.

Citando los documentos para ese valor:

   Este puntero está inicializado para apuntar a un arreglo de
   registros "struct _frozen`", terminada por uno cuyos miembros son
   todos "NULL" o cero. Cuando se importa un módulo congelado, se
   busca en esta tabla. El código de terceros podría jugar con esto
   para proporcionar una colección creada dinámicamente de módulos
   congelados.

Así que manipular este puntero podría incluso resultar útil. Para
restringir el tamaño del ejemplo, sólo mostramos cómo esta tabla puede
ser leída con "ctypes":

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

Hemos definido el tipo de datos "struct _frozen", para que podamos
obtener el puntero de la tabla:

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

Como *tabla`* es un "puntero" al arreglo de registros "struct_frozen",
podemos iterar sobre ella, pero sólo tenemos que asegurarnos de que
nuestro bucle termine, porque los punteros no tienen tamaño. Tarde o
temprano, probablemente se caerá con una violación de acceso o lo que
sea, así que es mejor salir del bucle cuando le demos a la entrada
"NULL":

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

El hecho de que la Python estándar tenga un módulo congelado y un
paquete congelado (indicado por el miembro "tamaño" negativo) no se
conoce bien, sólo se usa para hacer pruebas. Pruébalo con "import
__hello__" por ejemplo.


Sorpresas
---------

Hay algunas aristas en "ctypes" en las que podrías esperar algo
distinto de lo que realmente sucede.

Considere el siguiente ejemplo:

   >>> 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. Ciertamente esperábamos que la última declaración imprimiera "3 4
1 2". ¿Qué ha pasado? Aquí están los pasos de la línea "rc.a, rc.b =
rc.b, rc.a" arriba:

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

Note que "temp0" y "temp1" son objetos que todavía usan el buffer
interno del objeto "rc" de arriba. Así que ejecutando "rc.a = temp0"
copia el contenido del buffer de "temp0" en el buffer de "rc". Esto, a
su vez, cambia el contenido de "temp1". Por lo tanto, la última
asignación "rc.b = temp1", no tiene el efecto esperado.

Tengan en cuenta que la recuperación de subobjetos de Estructuras,
Uniones y Arreglos no *copia* el subobjeto, sino que recupera un
objeto contenido que accede al búfer subyacente del objeto raíz.

Otro ejemplo que puede comportarse de manera diferente a lo que uno
esperaría es este:

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

Nota:

  Los objetos instanciados desde "c_char_p" sólo pueden tener su valor
  fijado en bytes o enteros.

¿Por qué está imprimiendo "False"? Las instancias ctypes son objetos
que contienen un bloque de memoria más algunos *descriptor*s que
acceden al contenido de la memoria. Almacenar un objeto Python en el
bloque de memoria no almacena el objeto en sí mismo, en su lugar se
almacenan los "contenidos" del objeto. ¡Acceder a los contenidos de
nuevo construye un nuevo objeto Python cada vez!


Tipos de datos de tamaño variable
---------------------------------

"ctypes" proporciona algo de soporte para matrices y estructuras de
tamaño variable.

La función "resize()" puede ser usada para redimensionar el buffer de
memoria de un objeto ctypes existente. La función toma el objeto como
primer argumento, y el tamaño solicitado en bytes como segundo
argumento. El bloque de memoria no puede hacerse más pequeño que el
bloque de memoria natural especificado por el tipo de objeto, se lanza
un "ValueError" si se intenta:

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

Esto está bien, pero ¿cómo se puede acceder a los elementos
adicionales contenidos en este arreglo?  Dado que el tipo todavía sabe
sólo 4 elementos, obtenemos errores al acceder a otros elementos:

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

Otra forma de utilizar tipos de datos de tamaño variable con "ctypes"
es utilizar la naturaleza dinámica de Python, y (re)definir el tipo de
datos después de que se conozca el tamaño requerido, caso por caso.


referencia ctypes
=================


Encontrar bibliotecas compartidas
---------------------------------

Cuando se programa en un lenguaje compilado, se accede a las
bibliotecas compartidas cuando se compila/enlaza un programa, y cuándo
se ejecuta el programa.

El propósito de la función "find_library()" es localizar una
biblioteca de forma similar a lo que hace el compilador o el cargador
en tiempo de ejecución (en plataformas con varias versiones de una
biblioteca compartida se debería cargar la más reciente), mientras que
los cargadores de bibliotecas ctypes actúan como cuando se ejecuta un
programa, y llaman directamente al cargador en tiempo de ejecución.

El módulo "ctypes.util" proporciona una función que puede ayudar a
determinar la biblioteca a cargar.

ctypes.util.find_library(name)

   Intenta encontrar una biblioteca y retornar un nombre. *name* es el
   nombre de la biblioteca sin ningún prefijo como *lib*, sufijo como
   ".so", ".dylib" o número de versión (esta es la forma usada para la
   opción del enlazador posix "-l"). Si no se puede encontrar ninguna
   biblioteca, retorna "None".

La funcionalidad exacta depende del sistema.

En Linux, "find_library()" intenta ejecutar programas externos
("/sbin/ldconfig", "gcc", "objdump" y "ld") para encontrar el archivo
de la biblioteca. retorna el nombre del archivo de la biblioteca.

Distinto en la versión 3.6: En Linux, el valor de la variable de
entorno "LD_LIBRARY_PATH" se utiliza cuando se buscan bibliotecas, si
una biblioteca no puede ser encontrada por ningún otro medio.

Aquí hay algunos ejemplos:

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

On macOS, "find_library()" tries several predefined naming schemes and
paths to locate the library, and returns a full pathname if
successful:

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

En Windows, "find_library`()" busca a lo largo de la ruta de búsqueda
del sistema, y retorna la ruta completa, pero como no hay un esquema
de nombres predefinido, una llamada como "find_library("c")" fallará y
retornará "None".

Si envolvemos una biblioteca compartida con "ctypes", puede ser mejor
determinar el nombre de la biblioteca compartida en tiempo de
desarrollo, y codificarlo en el módulo de envoltura en lugar de usar
"find_library()" para localizar la biblioteca en tiempo de ejecución.


Cargando bibliotecas compartidas
--------------------------------

Hay varias maneras de cargar las bibliotecas compartidas en el proceso
Python. Una forma es instanciar una de las siguientes clases:

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

   Las instancias de esta clase representan bibliotecas compartidas
   cargadas. Las funciones de estas bibliotecas usan la convención
   estándar de llamada C, y se asume que retornan "int".

   En Windows, la creación de una instancia "CDLL" puede fallar
   incluso si existe el nombre de la DLL. Cuando no se encuentra una
   DLL dependiente de la DLL cargada, se lanza un error "OSError" con
   el mensaje *"[WinError 126] No se pudo encontrar el módulo
   especificado".* Este mensaje de error no contiene el nombre de DLL
   que falta porque la API de Windows no devuelve esta información, lo
   que dificulta el diagnóstico de este error. Para resolver este
   error y determinar qué DLL no se encuentra, debe buscar la lista de
   DLL dependientes y determinar cuál no se encuentra utilizando las
   herramientas de depuración y seguimiento de Windows.

Ver también:

  Herramienta Microsoft DUMPBIN -- Una herramienta para encontrar
  dependientes de DLL.

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

   Sólo Windows: Las instancias de esta clase representan bibliotecas
   compartidas cargadas, las funciones en estas bibliotecas usan la
   convención de llamada "stdcall", y se asume que retornan el código
   específico de windows "HRESULT`". Los valores "HRESULT`" contienen
   información que especifica si la llamada a la función falló o tuvo
   éxito, junto con un código de error adicional. Si el valor de
   retorno señala un fracaso, se eleva automáticamente un "OSError`".

   Distinto en la versión 3.3: "WindowsError" solía ser lanzado.

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

   Sólo Windows: Las instancias de esta clase representan bibliotecas
   compartidas cargadas, las funciones de estas bibliotecas usan la
   convención de llamada "stdcall", y se supone que retornan "int" por
   defecto.

El termino Python *global interpreter lock* es lanzado antes de llamar
a cualquier función exportada por estas librerías, y se requiere
después.

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

   Las instancias de esta clase se comportan como instancias "CDLL" ,
   excepto que el GIL de Python es *no* liberado durante la llamada a
   la función, y después de la ejecución de la función se comprueba si
   esta activo el flag de error de Python. Si el flag de error esta
   activado, se lanza una excepción Python.

   Por lo tanto, esto sólo es útil para llamar directamente a las
   funciones api C de Python.

Todas estas clases pueden ser instanciadas llamándolas con al menos un
argumento, la ruta de la biblioteca compartida.  Si tienes un
manejador existente de una biblioteca compartida ya cargada, se puede
pasar como el parámetro llamado "handle", de lo contrario la función
"dlopen" o "LoadLibrary" de la plataforma subyacente es utilizada para
cargar la biblioteca en el proceso, y  obtener un manejador de la
misma.

El parámetro *mode* puede utilizarse para especificar cómo se carga la
biblioteca. Para más detalles, consulte la página *dlopen(3)* del
manual. En Windows, *mode* es ignorado. En los sistemas posix,
RTLD_NOW siempre se agrega, y no es configurable.

El parámetro *use_errno*, cuando se establece en true, habilita un
mecanismo ctypes que permite acceder al número de error del sistema
"errno" de forma segura. "ctypes" mantiene una copia local del hilo de
la variable del sistema "errno"; si llamas a funciones extranjeras
creadas con "use_errno=True" entonces el valor "errno" antes de la
llamada a la función se intercambia con la copia privada de ctypes, lo
mismo ocurre inmediatamente después de la llamada a la función.

La función "ctypes.get_errno()" retorna el valor de la copia privada
de ctypes, y la función "ctypes.set_errno()" cambia la copia privada
de ctypes a un nuevo valor y retorna el valor anterior.

El parámetro *use_last_error*, cuando se establece en true, habilita
el mismo mecanismo para el código de error de Windows que es
administrado por las funciones de la API de Windows "GetLastError()" y
"SetLastError()"; "ctypes.get_last_error()" y
"ctypes.set_last_error()" se utilizan para solicitar y cambiar la
copia privada ctypes del código de error de Windows.

El parámetro *winmode* se utiliza en Windows para especificar cómo se
carga la biblioteca (ya que *mode* se ignora). Toma cualquier valor
que sea válido para el parámetro flags de la API de Win32
"LoadLibraryEx". Cuando se omite, el valor por defecto es usar los
flags que resultan en la carga de DLL más segura para evitar problemas
como el secuestro de DLL. Pasar la ruta completa a la DLL es la forma
más segura de asegurar que se cargan la biblioteca y las dependencias
correctas.

Distinto en la versión 3.8: Añadido el parámetro *winmode*.

ctypes.RTLD_GLOBAL

   Flag para usar como parámetro *modo*. En las plataformas en las que
   esta bandera no está disponible, se define como el cero entero.

ctypes.RTLD_LOCAL

   Flag para usar como parámetro *modo*. En las plataformas en las que
   esto no está disponible, es lo mismo que *RTLD_GLOBAL*.

ctypes.DEFAULT_MODE

   El modo por defecto que se utiliza para cargar las bibliotecas
   compartidas. En OSX 10.3, esto es *RTLD_GLOBAL*, de lo contrario es
   lo mismo que *RTLD_LOCAL*.

Las instancias de estas clases no tienen métodos públicos. Se puede
acceder a las funciones exportadas por la biblioteca compartida como
atributos o por índice. Tenga en cuenta que al acceder a la función a
través de un atributo se almacena en caché el resultado y, por lo
tanto, al acceder a él repetidamente se retorna el mismo objeto cada
vez. Por otro lado, acceder a ella a través de un índice retorna un
nuevo objeto cada vez:

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

Los siguientes atributos públicos están disponibles, su nombre
comienza con un guión bajo para no chocar con los nombres de las
funciones exportadas:

PyDLL._handle

   El manejador del sistema usado para acceder a la biblioteca.

PyDLL._name

   El nombre de la biblioteca pasado en el constructor.

Las bibliotecas compartidas también pueden ser cargadas usando uno de
los objetos prefabricados, que son instancias de la clase
"LibraryLoader", ya sea llamando al método "LoadLibrary()", o
recuperando la biblioteca como atributo de la instancia de carga.

class ctypes.LibraryLoader(dlltype)

   Clase que carga bibliotecas compartidas. *dlltype* debe ser uno de
   los tipos "CDLL", "PyDLL", "WinDLL", o "OleDLL".

   "__getattr__()" tiene un comportamiento especial: Permite cargar
   una biblioteca compartida accediendo a ella como atributo de una
   instancia de carga de biblioteca. El resultado se almacena en
   caché, de modo que los accesos repetidos a los atributos retornan
   la misma biblioteca cada vez.

   LoadLibrary(name)

      Carga una biblioteca compartida en el proceso y la retorna. Este
      método siempre retorna una nueva instancia de la biblioteca.

Estos cargadores prefabricados de bibliotecas están disponibles:

ctypes.cdll

   Crea instancias de "CDLL".

ctypes.windll

   Sólo Windows: Crea instancias de "WinDLL".

ctypes.oledll

   Sólo Windows: Crea instancias de "OleDLL".

ctypes.pydll

   Crea instancias de "PyDLL".

Para acceder directamente a la API C de Python, se dispone de un
objeto de biblioteca compartida de Python listo-para-usar:

ctypes.pythonapi

   Una instancia de "PyDLL" que expone las funciones de la API C de
   Python como atributos. Ten en cuenta que se supone que todas estas
   funciones retornan C "int", lo que por supuesto no siempre es
   cierto, así que tienes que asignar el atributo correcto "restype"
   para usar estas funciones.

Lanza un auditing event "ctypes.dlopen" con argumento "name".

Al acceder a una función en una biblioteca cargada se lanza un evento
de auditoría "ctypes.dlsym" con argumentos "library" (el objeto de la
biblioteca) y "name" (el nombre del símbolo como cadena o entero).

En los casos en los que sólo está disponible el manejador de la
biblioteca en lugar del objeto, al acceder a una función se produce un
evento de auditoría "ctypes.dlsym/handle" con los argumentos "handle"
(el manejador de la biblioteca en bruto) y "name".


Funciones foráneas
------------------

Como se explicó en la sección anterior, se puede acceder a las
funciones foráneas como atributos de las bibliotecas compartidas
cargadas. Los objetos de función creados de esta forma aceptan por
defecto cualquier número de argumentos, aceptan cualquier instancia de
datos ctypes como argumentos y retornan el tipo de resultado por
defecto especificado por el cargador de la biblioteca. Son instancias
de una clase privada:

class ctypes._FuncPtr

   Clase base para funciones foráneas C invocables.

   Las instancias de funciones foráneas también son tipos de datos
   compatibles con C; representan punteros de funciones C.

   Este comportamiento puede personalizarse asignando a los atributos
   especiales del objeto de la función foránea.

   restype

      Asigne un tipo de ctypes para especificar el tipo de resultado
      de la función externa. Usa "None" para "void", una función que
      no retorna nada.

      Es posible asignar un objeto Python invocable que no sea de tipo
      ctypes, en este caso se supone que la función retorna un C
      "int", y el invocable se llamará con este entero, lo que permite
      un posterior procesamiento o comprobación de errores. El uso de
      esto está obsoleto, para un postprocesamiento más flexible o
      para la comprobación de errores utilice un tipo de datos ctypes
      como "restype" y asigne un invocable al atributo "errcheck".

   argtypes

      Asigne una tupla de tipos ctypes para especificar los tipos de
      argumentos que acepta la función. Las funciones que utilizan la
      convención de llamada "stdcall" sólo pueden ser llamadas con el
      mismo número de argumentos que la longitud de esta tupla; las
      funciones que utilizan la convención de llamada C aceptan
      también argumentos adicionales no especificados.

      Cuando se llama a una función foránea, cada argumento real se
      pasa al método de la clase "from_param()" de los elementos de la
      tupla "argtypes", este método permite adaptar el argumento real
      a un objeto que la función externa acepta. Por ejemplo, un
      elemento "c_char_p" de la tupla "argtypes" convertirá una cadena
      pasada como argumento en un objeto de bytes utilizando reglas de
      conversión ctypes.

      Nuevo: Ahora es posible poner en argtypes elementos que no son
      de tipo ctypes, pero cada elemento debe tener un método
      "from_param()" que retorne un valor utilizable como argumento
      (entero, cadena, instancia ctypes). Esto permite definir
      adaptadores que pueden adaptar objetos personalizados como
      parámetros de la función.

   errcheck

      Asigne una función Python u otra llamada a este atributo. El
      invocable será llamado con tres o más argumentos:

      callable(result, func, arguments)

         *result* es lo que retorna la función externa, como se
         especifica en el atributo "restype".

         *func* es el propio objeto de la función foránea, lo que
         permite reutilizar el mismo objeto invocable para comprobar o
         postprocesar los resultados de varias funciones.

         *arguments* es una tupla que contiene los parámetros
         originalmente pasados a la llamada de la función, esto
         permite especializar el comportamiento en los argumentos
         utilizados.

      El objeto que retorna esta función será retornado por la llamada
      de la función foránea, pero también puede comprobar el valor del
      resultado y hacer una excepción si la llamada de la función
      foránea ha fallado.

exception ctypes.ArgumentError

   Esta excepción se lanza cuando una llamada a una función foránea no
   puede convertir uno de los argumentos pasados.

En Windows, cuando una llamada a una función foránea plantea una
excepción de sistema (por ejemplo, debido a una violación de acceso),
será capturada y sustituida por una excepción Python adecuada. Además,
un evento de auditoría "ctypes.seh_exception" con el argumento "code"
será levantado, permitiendo que un gancho de auditoría reemplace la
excepción con la suya propia.

Algunas formas de invocar llamadas a funciones foráneas pueden lanzar
un evento de auditoría "ctypes.call_function" con los argumentos
"function pointer" y "arguments".


Prototipos de funciones
-----------------------

Las funciones foráneas también pueden crearse mediante la
instanciación de prototipos de funciones. Los prototipos de funciones
son similares a los prototipos de funciones en C; describen una
función (tipo de retorno, tipos de argumentos, convención de llamada)
sin definir una implementación. Las funciones de fábrica deben ser
llamadas con el tipo de resultado deseado y los tipos de argumento de
la función, y pueden ser usadas como fábricas de decoradores, y como
tales, ser aplicadas a las funciones a través de la sintaxis
"@wrapper". Ver Funciones de retrollamadas (callback) para ejemplos.

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

   El prototipo de función retornado crea funciones que usan la
   convención de llamada C estándar. La función liberará el GIL
   durante la llamada. Si *use_errno* se configura a true, la copia
   privada de ctypes de la variable del sistema "errno" se intercambia
   con el valor real "errno" antes y después de la llamada;
   *use_last_error* hace lo mismo con el código de error de Windows.

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

   Windows only: The returned function prototype creates functions
   that use the "stdcall" calling convention.  The function will
   release the GIL during the call.  *use_errno* and *use_last_error*
   have the same meaning as above.

ctypes.PYFUNCTYPE(restype, *argtypes)

   El prototipo de función retornado crea funciones que usan la
   convención de llamadas de Python. La función *no* liberará el GIL
   durante la llamada.

Los prototipos de funciones creados por estas funciones de fábrica
pueden ser instanciados de diferentes maneras, dependiendo del tipo y
el número de los parámetros en la llamada:

   prototype(address)

      Retorna una función foránea en la dirección especificada que
      debe ser un número entero.

   prototype(callable)

      Crear una función de llamada C (una función de retrollamada) a
      partir de un *callable* Python.

   prototype(func_spec[, paramflags])

      Retorna una función foránea exportada por una biblioteca
      compartida. *func_spec* debe ser un 2-tupla "(name_or_ordinal,
      library)". El primer elemento es el nombre de la función
      exportada como cadena, o el ordinal de la función exportada como
      entero pequeño. El segundo elemento es la instancia de la
      biblioteca compartida.

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

      Retorna una función foránea que llamará a un método COM.
      *vtbl_index* es el índice de la tabla de funciones virtuales, un
      pequeño entero no negativo. *name* es el nombre del método COM.
      *iid* es un puntero opcional para el identificador de la
      interfaz que se utiliza en el informe de errores extendido.

      Los métodos COM usan una convención especial de llamadas:
      Requieren un puntero a la interfaz COM como primer argumento,
      además de los parámetros que se especifican en la tupla
      "argtypes".

   El parámetro opcional *paramflags* crea envoltorios de funciones
   foráneas con mucha más funcionalidad que las características
   descritas anteriormente.

   *paramflags* deben ser una tupla de la misma longitud que
   "argtypes".

   Cada elemento de esta tupla contiene más información sobre un
   parámetro, debe ser una tupla que contenga uno, dos o tres
   elementos.

   El primer elemento es un entero que contiene una combinación de
   flags de dirección para el parámetro:

      1
         Especifica un parámetro de entrada a la función.

      2
         Parámetro de salida. La función foránea rellena un valor.

      4
         Parámetro de entrada que por defecto es el cero entero.

   El segundo elemento opcional es el nombre del parámetro como
   cadena. Si se especifica esto, se puede llamar a la función foránea
   con parámetros con nombre.

   El tercer elemento opcional es el valor por defecto de este
   parámetro.

Este ejemplo demuestra cómo envolver la función "MessageBoxW" de
Windows para que soporte los parámetros por defecto y los argumentos
con nombre. La declaración C del archivo de cabecera de Windows es
esta:

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

Aquí está el envoltorio con "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)

La función foránea de "MessageBox" puede ser llamada de esta manera:

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

Un segundo ejemplo demuestra los parámetros de salida. La función
"GetWindowRect" de win32 retorna las dimensiones de una ventana
especificada copiándolas en la estructura "RECT" que la persona que
llama tiene que suministrar. Aquí está la declaración C:

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

Aquí está el envoltorio con "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)
   >>>

Las funciones con parámetros de salida retornarán automáticamente el
valor del parámetro de salida si hay uno solo, o una tupla que
contiene los valores del parámetro de salida cuando hay más de uno,
por lo que la función GetWindowRect retorna ahora una instancia RECT,
cuando se llama.

Los parámetros de salida pueden combinarse con el protocolo "errcheck"
para hacer un mayor procesamiento de la salida y la comprobación de
errores. La función api de win32 "GetWindowRect" retorna un "BOOL"
para señalar el éxito o el fracaso, por lo que esta función podría
hacer la comprobación de errores, y plantea una excepción cuando la
llamada api ha fallado:

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

Si la función "errcheck" retorna la tupla de argumentos que recibe sin
cambios, "ctypes" continúa el procesamiento normal que hace en los
parámetros de salida. Si quieres retornar una tupla de coordenadas de
ventana en lugar de una instancia "RECT", puedes recuperar los campos
de la función y retornarlos en su lugar, el procesamiento normal ya no
tendrá lugar:

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


Funciones de utilidad
---------------------

ctypes.addressof(obj)

   Retorna la dirección del buffer de memoria como un entero. *obj*
   debe ser una instancia de tipo ctypes.

   Lanza un auditing event "ctypes.addressof" con el argumento "obj".

ctypes.alignment(obj_or_type)

   Retorna los requerimientos de alineación de un tipo de ctypes.
   *obj_or_type* debe ser un tipo o instancia ctypes.

ctypes.byref(obj[, offset])

   Retorna un puntero ligero a *obj*, que debe ser un ejemplo de un
   tipo de ctypes. *offset* es por defecto cero, y debe ser un entero
   que se añadirá al valor del puntero interno.

   "byref(obj, offset)" corresponde a este código C:

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

   El objeto retornado sólo puede ser utilizado como un parámetro de
   llamada de función foránea. Se comporta de manera similar a
   "pointer(obj)", pero la construcción es mucho más rápida.

ctypes.cast(obj, type)

   Esta función es similar a la del operador de reparto en C. retorna
   una nueva instancia de *type* que apunta al mismo bloque de memoria
   que *obj*. *type* debe ser un tipo de puntero, y *obj* debe ser un
   objeto que pueda ser interpretado como un puntero.

ctypes.create_string_buffer(init_or_size, size=None)

   Esta función crea un búfer de caracteres mutables. El objeto
   retornado es un arreglo de ctypes de "c_char".

   *init_or_size* debe ser un número entero que especifique el tamaño
   del arreglo, o un objeto de bytes que se utilizará para inicializar
   los elementos del arreglo.

   Si se especifica un objeto bytes como primer argumento, el buffer
   se hace un elemento más grande que su longitud, de modo que el
   último elemento del arreglo es un carácter de terminación NUL. Se
   puede pasar un entero como segundo argumento que permite
   especificar el tamaño del arreglo si no se debe utilizar la
   longitud de los bytes.

   Lanza un auditing event "ctypes.create_string_buffer" con
   argumentos "init", "size".

ctypes.create_unicode_buffer(init_or_size, size=None)

   Esta función crea un búfer de caracteres unicode mutable. El objeto
   retornado es un arreglo de ctypes de "c_wchar".

   *init_or_size* debe ser un entero que especifique el tamaño del
   arreglo, o una cadena que se utilizará para inicializar los
   elementos del arreglo.

   Si se especifica una cadena como primer argumento, el búfer se hace
   un elemento más grande que la longitud de la cadena, de modo que el
   último elemento del arreglo es un carácter de terminación NUL. Se
   puede pasar un entero como segundo argumento que permite
   especificar el tamaño del arreglo si no se debe utilizar la
   longitud de la cadena.

   Lanza un auditing event "ctypes.create_unicode_buffer" con
   argumentos "init", "size".

ctypes.DllCanUnloadNow()

   Sólo Windows: Esta función es un gancho que permite implementar
   servidores COM en proceso con ctypes. Se llama desde la función
   DllCanUnloadNow que la extensión _ctypes dll exporta.

ctypes.DllGetClassObject()

   Sólo Windows: Esta función es un gancho que permite implementar
   servidores COM en proceso con ctypes. Se llama desde la función
   DllGetClassObject que la extensión "_ctypes" exporta.

ctypes.util.find_library(name)

   Intenta encontrar una biblioteca y retornar un nombre de ruta.
   *name* es el nombre de la biblioteca sin ningún prefijo como "lib",
   sufijo como ".so", ".dylib" o número de versión (esta es la forma
   usada para la opción del enlazador posix "-l"). Si no se puede
   encontrar ninguna biblioteca, retorna "None".

   La funcionalidad exacta depende del sistema.

ctypes.util.find_msvcrt()

   Sólo Windows: retorna el nombre de archivo de la biblioteca de
   tiempo de ejecución de VC usada por Python, y por los módulos de
   extensión. Si no se puede determinar el nombre de la biblioteca, se
   retorna "None".

   Si necesita liberar memoria, por ejemplo, asignada por un módulo de
   extensión con una llamada al "free(void *)", es importante que
   utilice la función en la misma biblioteca que asignó la memoria.

ctypes.FormatError([code])

   Sólo Windows: retorna una descripción textual del código de error
   *code*. Si no se especifica ningún código de error, se utiliza el
   último código de error llamando a la función de api de Windows
   GetLastError.

ctypes.GetLastError()

   Sólo Windows: retorna el último código de error establecido por
   Windows en el hilo de llamada. Esta función llama directamente a la
   función *GetLastError()* de Windows, no retorna la copia ctypes-
   private del código de error.

ctypes.get_errno()

   Retorna el valor actual de la copia ctypes-private de la variable
   de sistema "errno" en el hilo de llamada.

   Lanza un auditing event "ctypes.get_errno" sin argumentos.

ctypes.get_last_error()

   Sólo Windows: retorna el valor actual de la copia ctypes-private de
   la variable de sistema "LastError" en el hilo de llamada.

   Lanza un auditing event "ctypes.get_last_error" sin argumentos.

ctypes.memmove(dst, src, count)

   Igual que la función de la biblioteca estándar  de C *memmove*:
   copia *count* bytes de *src* a *dst*. *dst* y *src* deben ser
   enteros o instancias ctypes que pueden ser convertidos en punteros.

ctypes.memset(dst, c, count)

   Igual que la función de la biblioteca estándar de C *memset* C:
   llena el bloque de memoria en la dirección *dst* con *count* bytes
   de valor *c*. *dst* debe ser un número entero que especifique una
   dirección, o una instancia ctypes.

ctypes.POINTER(type)

   Esta función de fábrica crea y retorna un nuevo tipo de puntero
   ctypes. Los tipos de puntero se almacenan en caché y se reutilizan
   internamente, por lo que llamar a esta función repetidamente es
   barato. *type* debe ser un tipo ctypes.

ctypes.pointer(obj)

   Esta función crea una nueva instancia de puntero, apuntando a
   *obj*. El objeto retornado es del tipo "POINTER(tipo(obj))".

   Nota: Si sólo quieres pasar un puntero a un objeto a una llamada de
   función foránea, deberías usar "byref(obj)" que es mucho más
   rápido.

ctypes.resize(obj, size)

   Esta función redimensiona el búfer de memoria interna de *obj*, que
   debe ser una instancia de tipo ctypes. No es posible hacer el
   buffer más pequeño que el tamaño nativo del tipo de objetos, como
   lo indica "size of (type(obj))", pero es posible agrandar el
   buffer.

ctypes.set_errno(value)

   Poner el valor actual de la copia ctypes-private de la variable del
   sistema "errno" en el hilo de llamada a *valor* y retornar el valor
   anterior.

   Lanza un auditing event "ctypes.set_errno" con argumento "errno".

ctypes.set_last_error(value)

   Sólo para Windows: pone el valor actual de la copia ctypes-private
   de la variable del sistema "LastError" en el hilo de llamada a
   *valor* y retorna el valor anterior.

   Lanza un auditing event "ctypes.set_last_error" con argumento
   "error".

ctypes.sizeof(obj_or_type)

   Retorna el tamaño en bytes de un buffer de memoria tipo ctypes o
   instancia. Hace lo mismo que el operador C "sizeof".

ctypes.string_at(address, size=-1)

   Esta función retorna la cadena C que comienza en la dirección de
   memoria *address* como un objeto de bytes. Si se especifica el
   tamaño, se utiliza como tamaño, de lo contrario se asume que la
   cadena tiene un final cero.

   Lanza un auditing event "ctypes.string_at" con argumentos
   "address", "size".

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

   Sólo para Windows: esta función es probablemente la cosa peor
   nombrada de los ctypes. Crea una instancia de OSError. Si no se
   especifica el *code*, se llama a "GetLastError" para determinar el
   código de error. Si no se especifica *descr*, se llama a
   "FormatError`()" para obtener una descripción textual del error.

   Distinto en la versión 3.3: Una instancia de "WindowsError" solía
   ser creada.

ctypes.wstring_at(address, size=-1)

   Esta función retorna la cadena de caracteres anchos que comienza en
   la dirección de memoria *address* como una cadena. Si se especifica
   *size*, se utiliza como el número de caracteres de la cadena, de lo
   contrario se asume que la cadena tiene un final cero.

   Lanza un auditing event "ctypes.wstring_at" con argumentos
   "address", "size".


Tipos de datos
--------------

class ctypes._CData

   Esta clase no pública es la clase de base común de todos los tipos
   de datos de los ctypes. Entre otras cosas, todas las instancias de
   tipo ctypes contienen un bloque de memoria que contiene datos
   compatibles con C; la dirección del bloque de memoria es retornada
   por la función de ayuda "addressof()". Otra variable de instancia
   se expone como "_objetos"; ésta contiene otros objetos de Python
   que deben mantenerse vivos en caso de que el bloque de memoria
   contenga punteros.

   Métodos comunes de tipos de datos ctypes, estos son todos métodos
   de clase (para ser exactos, son métodos del *metaclass*):

   from_buffer(source[, offset])

      Este método retorna una instancia ctypes que comparte el buffer
      del objeto *source*. El objeto *source* debe soportar la
      interfaz del buffer de escritura. El parámetro opcional *offset*
      especifica un offset en el buffer de la fuente en bytes; el
      valor por defecto es cero. Si el buffer de la fuente no es lo
      suficientemente grande se lanza un "ValueError".

      Lanza un auditing event "ctypes.cdata/buffer" con argumentos
      "pointer", "size", "offset".

   from_buffer_copy(source[, offset])

      Este método crea una instancia ctypes, copiando el buffer del
      buffer de objetos *source* que debe ser legible. El parámetro
      opcional *offset* especifica un offset en el buffer de origen en
      bytes; el valor por defecto es cero. Si el buffer de fuente no
      es lo suficientemente grande se lanza un "ValueError".

      Lanza un auditing event "ctypes.cdata/buffer" con argumentos
      "pointer", "size", "offset".

   from_address(address)

      Este método retorna una instancia de tipo ctypes utilizando la
      memoria especificada por *address* que debe ser un entero.

      Lanza un auditing event "ctypes.cdata" con argumento "address".

   from_param(obj)

      Este método adapta el *obj* a un tipo de ctypes. Se llama con el
      objeto real usado en una llamada a una función externa cuando el
      tipo está presente en la tupla "argtypes" de la función foránea;
      debe retornar un objeto que pueda ser usado como parámetro de
      llamada a la función.

      Todos los tipos de datos ctypes tienen una implementación por
      defecto de este método de clase que normalmente retorna *obj* si
      es una instancia del tipo. Algunos tipos aceptan también otros
      objetos.

   in_dll(library, name)

      Este método retorna una instancia de tipo ctypes exportada por
      una biblioteca compartida. *name* es el nombre del símbolo que
      exporta los datos, *library* es la biblioteca compartida
      cargada.

   Variables de instancia común de los tipos de datos de ctypes:

   _b_base_

      A veces, las instancias de datos ctypes no poseen el bloque de
      memoria que contienen, sino que comparten parte del bloque de
      memoria de un objeto base. El miembro de sólo lectura "_b_base_"
      es el objeto raíz ctypes que posee el bloque de memoria.

   _b_needsfree_

      Esta variable de sólo lectura es verdadera cuando la instancia
      de datos ctypes ha sido asignada a el propio bloque de memoria,
      falsa en caso contrario.

   _objects

      Este miembro es "None" o un diccionario que contiene objetos de
      Python que deben mantenerse vivos para que el contenido del
      bloque de memoria sea válido. Este objeto sólo se expone para su
      depuración; nunca modifique el contenido de este diccionario.


Tipos de datos fundamentales
----------------------------

class ctypes._SimpleCData

   Esta clase no pública es la clase base de todos los tipos de datos
   de ctypes fundamentales. Se menciona aquí porque contiene los
   atributos comunes de los tipos de datos de ctypes fundamentales.
   "_SimpleCData" es una subclase de "_CData", por lo que hereda sus
   métodos y atributos. Los tipos de datos ctypes que no son y no
   contienen punteros ahora pueden ser archivados.

   Los instancias tienen un solo atributo:

   value

      Este atributo contiene el valor real de la instancia. Para los
      tipos enteros y punteros, es un entero, para los tipos de
      caracteres, es un objeto o cadena de bytes de un solo carácter,
      para los tipos de punteros de caracteres es un objeto o cadena
      de bytes de Python.

      Cuando el atributo "value" se recupera de una instancia ctypes,
      normalmente se retorna un nuevo objeto cada vez. "ctypes" *no*
      implementa el retorno del objeto original, siempre se construye
      un nuevo objeto. Lo mismo ocurre con todas las demás instancias
      de objetos ctypes.

Los tipos de datos fundamentales, cuando se retornan como resultados
de llamadas de funciones foráneas, o, por ejemplo, al recuperar
miembros de campo de estructura o elementos de arreglos, se convierten
de forma transparente a tipos nativos de Python. En otras palabras, si
una función externa tiene un "restype" de "c_char_p", siempre recibirá
un objeto de bytes Python, *no* una instancia de "c_char_p".

Las subclases de los tipos de datos fundamentales *no* heredan este
comportamiento. Así, si una función externa "restype" es una subclase
de "c_void_p", recibirás una instancia de esta subclase desde la
llamada a la función. Por supuesto, puedes obtener el valor del
puntero accediendo al atributo "value".

Estos son los tipos de datos fundamentales de ctypes:

class ctypes.c_byte

   Representa el tipo de datos C "signed char", e interpreta el valor
   como un entero pequeño. El constructor acepta un inicializador de
   entero opcional; no se hace ninguna comprobación de desbordamiento.

class ctypes.c_char

   Representa el tipo de datos C "char", e interpreta el valor como un
   solo carácter. El constructor acepta un inicializador de cadena
   opcional, la longitud de la cadena debe ser exactamente un
   carácter.

class ctypes.c_char_p

   Representa el tipo de datos C "char *" cuando apunta a una cadena
   terminada en cero. Para un puntero de carácter general que también
   puede apuntar a datos binarios, se debe usar "POINTER(c_char)". El
   constructor acepta una dirección entera, o un objeto de bytes.

class ctypes.c_double

   Representa el tipo de datos C "double". El constructor acepta un
   inicializador flotante opcional.

class ctypes.c_longdouble

   Representa el tipo de datos C "long double". El constructor acepta
   un inicializador flotante opcional. En las plataformas donde
   "sizeof(long double) == sizeof(double)" es un alias de "c_double".

class ctypes.c_float

   Representa el tipo de datos C "float". El constructor acepta un
   inicializador flotante opcional.

class ctypes.c_int

   Representa el tipo de datos C "signed int". El constructor acepta
   un inicializador entero opcional; no se hace ninguna comprobación
   de desbordamiento. En plataformas donde "sizeof(int) ==
   sizeof(long)" es un alias de "c_long".

class ctypes.c_int8

   Representa el tipo de datos C 8-bit "signed int". Normalmente un
   alias para "c_byte".

class ctypes.c_int16

   Representa el tipo de datos C 16-bit "signed int". Normalmente un
   alias para "c_short".

class ctypes.c_int32

   Representa el tipo de datos C 32-bit "signed int". Normalmente un
   alias para "c_int".

class ctypes.c_int64

   Representa el tipo de datos C 64-bit "signed int". Normalmente un
   alias para "c_longlong".

class ctypes.c_long

   Representa el tipo de datos C "signed long". El constructor acepta
   un inicializador entero opcional; no se hace ninguna comprobación
   de desbordamiento.

class ctypes.c_longlong

   Representa el tipo de datos C "significado long long". El
   constructor acepta un inicializador entero opcional; no se hace
   ninguna comprobación de desbordamiento.

class ctypes.c_short

   Representa el tipo de datos C "signed short". El constructor acepta
   un inicializador entero opcional; no se hace ninguna comprobación
   de desbordamiento.

class ctypes.c_size_t

   Representa el tipo de datos C "size_t".

class ctypes.c_ssize_t

   Representa el tipo de datos C "ssize_t".

   Nuevo en la versión 3.2.

class ctypes.c_ubyte

   Representa el tipo de datos C "unsigned char", interpreta el valor
   como un entero pequeño. El constructor acepta un inicializador
   entero opcional; no se hace ninguna comprobación de desbordamiento.

class ctypes.c_uint

   Representa el tipo de datos C "unsigned int". El constructor acepta
   un inicializador entero opcional; no se hace ninguna comprobación
   de desbordamiento. En plataformas donde "sizeof(int) ==
   sizeof(long)" es un alias para "c_ulong".

class ctypes.c_uint8

   Representa el tipo de datos C 8-bit "unsigned int". Normalmente un
   alias para "c_ubyte".

class ctypes.c_uint16

   Representa el tipo de datos C 16-bit "unsigned int". Normalmente un
   alias para "c_ushort".

class ctypes.c_uint32

   Representa el tipo de datos C 32-bit "unsigned int". Normalmente un
   alias para "c_uint".

class ctypes.c_uint64

   Representa el tipo de datos C 64-bit "unsigned int". Normalmente un
   alias para "c_ulonglong".

class ctypes.c_ulong

   Representa el tipo de datos C "unsigned long". El constructor
   acepta un inicializador entero opcional; no se hace ninguna
   comprobación de desbordamiento.

class ctypes.c_ulonglong

   Representa el tipo de datos C "unsigned long long". El constructor
   acepta un inicializador entero opcional; no se hace ninguna
   comprobación de desbordamiento.

class ctypes.c_ushort

   Representa el tipo de datos C "unsigned short". El constructor
   acepta un inicializador entero opcional; no se hace ninguna
   comprobación de desbordamiento.

class ctypes.c_void_p

   Representa el tipo C "void *". El valor se representa como un
   entero. El constructor acepta un inicializador entero opcional.

class ctypes.c_wchar

   Representa el tipo de datos C "wchar_t", e interpreta el valor como
   una cadena unicode de un solo carácter. El constructor acepta un
   inicializador de cadena opcional, la longitud de la cadena debe ser
   exactamente de un carácter.

class ctypes.c_wchar_p

   Representa el tipo de datos C "wchar_t *", que debe ser un puntero
   a una cadena de caracteres anchos con terminación cero. El
   constructor acepta una dirección entera, o una cadena.

class ctypes.c_bool

   Representa el tipo de datos C "bool" (más exactamente, "_Bool" de
   C99). Su valor puede ser "True" o "False", y el constructor acepta
   cualquier objeto que tenga un valor verdadero.

class ctypes.HRESULT

   Sólo Windows: Representa un valor "HRESULT" , que contiene
   información de éxito o error para una llamada de función o método.

class ctypes.py_object

   Representa el tipo de datos C "PyObject *". Llamar esto sin un
   argumento crea un puntero "NULL" "PyObject *".

El módulo "ctypes.wintypes" proporciona otros tipos de datos
específicos de Windows, por ejemplo "HWND", "WPARAM", o "DWORD".
Algunas estructuras útiles como "MSG" o "RECT" también están
definidas.


Tipos de datos estructurados
----------------------------

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

   Clase base abstracta para uniones en orden de bytes nativos.

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

   Clase base abstracta para estructuras en orden de bytes *big
   endian*.

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

   Clase base abstracta para estructuras en orden de bytes *little
   endian*.

Las estructuras con un orden de bytes no nativo no pueden contener
campos de tipo puntero, o cualquier otro tipo de datos que contenga
campos de tipo puntero.

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

   Clase base abstracta para estructuras en orden de bytes *native*.

   La estructura concreta y los tipos de unión deben crearse
   subclasificando uno de estos tipos, y al menos definir una variable
   de clase "_fields_". "ctypes" creará *descriptor*s que permitan
   leer y escribir los campos por accesos directos de atributos. Estos
   son los

   _fields_

      Una secuencia que define los campos de estructura. Los elementos
      deben ser de 2 o 3 tuplas. El primer ítem es el nombre del
      campo, el segundo ítem especifica el tipo de campo; puede ser
      cualquier tipo de datos ctypes.

      Para los campos de tipo entero como "c_int", se puede dar un
      tercer elemento opcional. Debe ser un pequeño entero positivo
      que defina el ancho de bit del campo.

      Los nombres de los campos deben ser únicos dentro de una
      estructura o unión. Esto no se comprueba, sólo se puede acceder
      a un campo cuando los nombres se repiten.

      Es posible definir la variable de clase "_fields_" *después* de
      la sentencia de clase que define la subclase Estructura, esto
      permite crear tipos de datos que se refieren directa o
      indirectamente a sí mismos:

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

      Sin embargo, la variable de clase "_fields_" debe ser definida
      antes de que el tipo sea usado por primera vez (se crea una
      instancia, se llama a "sizeof()", y así sucesivamente). Las
      asignaciones posteriores a la variable de clase "_fields_"
      lanzarán un AttributeError.

      Es posible definir subclases de tipos de estructura, que heredan
      los campos de la clase base más el "_fields_" definido en la
      subclase, si existe.

   _pack_

      Un pequeño entero opcional que permite anular la alineación de
      los campos de estructura en la instancia. "_pack_" ya debe estar
      definido cuando se asigna "_fields_", de lo contrario no tendrá
      ningún efecto.

   _anonymous_

      Una secuencia opcional que enumera los nombres de los campos sin
      nombre (anónimos). "_anonymous_" debe estar ya definida cuando
      se asigna "_fields_", de lo contrario no tendrá ningún efecto.

      Los campos listados en esta variable deben ser campos de tipo
      estructura o unión. "ctypes" creará descriptores en el tipo de
      estructura que permitan acceder a los campos anidados
      directamente, sin necesidad de crear el campo de estructura o
      unión.

      Aquí hay un tipo de ejemplo (Windows):

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

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

      La estructura "TYPEDESC" describe un tipo de datos COM, el campo
      "vt" especifica cuál de los campos de unión es válido. Como el
      campo "u" está definido como campo anónimo, ahora es posible
      acceder a los miembros directamente desde la instancia TYPEDESC.
      "td.lptdesc" y "td.u.lptdesc" son equivalentes, pero el primero
      es más rápido ya que no necesita crear una instancia de unión
      temporal:

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

   Es posible definir subclases de estructuras, que heredan los campos
   de la clase base. Si la definición de la subclase tiene una
   variable "_fields_" separada, los campos especificados en ella se
   añaden a los campos de la clase base.

   Los constructores de estructuras y uniones aceptan tanto argumentos
   posicionales como de palabras clave. Los argumentos posicionales se
   usan para inicializar los campos de los miembros en el mismo orden
   en que aparecen en "_fields_". Los argumentos de palabras clave en
   el constructor se interpretan como asignaciones de atributos, por
   lo que inicializarán "_fields_" con el mismo nombre, o crearán
   nuevos atributos para nombres no presentes en "_fields_".


Arreglos y punteros
-------------------

class ctypes.Array(*args)

   Clase base abstracta para arreglos.

   The recommended way to create concrete array types is by
   multiplying any "ctypes" data type with a non-negative integer.
   Alternatively, you can subclass this type and define "_length_" and
   "_type_" class variables. Array elements can be read and written
   using standard subscript and slice accesses; for slice reads, the
   resulting object is *not* itself an "Array".

   _length_

      Un número entero positivo que especifica el número de elementos
      del conjunto. Los subíndices fuera de rango dan como resultado
      un "IndexError". Será retornado por "len()".

   _type_

      Especifica el tipo de cada elemento del arreglo.

   Los constructores de subclases de arreglos aceptan argumentos
   posicionales, usados para inicializar los elementos en orden.

class ctypes._Pointer

   Clase base, privada y abstracta para punteros.

   Los tipos de punteros concretos se crean llamando a "POINTER()" con
   el tipo que será apuntado; esto se hace automáticamente por
   "pointer()".

   Si un puntero apunta a un arreglo, sus elementos pueden ser leídos
   y escritos usando accesos de subíndices y cortes estándar. Los
   objetos punteros no tienen tamaño, así que "len()" lanzará un
   "TypeError". Los subíndices negativos se leerán de la memoria
   *antes* que el puntero (como en C), y los subíndices fuera de rango
   probablemente se bloqueen con una violación de acceso (si tienes
   suerte).

   _type_

      Especifica el tipo apuntado.

   contents

      Retorna el objeto al que el puntero apunta. Asignando a este
      atributo cambia el puntero para que apunte al objeto asignado.
