ctypes
--- Python 用の外部関数ライブラリ¶
ソースコード: Lib/ctypes
ctypes
は Python のための外部関数ライブラリです。このライブラリは C と互換性のあるデータ型を提供し、動的リンク/共有ライブラリ内の関数呼び出しを可能にします。動的リンク/共有ライブラリを純粋な Python でラップするために使うことができます。
ctypes チュートリアル¶
注意: このチュートリアルのコードサンプルは動作確認のために doctest
を使います。コードサンプルの中には Linux、 Windows、あるいは macOS 上で異なる動作をするものがあるため、サンプルのコメントに doctest 命令を入れてあります。
注意: いくつかのコードサンプルで ctypes の c_int
型を参照しています。 sizeof(long) == sizeof(int)
であるようなプラットフォームでは、この型は c_long
のエイリアスです。そのため、 c_int
型を想定しているときに c_long
が表示されたとしても、混乱しないようにしてください --- 実際には同じ型なのです。
動的リンクライブラリをロードする¶
動的リンクライブラリをロードするために、 ctypes
は cdll をエクスポートします。 Windows では windll と oledll オブジェクトをエクスポートします。
You load libraries by accessing them as attributes of these objects. cdll
loads libraries which export functions using the standard cdecl
calling
convention, while windll libraries call functions using the stdcall
calling convention. oledll also uses the stdcall
calling convention, and
assumes the functions return a Windows HRESULT
error code. The error
code is used to automatically raise an OSError
exception when the
function call fails.
バージョン 3.3 で変更: Windows エラーは以前は WindowsError
を送出していましたが、これは現在では OSError
の別名になっています。
Here are some examples for Windows. Note that msvcrt
is the MS standard C
library containing most standard C functions, and uses the cdecl
calling
convention:
>>> from ctypes import *
>>> print(windll.kernel32)
<WinDLL 'kernel32', handle ... at ...>
>>> print(cdll.msvcrt)
<CDLL 'msvcrt', handle ... at ...>
>>> libc = cdll.msvcrt
>>>
Windows では通常の .dll
ファイル拡張子を自動的に追加します。
注釈
cdll.msvcrt
経由で標準 C ライブラリにアクセスすると、Python が使用しているライブラリとは互換性のない可能性のある、古いバージョンのライブラリが使用されます。可能な場合には、ネイティブ Python の機能を使用するか、msvcrt
モジュールをインポートして使用してください。
On Linux, it is required to specify the filename including the extension to
load a library, so attribute access can not be used to load libraries. Either the
LoadLibrary()
method of the dll loaders should be used,
or you should load the library by creating an instance of CDLL by calling
the constructor:
>>> cdll.LoadLibrary("libc.so.6")
<CDLL 'libc.so.6', handle ... at ...>
>>> libc = CDLL("libc.so.6")
>>> libc
<CDLL 'libc.so.6', handle ... at ...>
>>>
ロードしたdllから関数にアクセスする¶
dll オブジェクトの属性として関数にアクセスします:
>>> libc.printf
<_FuncPtr object at 0x...>
>>> print(windll.kernel32.GetModuleHandleA)
<_FuncPtr object at 0x...>
>>> print(windll.kernel32.MyOwnFunction)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "ctypes.py", line 239, in __getattr__
func = _StdcallFuncPtr(name, self)
AttributeError: function 'MyOwnFunction' not found
>>>
Note that win32 system dlls like kernel32
and user32
often export ANSI
as well as UNICODE versions of a function. The UNICODE version is exported with
a W
appended to the name, while the ANSI version is exported with an A
appended to the name. The win32 GetModuleHandle
function, which returns a
module handle for a given module name, has the following C prototype, and a
macro is used to expose one of them as GetModuleHandle
depending on whether
UNICODE is defined or not:
/* ANSI version */
HMODULE GetModuleHandleA(LPCSTR lpModuleName);
/* UNICODE version */
HMODULE GetModuleHandleW(LPCWSTR lpModuleName);
windll は魔法を使ってどちらか一つを選ぶようなことはしません。GetModuleHandleA
もしくは GetModuleHandleW
を明示的に指定して必要とするバージョンにアクセスし、バイト列か文字列を使ってそれぞれ呼び出さなければなりません。
時には、 dll が関数を "??2@YAPAXI@Z"
のような Python 識別子として有効でない名前でエクスポートすることがあります。このような場合に関数を取り出すには、 getattr()
を使わなければなりません。:
>>> getattr(cdll.msvcrt, "??2@YAPAXI@Z")
<_FuncPtr object at 0x...>
>>>
Windows では、名前ではなく序数によって関数をエクスポートする dll もあります。こうした関数には序数を使って dll オブジェクトにインデックス指定することでアクセスします:
>>> cdll.kernel32[1]
<_FuncPtr object at 0x...>
>>> cdll.kernel32[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "ctypes.py", line 310, in __getitem__
func = _StdcallFuncPtr(name, self)
AttributeError: function ordinal 0 not found
>>>
関数を呼び出す¶
You can call these functions like any other Python callable. This example uses
the rand()
function, which takes no arguments and returns a pseudo-random integer:
>>> print(libc.rand())
1804289383
On Windows, you can call the GetModuleHandleA()
function, which returns a win32 module
handle (passing None
as single argument to call it with a NULL
pointer):
>>> print(hex(windll.kernel32.GetModuleHandleA(None)))
0x1d000000
>>>
cdecl
呼び出し規約を使って stdcall
関数を呼び出したときには、 ValueError
が送出されます。逆の場合も同様です:
>>> cdll.kernel32.GetModuleHandleA(None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Procedure probably called with not enough arguments (4 bytes missing)
>>>
>>> windll.msvcrt.printf(b"spam")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Procedure probably called with too many arguments (4 bytes in excess)
>>>
正しい呼び出し規約を知るためには、呼び出したい関数についての C ヘッダファイルもしくはドキュメントを見なければなりません。
Windows では、関数が無効な引数とともに呼び出された場合の一般保護例外によるクラッシュを防ぐために、 ctypes
は win32 構造化例外処理を使います:
>>> windll.kernel32.GetModuleHandleA(32)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: exception: access violation reading 0x00000020
>>>
しかしそれでも他に ctypes
で Python がクラッシュする状況はあるので、どちらにせよ気を配るべきです。クラッシュのデバッグには、 faulthandler
モジュールが役に立つ場合があります (例えば、誤った C ライブラリ呼び出しによって引き起こされたセグメンテーション違反) 。
None
, integers, bytes objects and (unicode) strings are the only native
Python objects that can directly be used as parameters in these function calls.
None
is passed as a C NULL
pointer, bytes objects and strings are passed
as pointer to the memory block that contains their data (char* or
wchar_t*). Python integers are passed as the platforms default C
int type, their value is masked to fit into the C type.
他のパラメータ型をもつ関数呼び出しに移る前に、 ctypes
データ型についてさらに学ぶ必要があります。
基本データ型¶
ctypes
ではいくつもの C 互換のプリミティブなデータ型を定義しています:
ctypes の型 |
C の型 |
Python の型 |
---|---|---|
_Bool |
bool (1) |
|
char |
1文字のバイト列オブジェクト |
|
|
1文字の文字列 |
|
char |
int |
|
unsigned char |
int |
|
short |
int |
|
unsigned short |
int |
|
int |
int |
|
unsigned int |
int |
|
long |
int |
|
unsigned long |
int |
|
__int64 または long long |
int |
|
unsigned __int64 または unsigned long long |
int |
|
|
int |
|
|
int |
|
|
int |
|
float |
浮動小数点数 |
|
double |
浮動小数点数 |
|
long double |
浮動小数点数 |
|
char* (NUL 終端) |
バイト列オブジェクトまたは |
|
wchar_t* (NUL 終端) |
文字列または |
|
void* |
整数または |
コンストラクタは任意のオブジェクトをその真偽値として受け取ります。
これら全ての型はその型を呼び出すことによって作成でき、オプションとして型と値が合っている初期化子を指定することができます:
>>> c_int()
c_long(0)
>>> c_wchar_p("Hello, World")
c_wchar_p(140018365411392)
>>> c_ushort(-3)
c_ushort(65533)
>>>
これらの型は変更可能であり、値を後で変更することもできます:
>>> i = c_int(42)
>>> print(i)
c_long(42)
>>> print(i.value)
42
>>> i.value = -99
>>> print(i.value)
-99
>>>
新しい値をポインタ型 c_char_p
, c_wchar_p
および c_void_p
のインスタンスへ代入すると、変わるのは指している メモリ位置 であって、メモリブロックの 内容ではありません (これは当然で、なぜなら、 Python バイト列オブジェクトは変更不可能だからです):
>>> 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
>>>
しかし、変更可能なメモリを指すポインタであることを想定している関数へそれらを渡さないように注意すべきです。もし変更可能なメモリブロックが必要なら、 ctypes には create_string_buffer()
関数があり、いろいろな方法で作成することできます。現在のメモリブロックの内容は raw
プロパティを使ってアクセス (あるいは変更) することができます。もし現在のメモリブロックに NUL 終端文字列としてアクセスしたいなら、 value
プロパティを使ってください:
>>> from ctypes import *
>>> p = create_string_buffer(3) # create a 3 byte buffer, initialized to NUL bytes
>>> print(sizeof(p), repr(p.raw))
3 b'\x00\x00\x00'
>>> p = create_string_buffer(b"Hello") # create a buffer containing a NUL terminated string
>>> print(sizeof(p), repr(p.raw))
6 b'Hello\x00'
>>> print(repr(p.value))
b'Hello'
>>> p = create_string_buffer(b"Hello", 10) # create a 10 byte buffer
>>> print(sizeof(p), repr(p.raw))
10 b'Hello\x00\x00\x00\x00\x00'
>>> p.value = b"Hi"
>>> print(sizeof(p), repr(p.raw))
10 b'Hi\x00lo\x00\x00\x00\x00\x00'
>>>
The create_string_buffer()
function replaces the old c_buffer()
function (which is still available as an alias). To create a mutable memory
block containing unicode characters of the C type wchar_t
, use the
create_unicode_buffer()
function.
続・関数を呼び出す¶
printf は sys.stdout
では なく 、本物の標準出力チャンネルへプリントすることに注意してください。したがって、これらの例はコンソールプロンプトでのみ動作し、 IDLE や 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: TypeError: Don't know how to convert parameter 2
>>>
前に述べたように、必要な C のデータ型へ変換できるようにするためには、整数、文字列およびバイト列オブジェクトを除くすべての Python 型を対応する ctypes
型でラップしなければなりません:
>>> printf(b"An int %d, a double %f\n", 1234, c_double(3.14))
An int 1234, a double 3.140000
31
>>>
Calling variadic functions¶
On a lot of platforms calling variadic functions through ctypes is exactly the same as calling functions with a fixed number of parameters. On some platforms, and in particular ARM64 for Apple Platforms, the calling convention for variadic functions is different than that for regular functions.
On those platforms it is required to specify the argtypes
attribute for the regular, non-variadic, function arguments:
libc.printf.argtypes = [ctypes.c_char_p]
Because specifying the attribute does not inhibit portability it is advised to always
specify argtypes
for all variadic functions.
自作のデータ型とともに関数を呼び出す¶
You can also customize ctypes
argument conversion to allow instances of
your own classes be used as function arguments. ctypes
looks for an
_as_parameter_
attribute and uses this as the function argument. The
attribute must be an integer, string, bytes, a ctypes
instance, or an
object with an _as_parameter_
attribute:
>>> class Bottles:
... def __init__(self, number):
... self._as_parameter_ = number
...
>>> bottles = Bottles(42)
>>> printf(b"%d bottles of beer\n", bottles)
42 bottles of beer
19
>>>
If you don't want to store the instance's data in the _as_parameter_
instance variable, you could define a property
which makes the
attribute available on request.
要求される引数の型を指定する (関数プロトタイプ)¶
It is possible to specify the required argument types of functions exported from
DLLs by setting the argtypes
attribute.
argtypes
must be a sequence of C data types (the printf()
function is
probably not a good example here, because it takes a variable number and
different types of parameters depending on the format string, on the other hand
this is quite handy to experiment with this feature):
>>> 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
>>>
(C の関数のプロトタイプのように) 書式を指定すると互換性のない引数型になるのを防ぎ、引数を有効な型へ変換しようとします。:
>>> printf(b"%d %d %d", 1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ArgumentError: argument 2: TypeError: wrong type
>>> printf(b"%s %d %f\n", b"X", 2, 3)
X 2 3.000000
13
>>>
If you have defined your own classes which you pass to function calls, you have
to implement a from_param()
class method for them to be able to use them
in the argtypes
sequence. The from_param()
class method receives
the Python object passed to the function call, it should do a typecheck or
whatever is needed to make sure this object is acceptable, and then return the
object itself, its _as_parameter_
attribute, or whatever you want to
pass as the C function argument in this case. Again, the result should be an
integer, string, bytes, a ctypes
instance, or an object with an
_as_parameter_
attribute.
戻り値の型¶
By default functions are assumed to return the C int type. Other
return types can be specified by setting the restype
attribute of the
function object.
The C prototype of time()
is time_t time(time_t *)
. Because time_t
might be of a different type than the default return type int, you should
specify the restype
attribute:
>>> libc.time.restype = c_time_t
The argument types can be specified using argtypes
:
>>> libc.time.argtypes = (POINTER(c_time_t),)
To call the function with a NULL
pointer as first argument, use None
:
>>> print(libc.time(None))
1150640792
Here is a more advanced example, it uses the strchr()
function, which expects
a string pointer and a char, and returns a pointer to a string:
>>> strchr = libc.strchr
>>> strchr(b"abcdef", ord("d"))
8059983
>>> strchr.restype = c_char_p # c_char_p is a pointer to a string
>>> strchr(b"abcdef", ord("d"))
b'def'
>>> print(strchr(b"abcdef", ord("x")))
None
>>>
If you want to avoid the ord("x")
calls above, you can set the
argtypes
attribute, and the second argument will be converted from a
single character Python bytes object into a C char:
>>> strchr.restype = c_char_p
>>> strchr.argtypes = [c_char_p, c_char]
>>> strchr(b"abcdef", b"d")
b'def'
>>> strchr(b"abcdef", b"def")
Traceback (most recent call last):
ctypes.ArgumentError: argument 2: TypeError: one character bytes, bytearray or integer expected
>>> print(strchr(b"abcdef", b"x"))
None
>>> strchr(b"abcdef", b"d")
b'def'
>>>
You can also use a callable Python object (a function or a class for example) as
the restype
attribute, if the foreign function returns an integer. The
callable will be called with the integer the C function returns, and the
result of this call will be used as the result of your function call. This is
useful to check for error return values and automatically raise an exception:
>>> GetModuleHandle = windll.kernel32.GetModuleHandleA
>>> def ValidHandle(value):
... if value == 0:
... raise WinError()
... return value
...
>>>
>>> GetModuleHandle.restype = ValidHandle
>>> GetModuleHandle(None)
486539264
>>> GetModuleHandle("something silly")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in ValidHandle
OSError: [Errno 126] The specified module could not be found.
>>>
WinError
はエラーコードの文字列表現を得るために Windows の FormatMessage()
api を呼び出し、例外を 返す 関数です。 WinError
はオプションでエラーコードパラメータを取ります。このパラメータが使われない場合は、エラーコードを取り出すために GetLastError()
を呼び出します。
Please note that a much more powerful error checking mechanism is available
through the errcheck
attribute;
see the reference manual for details.
ポインタを渡す(または、パラメータの参照渡し)¶
時には、 C api 関数がパラメータのデータ型として ポインタ を想定していることがあります。おそらくパラメータと同一の場所に書き込むためか、もしくはそのデータが大きすぎて値渡しできない場合です。これは パラメータの参照渡し としても知られています。
ctypes
は byref()
関数をエクスポートしており、パラメータを参照渡しするために使用します。 pointer()
関数を使っても同じ効果が得られます。しかし、 pointer()
は本当のポインタオブジェクトを構築するためより多くの処理を行うことから、 Python 側でポインタオブジェクト自体を必要としないならば byref()
を使う方がより高速です。:
>>> i = c_int()
>>> f = c_float()
>>> s = create_string_buffer(b'\000' * 32)
>>> print(i.value, f.value, repr(s.value))
0 0.0 b''
>>> libc.sscanf(b"1 3.14 Hello", b"%d %f %s",
... byref(i), byref(f), s)
3
>>> print(i.value, f.value, repr(s.value))
1 3.1400001049 b'Hello'
>>>
構造体と共用体¶
Structures and unions must derive from the Structure
and Union
base classes which are defined in the ctypes
module. Each subclass must
define a _fields_
attribute. _fields_
must be a list of
2-tuples, containing a field name and a field type.
フィールド型は c_int
か他の ctypes
型 (構造体、共用体、配列、ポインタ) から派生した ctypes
型である必要があります。
以下は、 x と y という名前の二つの整数からなる簡単な POINT 構造体の例です。コンストラクタで構造体を初期化する方法も説明しています:
>>> 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
>>>
しかし、もっと複雑な構造体を構築することもできます。ある構造体は、他の構造体をフィールド型として使うことで、他の構造体を含むことができます。
upperleft と lowerright という名前の二つの POINT を持つ RECT 構造体です。:
>>> 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
>>>
入れ子になった構造体はいくつかの方法を用いてコンストラクタで初期化することができます。:
>>> r = RECT(POINT(1, 2), POINT(3, 4))
>>> r = RECT((1, 2), (3, 4))
フィールド descriptor (記述子)は クラス から取り出せます。デバッグするときに役に立つ情報を得ることができます:
>>> print(POINT.x)
<Field type=c_long, ofs=0, size=4>
>>> print(POINT.y)
<Field type=c_long, ofs=4, size=4>
>>>
警告
ctypes
では、ビットフィールドのある共用体や構造体の関数への値渡しはサポートしていません。これは 32-bit の x86 環境では動くかもしれませんが、このライブラリでは一般の場合に動作することは保証していません。
構造体/共用体アライメントとバイトオーダー¶
By default, Structure and Union fields are aligned in the same way the C
compiler does it. It is possible to override this behavior by specifying a
_pack_
class attribute in the subclass definition.
This must be set to a positive integer and specifies the maximum alignment for the fields.
This is what #pragma pack(n)
also does in MSVC.
ctypes
は Structure と Union に対してネイティブのバイトオーダーを使います。ネイティブではないバイトオーダーの構造体を作成するには、 BigEndianStructure
, LittleEndianStructure
, BigEndianUnion
および LittleEndianUnion
ベースクラスの中の一つを使います。これらのクラスにポインタフィールドを持たせることはできません。
構造体と共用体におけるビットフィールド¶
It is possible to create structures and unions containing bit fields. Bit fields
are only possible for integer fields, the bit width is specified as the third
item in the _fields_
tuples:
>>> 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>
>>>
配列¶
配列 (Array) はシーケンスであり、決まった数の同じ型のインスタンスを持ちます。
推奨されている配列の作成方法はデータ型に正の整数を掛けることです。:
TenPointsArrayType = POINT * 10
ややわざとらしいデータ型の例になりますが、他のものに混ざって 4 個の POINT がある構造体です:
>>> from ctypes import *
>>> class POINT(Structure):
... _fields_ = ("x", c_int), ("y", c_int)
...
>>> class MyStruct(Structure):
... _fields_ = [("a", c_int),
... ("b", c_float),
... ("point_array", POINT * 4)]
>>>
>>> print(len(MyStruct().point_array))
4
>>>
インスタンスはクラスを呼び出す通常の方法で作成します。:
arr = TenPointsArrayType()
for pt in arr:
print(pt.x, pt.y)
上記のコードは 0 0
という行が並んだものを表示します。配列の要素がゼロで初期化されているためです。
正しい型の初期化子を指定することもできます。:
>>> 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
>>>
ポインタ¶
ポインタのインスタンスは ctypes
型に対して pointer()
関数を呼び出して作成します。:
>>> from ctypes import *
>>> i = c_int(42)
>>> pi = pointer(i)
>>>
次のように、ポインタインスタンスは、ポインタが指すオブジェクト (上の例では i
) を返す contents
属性を持ちます:
>>> pi.contents
c_long(42)
>>>
ctypes
は OOR (original object return 、元のオブジェクトを返すこと) ではないことに注意してください。属性を取り出す度に、新しい同等のオブジェクトを作成しているのです。:
>>> pi.contents is i
False
>>> pi.contents is pi.contents
False
>>>
別の c_int
インスタンスがポインタの contents 属性に代入されると、これが記憶されているメモリ位置を指すポインタに変化します。:
>>> i = c_int(99)
>>> pi.contents = i
>>> pi.contents
c_long(99)
>>>
ポインタインスタンスは整数でインデックス指定することもできます。:
>>> pi[0]
99
>>>
整数インデックスへ代入するとポインタが指す値が変更されます。:
>>> print(i)
c_long(99)
>>> pi[0] = 22
>>> print(i)
c_long(22)
>>>
0 ではないインデックスを使うこともできますが、 C の場合と同じように自分が何をしているかを理解している必要があります。任意のメモリ位置にアクセスもしくは変更できるのです。一般的にこの機能を使うのは、 C 関数からポインタを受け取り、そのポインタが単一の要素ではなく実際に配列を指していると 分かっている 場合だけです。
舞台裏では、 pointer()
関数は単にポインタインスタンスを作成するという以上のことを行っています。はじめにポインタ 型 を作成する必要があります。これは任意の ctypes
型を受け取る POINTER()
関数を使って行われ、新しい型を返します:
>>> 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...>
>>>
ポインタ型を引数なしで呼び出すと NULL
ポインタを作成します。 NULL
ポインタは False
ブール値を持っています。:
>>> null_ptr = POINTER(c_int)()
>>> print(bool(null_ptr))
False
>>>
ctypes
はポインタの指す値を取り出すときに NULL
かどうかを調べます(しかし、 NULL
でない不正なポインタの指す値の取り出す行為は Python をクラッシュさせるでしょう)。:
>>> null_ptr[0]
Traceback (most recent call last):
....
ValueError: NULL pointer access
>>>
>>> null_ptr[0] = 1234
Traceback (most recent call last):
....
ValueError: NULL pointer access
>>>
型変換¶
Usually, ctypes does strict type checking. This means, if you have
POINTER(c_int)
in the argtypes
list of a function or as the type of
a member field in a structure definition, only instances of exactly the same
type are accepted. There are some exceptions to this rule, where ctypes accepts
other objects. For example, you can pass compatible array instances instead of
pointer types. So, for POINTER(c_int)
, ctypes accepts an array of c_int:
>>> class Bar(Structure):
... _fields_ = [("count", c_int), ("values", POINTER(c_int))]
...
>>> bar = Bar()
>>> bar.values = (c_int * 3)(1, 2, 3)
>>> bar.count = 3
>>> for i in range(bar.count):
... print(bar.values[i])
...
1
2
3
>>>
In addition, if a function argument is explicitly declared to be a pointer type
(such as POINTER(c_int)
) in argtypes
, an object of the pointed
type (c_int
in this case) can be passed to the function. ctypes will apply
the required byref()
conversion in this case automatically.
POINTER型フィールドを NULL
に設定するために、 None
を代入してもかまいません。:
>>> bar.values = None
>>>
時には、非互換な型のインスタンスであることもあります。 C では、ある型を他の型へキャストすることができます。 ctypes
は同じやり方で使える cast()
関数を提供しています。上で定義した Bar
構造体は POINTER(c_int)
ポインタまたは c_int
配列を values
フィールドに対して受け取り、他の型のインスタンスは受け取りません:
>>> bar.values = (c_byte * 4)()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: incompatible types, c_byte_Array_4 instance instead of LP_c_long instance
>>>
このような場合には、 cast()
関数が便利です。
cast()
関数は ctypes インスタンスを異なる ctypes データ型を指すポインタへキャストするために使えます。 cast()
は二つのパラメータ、ある種のポインタかそのポインタへ変換できる ctypes オブジェクトと、 ctypes ポインタ型を取ります。そして、第二引数のインスタンスを返します。このインスタンスは第一引数と同じメモリブロックを参照しています:
>>> a = (c_byte * 4)()
>>> cast(a, POINTER(c_int))
<ctypes.LP_c_long object at ...>
>>>
したがって、 cast()
を Bar
構造体の values
フィールドへ代入するために使うことができます:
>>> bar = Bar()
>>> bar.values = cast((c_byte * 4)(), POINTER(c_int))
>>> print(bar.values[0])
0
>>>
不完全型¶
不完全型 はメンバーがまだ指定されていない構造体、共用体もしくは配列です。 C では、前方宣言により指定され、後で定義されます。:
struct cell; /* forward declaration */
struct cell {
char *name;
struct cell *next;
};
ctypes コードへの直接的な変換ではこうなるでしょう。しかし、動作しません:
>>> class cell(Structure):
... _fields_ = [("name", c_char_p),
... ("next", POINTER(cell))]
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in cell
NameError: name 'cell' is not defined
>>>
because the new class cell
is not available in the class statement itself.
In ctypes
, we can define the cell
class and set the
_fields_
attribute later, after the class statement:
>>> from ctypes import *
>>> class cell(Structure):
... pass
...
>>> cell._fields_ = [("name", c_char_p),
... ("next", POINTER(cell))]
>>>
試してみましょう。 cell
のインスタンスを二つ作り、互いに参照し合うようにします。最後に、つながったポインタを何度かたどります。:
>>> c1 = cell()
>>> c1.name = b"foo"
>>> c2 = cell()
>>> c2.name = b"bar"
>>> c1.next = pointer(c2)
>>> c2.next = pointer(c1)
>>> p = c1
>>> for i in range(8):
... print(p.name, end=" ")
... p = p.next[0]
...
foo bar foo bar foo bar foo bar
>>>
コールバック関数¶
ctypes
は C の呼び出し可能な関数ポインタを Python 呼び出し可能オブジェクトから作成できるようにします。これらは コールバック関数 と呼ばれることがあります。
最初に、コールバック関数のためのクラスを作る必要があります。そのクラスには呼び出し規約、戻り値の型およびこの関数が受け取る引数の数と型についての情報があります。
CFUNCTYPE()
ファクトリ関数は通常の cdecl
呼び出し規約を用いてコールバック関数のための型を作成します。 Windows では、 WINFUNCTYPE()
ファクトリ関数が stdcall
呼び出し規約を用いてコールバック関数の型を作成します。
これらのファクトリ関数はともに最初の引数に戻り値の型、残りの引数としてコールバック関数が想定する引数の型を渡して呼び出されます。
I will present an example here which uses the standard C library's
qsort()
function, that is used to sort items with the help of a callback
function. qsort()
will be used to sort an array of integers:
>>> IntArray5 = c_int * 5
>>> ia = IntArray5(5, 1, 7, 33, 99)
>>> qsort = libc.qsort
>>> qsort.restype = None
>>>
qsort()
must be called with a pointer to the data to sort, the number of
items in the data array, the size of one item, and a pointer to the comparison
function, the callback. The callback will then be called with two pointers to
items, and it must return a negative integer if the first item is smaller than
the second, a zero if they are equal, and a positive integer otherwise.
コールバック関数は整数へのポインタを受け取り、整数を返す必要があります。まず、コールバック関数のための type
を作成します。:
>>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
>>>
まず初めに、これが受け取った変数を表示するだけのシンプルなコールバックです:
>>> def py_cmp_func(a, b):
... print("py_cmp_func", a[0], b[0])
... return 0
...
>>> cmp_func = CMPFUNC(py_cmp_func)
>>>
結果は以下の通りです:
>>> 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
>>>
ここで 2 つの要素を実際に比較し、役に立つ結果を返します:
>>> 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
>>>
簡単に確認できるように、配列を次のようにソートしました:
>>> for i in ia: print(i, end=" ")
...
1 5 7 33 99
>>>
関数ファクトリはデコレータファクトリとしても使えるので、次のようにも書けます:
>>> @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
>>>
注釈
C コードから CFUNCTYPE()
オブジェクトが使用される限り、そのオブジェクトへの参照を確実に保持してください。 ctypes
は参照を保持しないため、あなたが参照を保持しないと、オブジェクトはガベージコレクションの対象となり、コールバックが行われたときにプログラムをクラッシュさせる場合があります。
同様に、コールバック関数が Python の管理外 (例えば、コールバックを呼び出す外部のコード) で作られたスレッドで呼び出された場合、 ctypes は全ての呼び出しごとに新しいダミーの Python スレッドを作成することに注意してください。 この動作はほとんどの目的に対して正しいものですが、同じ C スレッドからの呼び出しだったとしても、 threading.local
で格納された値は異なるコールバックをまたいで生存は しません 。
dllからエクスポートされた値へアクセスする¶
Some shared libraries not only export functions, they also export variables. An
example in the Python library itself is the Py_Version
, Python
runtime version number encoded in a single constant integer.
ctypes
can access values like this with the in_dll()
class methods of
the type. pythonapi is a predefined symbol giving access to the Python C
api:
>>> version = ctypes.c_int.in_dll(ctypes.pythonapi, "Py_Version")
>>> print(hex(version.value))
0x30c00a0
ポインタの使い方を説明する拡張例では、 Python がエクスポートする PyImport_FrozenModules
ポインタにアクセスします。
この値のドキュメントから引用すると:
このポインタは
_frozen
のレコードからなり、終端の要素のメンバがNULL
かゼロになっているような配列を指すよう初期化されます。 フリーズされたモジュールをインポートするとき、このテーブルを検索します。 サードパーティ製のコードからこのポインタに仕掛けを講じて、動的に生成されたフリーズ化モジュールの集合を提供するようにできます。
これで、このポインタを操作することが役に立つことを証明できるでしょう。例の大きさを制限するために、このテーブルを ctypes
を使って読む方法だけを示します。:
>>> from ctypes import *
>>>
>>> class struct_frozen(Structure):
... _fields_ = [("name", c_char_p),
... ("code", POINTER(c_ubyte)),
... ("size", c_int),
... ("get_code", POINTER(c_ubyte)), # Function pointer
... ]
...
>>>
私たちは _frozen
データ型を定義済みなので、このテーブルを指すポインタを得ることができます。:
>>> FrozenTable = POINTER(struct_frozen)
>>> table = FrozenTable.in_dll(pythonapi, "_PyImport_FrozenBootstrap")
>>>
table
が struct_frozen
レコードの配列への pointer
なので、その配列に対して反復処理を行えます。しかし、ループが確実に終了するようにする必要があります。なぜなら、ポインタに大きさの情報がないからです。遅かれ早かれ、アクセス違反か何かでクラッシュすることになるでしょう。 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
zipimport 12345
>>>
標準 Python はフローズンモジュールとフローズンパッケージ (負の size
メンバーで表されています) を持っているという事実はあまり知られておらず、テストにだけ使われています。例えば、 import __hello__
を試してみてください。
びっくり仰天¶
There are some edges in ctypes
where you might expect something other
than what actually happens.
次に示す例について考えてみてください。:
>>> 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
>>>
うーん、最後の文に 3 4 1 2
と表示されることを期待していたはずです。何が起きたのでしょうか? 上の行の rc.a, rc.b = rc.b, rc.a
の各段階はこのようになります。:
>>> temp0, temp1 = rc.b, rc.a
>>> rc.a = temp0
>>> rc.b = temp1
>>>
temp0
と temp1
は前記の rc
オブジェクトの内部バッファでまだ使われているオブジェクトです。したがって、 rc.a = temp0
を実行すると temp0
のバッファ内容が rc
のバッファへコピーされます。さらに、これは temp1
の内容を変更します。そのため、最後の代入 rc.b = temp1
は、期待する結果にはならないのです。
Structure 、 Union および Array のサブオブジェクトを取り出しても、そのサブオブジェクトが コピー されるわけではなく、ルートオブジェクトの内部バッファにアクセスするラッパーオブジェクトを取り出すことを覚えておいてください。
期待とは違う振る舞いをする別の例はこれです:
>>> s = c_char_p()
>>> s.value = b"abc def ghi"
>>> s.value
b'abc def ghi'
>>> s.value is s.value
False
>>>
注釈
c_char_p
からインスタンス化されたオブジェクトは、bytes または整数に設定された値しか持てません。
なぜ False
と表示されるのでしょうか? ctypes インスタンスはメモリと、メモリの内容にアクセスするいくつかの descriptor (記述子)を含むオブジェクトです。メモリブロックに Python オブジェクトを保存してもオブジェクト自身が保存される訳ではなく、オブジェクトの contents
が保存されます。その contents に再アクセスすると新しい Python オブジェクトがその度に作られます。
可変サイズのデータ型¶
ctypes
は可変サイズの配列と構造体をサポートしています。
resize()
関数は既存の ctypes オブジェクトのメモリバッファのサイズを変更したい場合に使えます。この関数は第一引数にオブジェクト、第二引数に要求されたサイズをバイト単位で指定します。メモリブロックはオブジェクト型で指定される通常のメモリブロックより小さくすることはできません。これをやろうとすると、 ValueError
が送出されます。:
>>> short_array = (c_short * 4)()
>>> print(sizeof(short_array))
8
>>> resize(short_array, 4)
Traceback (most recent call last):
...
ValueError: minimum size is 8
>>> resize(short_array, 32)
>>> sizeof(short_array)
32
>>> sizeof(type(short_array))
8
>>>
これはこれで上手くいっていますが、この配列の追加した要素へどうやってアクセスするのでしょうか? この型は要素の数が 4 個であるとまだ認識しているので、他の要素にアクセスするとエラーになります。:
>>> short_array[:]
[0, 0, 0, 0]
>>> short_array[7]
Traceback (most recent call last):
...
IndexError: invalid index
>>>
ctypes
で可変サイズのデータ型を使うもう一つの方法は、必要なサイズが分かった後に Python の動的性質を使って一つ一つデータ型を(再)定義することです。
ctypesリファレンス¶
外部関数¶
As explained in the previous section, foreign functions can be accessed as attributes of loaded shared libraries. The function objects created in this way by default accept any number of arguments, accept any ctypes data instances as arguments, and return the default result type specified by the library loader.
They are instances of a private local class _FuncPtr
(not exposed
in ctypes
) which inherits from the private _CFuncPtr
class:
>>> import ctypes
>>> lib = ctypes.CDLL(None)
>>> issubclass(lib._FuncPtr, ctypes._CFuncPtr)
True
>>> lib._FuncPtr is ctypes._CFuncPtr
False
- class ctypes._CFuncPtr¶
C の呼び出し可能外部関数のためのベースクラス。
外部関数のインスタンスも C 互換データ型です。それらは C の関数ポインタを表しています。
この振る舞いは外部関数オブジェクトの特別な属性に代入することによって、カスタマイズすることができます。
- restype¶
外部関数の結果の型を指定するために ctypes 型を代入する。何も返さない関数を表す void に対しては
None
を使います。It is possible to assign a callable Python object that is not a ctypes type, in this case the function is assumed to return a C int, and the callable will be called with this integer, allowing further processing or error checking. Using this is deprecated, for more flexible post processing or error checking use a ctypes data type as
restype
and assign a callable to theerrcheck
attribute.
- argtypes¶
関数が受け取る引数の型を指定するために ctypes 型のタプルを代入します。
stdcall
呼び出し規約を使う関数はこのタプルの長さと同じ数の引数で呼び出されます。C 呼び出し規約を使う関数は、追加の不特定の引数も取ります。When a foreign function is called, each actual argument is passed to the
from_param()
class method of the items in theargtypes
tuple, this method allows adapting the actual argument to an object that the foreign function accepts. For example, ac_char_p
item in theargtypes
tuple will convert a string passed as argument into a bytes object using ctypes conversion rules.New: It is now possible to put items in argtypes which are not ctypes types, but each item must have a
from_param()
method which returns a value usable as argument (integer, string, ctypes instance). This allows defining adapters that can adapt custom objects as function parameters.
- errcheck¶
Python 関数または他の呼び出し可能オブジェクトをこの属性に代入します。呼び出し可能オブジェクトは三つ以上の引数とともに呼び出されます。
- callable(result, func, arguments)
result is what the foreign function returns, as specified by the
restype
attribute.func は外部関数オブジェクト自身で、これにより複数の関数の処理結果をチェックまたは後処理するために、同じ呼び出し可能オブジェクトを再利用できるようになります。
arguments は関数呼び出しに最初に渡されたパラメータが入ったタプルです。これにより使われた引数に基づいた特別な振る舞いをさせることができるようになります。
この関数が返すオブジェクトは外部関数呼び出しから返された値でしょう。しかし、戻り値をチェックして、外部関数呼び出しが失敗しているなら例外を送出させることもできます。
- exception ctypes.ArgumentError¶
この例外は外部関数呼び出しが渡された引数を変換できなかったときに送出されます。
On Windows, when a foreign function call raises a system exception (for
example, due to an access violation), it will be captured and replaced with
a suitable Python exception. Further, an auditing event
ctypes.set_exception
with argument code
will be raised, allowing an
audit hook to replace the exception with its own.
Some ways to invoke foreign function calls may raise an auditing event
ctypes.call_function
with arguments function pointer
and arguments
.
関数プロトタイプ¶
外部関数は関数プロトタイプをインスタンス化することによって作成されます。
関数プロトタイプは C の関数プロトタイプと似ています。実装は定義せずに、関数 (返り値の型、引数の型、呼び出し規約) を記述します。
ファクトリ関数は、その関数に要求される返り値の型と引数の型とともに呼び出されます。そしてこの関数はデコレータファクトリとしても使え、 @wrapper
構文で他の関数に適用できます。
例については コールバック関数 を参照してください。
- ctypes.CFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)¶
返された関数プロトタイプは標準 C 呼び出し規約をつかう関数を作成します。関数は呼び出されている間 GIL を解放します。 use_errno が真に設定されれば、呼び出しの前後で System 変数
errno
の ctypesプライベートコピーは本当のerrno
の値と交換されます。 use_last_error も Windows エラーコードに対するのと同様です。
- ctypes.WINFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)¶
Windows のみ: 返された関数プロトタイプは
stdcall
呼び出し規約を使う関数を作成します。関数は呼び出されている間 GIL を解放します。 use_errno と use_last_error は前述と同じ意味を持ちます。
- ctypes.PYFUNCTYPE(restype, *argtypes)¶
返された関数プロトタイプは Python 呼び出し規約を使う関数を作成します。関数は呼び出されている間 GIL を解放 しません。
ファクトリ関数によって作られた関数プロトタイプは呼び出しのパラメータの型と数に依存した別の方法でインスタンス化することができます。 :
- prototype(address)
指定されたアドレス(整数でなくてはなりません)の外部関数を返します。
- prototype(callable)
Python の callable から C の呼び出し可能関数(コールバック関数) を作成します。
- prototype(func_spec[, paramflags])
共有ライブラリがエクスポートしている外部関数を返します。 func_spec は 2 要素タプル
(name_or_ordinal, library)
でなければなりません。第一要素はエクスポートされた関数の名前である文字列、またはエクスポートされた関数の序数である小さい整数です。第二要素は共有ライブラリインスタンスです。
- prototype(vtbl_index, name[, paramflags[, iid]])
COM メソッドを呼び出す外部関数を返します。 vtbl_index は仮想関数テーブルのインデックスで、非負の小さい整数です。 name は COM メソッドの名前です。 iid はオプションのインターフェイス識別子へのポインタで、拡張されたエラー情報の提供のために使われます。
COM methods use a special calling convention: They require a pointer to the COM interface as first argument, in addition to those parameters that are specified in the
argtypes
tuple.
オプションの paramflags パラメータは上述した機能より多機能な外部関数ラッパーを作成します。
paramflags must be a tuple of the same length as argtypes
.
このタプルの個々の要素はパラメータについてのより詳細な情報を持ち、 1 、 2 もしくは 3 要素を含むタプルでなければなりません。
第一要素はパラメータについてのフラグの組み合わせを含んだ整数です。
- 1
入力パラメータを関数に指定します。
- 2
出力パラメータ。外部関数が値を書き込みます。
- 4
デフォルトで整数ゼロになる入力パラメータ。
オプションの第二要素はパラメータ名の文字列です。これが指定された場合は、外部関数を名前付きパラメータで呼び出すことができます。
オプションの第三要素はこのパラメータのデフォルト値です。
The following example demonstrates how to wrap the Windows MessageBoxW
function so
that it supports default parameters and named arguments. The C declaration from
the windows header file is this:
WINUSERAPI int WINAPI
MessageBoxW(
HWND hWnd,
LPCWSTR lpText,
LPCWSTR lpCaption,
UINT uType);
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)
これで外部関数の MessageBox
を次のような方法で呼び出すことができるようになりました:
>>> MessageBox()
>>> MessageBox(text="Spam, spam, spam")
>>> MessageBox(flags=2, text="foo bar")
二番目の例は出力パラメータについて説明します。 win32 の GetWindowRect
関数は、指定されたウィンドウの大きさを呼び出し側が与える RECT
構造体へコピーすることで取り出します。 C の宣言はこうです。:
WINUSERAPI BOOL WINAPI
GetWindowRect(
HWND hWnd,
LPRECT lpRect);
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)
>>>
出力パラメータを持つ関数は、単一のパラメータがある場合にはその出力パラメータ値を、複数のパラメータがある場合には出力パラメータ値が入ったタプルを、それぞれ自動的に返します。そのため、GetWindowRect 関数は呼び出されると RECT インスタンスを返します。
Output parameters can be combined with the errcheck
protocol to do
further output processing and error checking. The win32 GetWindowRect
api
function returns a BOOL
to signal success or failure, so this function could
do the error checking, and raises an exception when the api call failed:
>>> def errcheck(result, func, args):
... if not result:
... raise WinError()
... return args
...
>>> GetWindowRect.errcheck = errcheck
>>>
If the errcheck
function returns the argument tuple it receives
unchanged, ctypes
continues the normal processing it does on the output
parameters. If you want to return a tuple of window coordinates instead of a
RECT
instance, you can retrieve the fields in the function and return them
instead, the normal processing will no longer take place:
>>> 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
>>>
ユーティリティー関数¶
- ctypes.addressof(obj)¶
メモリバッファのアドレスを示す整数を返します。 obj は ctypes 型のインスタンスでなければなりません。
引数
obj
を指定して 監査イベントctypes.addressof
を送出します。
- ctypes.alignment(obj_or_type)¶
ctypes 型のアライメントの必要条件を返します。 obj_or_type は ctypes 型またはインスタンスでなければなりません。
- ctypes.byref(obj[, offset])¶
obj (ctypes 型のインスタンスでなければならない) への軽量ポインタを返します。 offset はデフォルトでは 0 で、内部ポインターへ加算される整数です。
byref(obj, offset)
は、 C コードとしては、以下のようにみなされます。:(((char *)&obj) + offset)
返されるオブジェクトは外部関数呼び出しのパラメータとしてのみ使用できます。
pointer(obj)
と似たふるまいをしますが、作成が非常に速く行えます。
- ctypes.cast(obj, type)¶
この関数は C のキャスト演算子に似ています。obj と同じメモリブロックを指している type の新しいインスタンスを返します。type はポインタ型でなければならず、obj はポインタとして解釈できるオブジェクトでなければなりません。
- ctypes.create_string_buffer(init_or_size, size=None)¶
この関数は変更可能な文字バッファを作成します。返されるオブジェクトは
c_char
の ctypes 配列です。init_or_size は配列のサイズを指定する整数もしくは配列要素を初期化するために使われるバイト列オブジェクトである必要があります。
バイト列オブジェクトが第一引数として指定されていた場合、配列の最後の要素が NUL 終端文字となるように、バイト列オブジェクトの長さより 1 つ長いバッファを作成します。バイト列の長さを使うべきではない場合は、第二引数として整数を渡して、配列の長さを指定することができます。
引数
init
,size
を指定して 監査イベントctypes.create_string_buffer
を送出します。
- ctypes.create_unicode_buffer(init_or_size, size=None)¶
この関数は変更可能な Unicode 文字バッファを作成します。返されるオブジェクトは
c_wchar
の ctypes 配列です。init_or_size は配列のサイズを指定する整数もしくは配列要素を初期化するために使われる文字列である必要があります。
第一引数として文字列が指定された場合は、バッファが文字列の長さより一要素分大きく作られます。配列の最後の要素が NUL 終端文字であるためです。文字列の長さを使うべきでない場合は、配列のサイズを指定するために整数を第二引数として渡すことができます。
引数
init
,size
を指定して 監査イベントctypes.create_unicode_buffer
を送出します。
- ctypes.DllCanUnloadNow()¶
Windows 用: この関数は ctypes をつかってインプロセス COM サーバーを実装できるようにするためのフックです。_ctypes 拡張 dll がエクスポートしている DllCanUnloadNow 関数から呼び出されます。
- ctypes.DllGetClassObject()¶
Windows 用: この関数は ctypes をつかってインプロセス COM サーバーを実装できるようにするためのフックです。
_ctypes
拡張 dll がエクスポートしている DllGetClassObject 関数から呼び出されます。
- ctypes.util.find_library(name)¶
ライブラリを検索し、パス名を返します。 name は
lib
のような接頭辞、.so
や.dylib
のような接尾辞、そして、バージョンナンバーを除くライブラリ名です (これは posix のリンカーオプション-l
で使われる書式です) 。もしライブラリが見つからなければ、None
を返します。厳密な機能はシステムに依存します。
- ctypes.util.find_msvcrt()¶
Windows 用: Python と拡張モジュールで使われる VC ランタイムライブラリのファイル名を返します。もしライブラリ名が同定できなければ、
None
を返します。もし、例えば拡張モジュールにより割り付けられたメモリを
free(void *)
で解放する必要があるなら、メモリ割り付けを行ったのと同じライブラリの関数を使うことが重要です。
- ctypes.FormatError([code])¶
Windows 用: エラーコード code の説明文を返します。エラーコードが指定されない場合は、 Windows api 関数 GetLastError を呼び出して、もっとも新しいエラーコードが使われます。
- ctypes.GetLastError()¶
Windows 用: 呼び出し側のスレッド内で Windows によって設定された最新のエラーコードを返します。この関数は Windows の
GetLastError()
関数を直接実行します。 ctypes のプライベートなエラーコードのコピーを返したりはしません。
- ctypes.get_last_error()¶
Windows only: returns the current value of the ctypes-private copy of the system
LastError
variable in the calling thread.引数無しで 監査イベント
ctypes.get_last_error
を送出します。
- ctypes.memmove(dst, src, count)¶
標準 C の memmove ライブラリ関数と同じものです。: count バイトを src から dst へコピーします。 dst と src はポインタへ変換可能な整数または ctypes インスタンスでなければなりません。
- ctypes.memset(dst, c, count)¶
標準 C の memset ライブラリ関数と同じものです。: アドレス dst のメモリブロックを値 c を count バイト分書き込みます。 dst はアドレスを指定する整数または ctypes インスタンスである必要があります。
- ctypes.POINTER(type, /)¶
Create and return a new ctypes pointer type. Pointer types are cached and reused internally, so calling this function repeatedly is cheap. type must be a ctypes type.
- ctypes.pointer(obj, /)¶
Create a new pointer instance, pointing to obj. The returned object is of the type
POINTER(type(obj))
.注意: 外部関数呼び出しへオブジェクトへのポインタを渡したいだけなら、はるかに高速な
byref(obj)
を使うべきです。
- ctypes.resize(obj, size)¶
この関数は obj の内部メモリバッファのサイズを変更します。 obj は ctypes 型のインスタンスでなければなりません。バッファを
sizeof(type(obj))
で与えられるオブジェクト型の本来のサイズより小さくすることはできませんが、バッファを拡大することはできます。
- ctypes.set_errno(value)¶
システム変数
errno
の、呼び出し元スレッドでの ctypes のプライベートコピーの現在値を value に設定し、前の値を返します。引数
errno
を指定して 監査イベントctypes.set_errno
を送出します。
- ctypes.set_last_error(value)¶
Windows only: set the current value of the ctypes-private copy of the system
LastError
variable in the calling thread to value and return the previous value.引数
error
を指定して 監査イベントctypes.set_last_error
を送出します。
- ctypes.sizeof(obj_or_type)¶
ctypes の型やインスタンスのメモリバッファのサイズをバイト数で返します。C の
sizeof
演算子と同様の動きをします。
- ctypes.string_at(ptr, size=-1)¶
Return the byte string at void *ptr. If size is specified, it is used as size, otherwise the string is assumed to be zero-terminated.
Raises an auditing event
ctypes.string_at
with argumentsptr
,size
.
- ctypes.WinError(code=None, descr=None)¶
Windows only: this function is probably the worst-named thing in ctypes. It creates an instance of
OSError
. If code is not specified,GetLastError
is called to determine the error code. If descr is not specified,FormatError()
is called to get a textual description of the error.バージョン 3.3 で変更: An instance of
WindowsError
used to be created, which is now an alias ofOSError
.
- ctypes.wstring_at(ptr, size=-1)¶
Return the wide-character string at void *ptr. If size is specified, it is used as the number of characters of the string, otherwise the string is assumed to be zero-terminated.
Raises an auditing event
ctypes.wstring_at
with argumentsptr
,size
.
データ型¶
- class ctypes._CData¶
この非公開クラスはすべての ctypes データ型の共通のベースクラスです。他のことはさておき、すべての ctypes 型インスタンスは C 互換データを保持するメモリブロックを内部に持ちます。このメモリブロックのアドレスは
addressof()
ヘルパー関数が返します。別のインスタンス変数が_objects
として公開されます。これはメモリブロックがポインタを含む場合に存続し続ける必要のある他の Python オブジェクトを含んでいます。ctypes データ型の共通メソッド、すべてのクラスメソッドが存在します (正確には、 メタクラス のメソッドです):
- from_buffer(source[, offset])¶
このメソッドは source オブジェクトのバッファを共有する ctypes のインスタンスを返します。 source オブジェクトは書き込み可能バッファインターフェースをサポートしている必要があります。オプションの offset 引数では source バッファのオフセットをバイト単位で指定します。デフォルトではゼロです。もし source バッファが十分に大きくなければ、
ValueError
が送出されます。引数
pointer
,size
,offset
を指定して 監査イベントctypes.cdata/buffer
を送出します。
- from_buffer_copy(source[, offset])¶
このメソッドは source オブジェクトの読み出し可能バッファをコピーすることで、ctypes のインスタンスを生成します。オプションの offset 引数では source バッファのオフセットをバイト単位で指定します。デフォルトではゼロです。もし source バッファが十分に大きくなければ、
ValueError
が送出されます。引数
pointer
,size
,offset
を指定して 監査イベントctypes.cdata/buffer
を送出します。
- from_address(address)¶
このメソッドは address で指定されたメモリを使って ctypes 型のインスタンスを返します。 address は整数でなければなりません。
This method, and others that indirectly call this method, raises an auditing event
ctypes.cdata
with argumentaddress
.
- from_param(obj)¶
This method adapts obj to a ctypes type. It is called with the actual object used in a foreign function call when the type is present in the foreign function's
argtypes
tuple; it must return an object that can be used as a function call parameter.すべての ctypes のデータ型は、それが型のインスタンスであれば、 obj を返すこのクラスメソッドのデフォルトの実装を持ちます。いくつかの型は、別のオブジェクトも受け付けます。
- in_dll(library, name)¶
このメソッドは、共有ライブラリによってエクスポートされた ctypes 型のインスタンスを返します。 name はエクスポートされたデータの名前で、 library はロードされた共有ライブラリです。
ctypes データ型共通のインスタンス変数:
- _b_base_¶
ctypes 型データのインスタンスは、それ自身のメモリブロックを持たず、基底オブジェクトのメモリブロックの一部を共有することがあります。
_b_base_
読み出し専用属性は、メモリブロックを保持する ctypes の基底オブジェクトです。
- _b_needsfree_¶
この読み出し専用の変数は、 ctypes データインスタンスが、それ自身に割り当てられたメモリブロックを持つとき true になります。それ以外の場合は false になります。
- _objects¶
このメンバは
None
、または、メモリブロックの内容が正しく保つために、生存させておかなくてはならない Python オブジェクトを持つディクショナリです。このオブジェクトはデバッグでのみ使われます。決してディクショナリの内容を変更しないで下さい。
基本データ型¶
- class ctypes._SimpleCData¶
この非公開クラスは、全ての基本的な ctypes データ型の基底クラスです。これは基本的な ctypes データ型に共通の属性を持っているので、ここで触れておきます。
_SimpleCData
は_CData
の子クラスなので、そのメソッドと属性を継承しています。ポインタでないかポインタを含まない ctypes データ型は、現在は pickle 化できます。インスタンスは一つだけ属性を持ちます:
Fundamental data types, when returned as foreign function call results, or, for
example, by retrieving structure field members or array items, are transparently
converted to native Python types. In other words, if a foreign function has a
restype
of c_char_p
, you will always receive a Python bytes
object, not a c_char_p
instance.
Subclasses of fundamental data types do not inherit this behavior. So, if a
foreign functions restype
is a subclass of c_void_p
, you will
receive an instance of this subclass from the function call. Of course, you can
get the value of the pointer by accessing the value
attribute.
これらが基本 ctypes データ型です:
- class ctypes.c_byte¶
C の signed char データ型を表し、小整数として値を解釈します。コンストラクタはオプションの整数初期化子を受け取ります。オーバーフローのチェックは行われません。
- class ctypes.c_char¶
C char データ型を表し、単一の文字として値を解釈します。コンストラクタはオプションの文字列初期化子を受け取り、その文字列の長さちょうど一文字である必要があります。
- class ctypes.c_char_p¶
C char* データ型を表し、ゼロ終端文字列へのポインタでなければなりません。バイナリデータを指す可能性のある一般的なポインタに対しては
POINTER(c_char)
を使わなければなりません。コンストラクタは整数のアドレスもしくはバイト列オブジェクトを受け取ります。
- class ctypes.c_double¶
C double データ型を表します。コンストラクタはオプションの浮動小数点数初期化子を受け取ります。
- class ctypes.c_longdouble¶
C long double データ型を表します。コンストラクタはオプションで浮動小数点数初期化子を受け取ります。
sizeof(long double) == sizeof(double)
であるプラットフォームではc_double
の別名です。
- class ctypes.c_float¶
C float データ型を表します。コンストラクタはオプションの浮動小数点数初期化子を受け取ります。
- class ctypes.c_int¶
C signed int データ型を表します。コンストラクタはオプションの整数初期化子を受け取ります。オーバーフローのチェックは行われません。
sizeof(int) == sizeof(long)
であるプラットフォームでは、c_long
の別名です。
- class ctypes.c_int64¶
C 64-bit signed int データ型を表します。たいていは、
c_longlong
の別名です。
- class ctypes.c_long¶
C signed long データ型を表します。コンストラクタはオプションの整数初期化子を受け取ります。オーバーフローのチェックは行われません。
- class ctypes.c_longlong¶
C signed long long データ型を表します。コンストラクタはオプションの整数初期化子を受け取ります。オーバーフローのチェックは行われません。
- class ctypes.c_short¶
C signed short データ型を表します。コンストラクタはオプションの整数初期化子を受け取ります。オーバーフローのチェックは行われません。
- class ctypes.c_size_t¶
C
size_t
データ型を表します。
- class ctypes.c_ssize_t¶
C
ssize_t
データ型を表します。Added in version 3.2.
- class ctypes.c_time_t¶
Represents the C
time_t
datatype.Added in version 3.12.
- class ctypes.c_ubyte¶
C の unsigned char データ型を表し、小さな整数として値を解釈します。コンストラクタはオプションの整数初期化子を受け取ります; オーバーフローのチェックは行われません。
- class ctypes.c_uint¶
C の unsigned int データ型を表します。コンストラクタはオプションの整数初期化子を受け取ります; オーバーフローのチェックは行われません。これは、
sizeof(int) == sizeof(long)
であるプラットフォームではc_ulong
の別名です。
- class ctypes.c_uint64¶
C 64-bit unsigned int データ型を表します。たいていは、
c_ulonglong
の別名です。
- class ctypes.c_ulong¶
C unsigned long データ型を表します。コンストラクタはオプションの整数初期化子を受け取ります。オーバーフローのチェックは行われません。
- class ctypes.c_ulonglong¶
C unsigned long long データ型を表します。コンストラクタはオプションの整数初期化子を受け取ります。オーバーフローのチェックは行われません。
- class ctypes.c_ushort¶
C unsigned short データ型を表します。コンストラクタはオプションの整数初期化子を受け取ります。オーバーフローのチェックは行われません。
- class ctypes.c_void_p¶
C void* データ型を表します。値は整数として表されます。コンストラクタはオプションの整数初期化子を受け取ります。
- class ctypes.c_wchar¶
C
wchar_t
データ型を表し、値は Unicode 文字列の単一の文字として解釈されます。コンストラクタはオプションの文字列初期化子を受け取り、その文字列の長さはちょうど一文字である必要があります。
- class ctypes.c_wchar_p¶
C wchar_t* データ型を表し、ゼロ終端ワイド文字列へのポインタでなければなりません。コンストラクタは整数のアドレスもしくは文字列を受け取ります。
- class ctypes.c_bool¶
C の bool データ型 (より正確には、 C99 以降の _Bool) を表します。
True
またはFalse
の値を持ち、コンストラクタは真偽値と解釈できるオブジェクトを受け取ります。
- class ctypes.HRESULT¶
Windows only: Represents a
HRESULT
value, which contains success or error information for a function or method call.
The ctypes.wintypes
module provides quite some other Windows specific
data types, for example HWND
, WPARAM
, or DWORD
.
Some useful structures like MSG
or RECT
are also defined.
構造化データ型¶
- class ctypes.Union(*args, **kw)¶
ネイティブのバイトオーダーでの共用体のための抽象ベースクラス。
- class ctypes.BigEndianUnion(*args, **kw)¶
ビックエンディアン バイトオーダーでの共用体のための抽象ベースクラス。
Added in version 3.11.
- class ctypes.LittleEndianUnion(*args, **kw)¶
リトルエンディアン バイトオーダーでの共用体のための抽象ベースクラス。
Added in version 3.11.
- class ctypes.BigEndianStructure(*args, **kw)¶
ビックエンディアン バイトオーダーでの構造体のための抽象ベースクラス。
- class ctypes.LittleEndianStructure(*args, **kw)¶
リトルエンディアン バイトオーダーでの構造体のための抽象ベースクラス。
ネイティブではないバイトオーダーを持つ構造体および共用体にポインタ型フィールドあるいはポインタ型フィールドを含む他のどんなデータ型をも入れることはできません。
- class ctypes.Structure(*args, **kw)¶
ネイティブ のバイトオーダーでの構造体のための抽象ベースクラス。
具象構造体型と具象共用体型はこれらの型の一つをサブクラス化することで作らなければなりません。少なくとも、
_fields_
クラス変数を定義する必要があります。ctypes
は、属性に直接アクセスしてフィールドを読み書きできるようにする デスクリプタ を作成するでしょう。これらは、- _fields_¶
構造体のフィールドを定義するシーケンス。要素は2要素タプルか3要素タプルでなければなりません。第一要素はフィールドの名前です。第二要素はフィールドの型を指定します。それはどんな ctypes データ型でも構いません。
c_int
のような整数型のために、オプションの第三要素を与えることができます。フィールドのビット幅を定義する正の小整数である必要があります。一つの構造体と共用体の中で、フィールド名はただ一つである必要があります。これはチェックされません。名前が繰り返しでてきたときにアクセスできるのは一つのフィールドだけです。
Structure サブクラスを定義するクラス文の 後で 、
_fields_
クラス変数を定義することができます。これにより、次のように自身を直接または間接的に参照するデータ型を作成できるようになります:class List(Structure): pass List._fields_ = [("pnext", POINTER(List)), ... ]
しかし、
_fields_
クラス変数はその型が最初に使われる (インスタンスが作成される、それに対してsizeof()
が呼び出されるなど) より前に定義されていなければなりません。その後_fields_
クラス変数へ代入すると AttributeError が送出されます。構造体型のサブクラスのサブクラスを定義することもでき、もしあるならサブクラスのサブクラス内で定義された
_fields_
に加えて、基底クラスのフィールドも継承します。
- _pack_¶
An optional small integer that allows overriding the alignment of structure fields in the instance.
_pack_
must already be defined when_fields_
is assigned, otherwise it will have no effect. Setting this attribute to 0 is the same as not setting it at all.
- _anonymous_¶
無名 (匿名) フィールドの名前が並べあげられたオプションのシーケンス。
_fields_
が代入されたとき、_anonymous_
がすでに定義されていなければなりません。そうでなければ、何ら影響はありません。この変数に並べあげられたフィールドは構造体型もしくは共用体型フィールドである必要があります。構造体フィールドまたは共用体フィールドを作る必要なく、入れ子になったフィールドに直接アクセスできるようにするために、
ctypes
は構造体型の中に記述子を作成します。型の例です (Windows):
class _U(Union): _fields_ = [("lptdesc", POINTER(TYPEDESC)), ("lpadesc", POINTER(ARRAYDESC)), ("hreftype", HREFTYPE)] class TYPEDESC(Structure): _anonymous_ = ("u",) _fields_ = [("u", _U), ("vt", VARTYPE)]
TYPEDESC
構造体はCOMデータ型を表現しており、vt
フィールドは共用体フィールドのどれが有効であるかを指定します。u
フィールドは匿名フィールドとして定義されているため、 TYPEDESC インスタンスから取り除かれてそのメンバーへ直接アクセスできます。td.lptdesc
とtd.u.lptdesc
は同等ですが、前者がより高速です。なぜなら一時的な共用体インスタンスを作る必要がないためです。:td = TYPEDESC() td.vt = VT_PTR td.lptdesc = POINTER(some_type) td.u.lptdesc = POINTER(some_type)
構造体のサブクラスのサブクラスを定義することができ、基底クラスのフィールドを継承します。 サブクラス定義に別の
_fields_
変数がある場合は、この中で指定されたフィールドは基底クラスのフィールドへ追加されます。構造体と共用体のコンストラクタは位置引数とキーワード引数の両方を受け取ります。位置引数は
_fields_
の中に現れたのと同じ順番でメンバーフィールドを初期化するために使われます。コンストラクタのキーワード引数は属性代入として解釈され、そのため、同じ名前をもつ_fields_
を初期化するか、_fields_
に存在しない名前に対しては新しい属性を作ります。
配列とポインタ¶
- class ctypes.Array(*args)¶
配列のための抽象基底クラスです。
具象配列型を作成するための推奨される方法は、任意の
ctypes
データ型に非負の整数を乗算することです。代わりに、この型のサブクラスを作成し、_length_
と_type_
のクラス変数を定義することもできます。配列の要素は、標準の添え字とスライスによるアクセスを使用して読み書きを行うことができます。スライスの読み込みでは、結果のオブジェクト自体はArray
ではありません。- _length_¶
配列の要素数を指定する正の整数。範囲外の添え字を指定すると、
IndexError
が送出されます。len()
がこの整数を返します。
- _type_¶
配列内の各要素の型を指定します。
配列のサブクラスのコンストラクタは、位置引数を受け付けて、配列を順番に初期化するために使用します。
- class ctypes._Pointer¶
ポインタのためのプライベートな抽象基底クラスです。
具象ポインタ型は、ポイント先の型を持つ
POINTER()
を呼び出すことで、作成できます。これは、pointer()
により自動的に行われます。ポインタが配列を指す場合、その配列の要素は、標準の添え字とスライスによるアクセスを使用して読み書きが行えます。ポインタオブジェクトには、サイズがないため、
len()
関数はTypeError
を送出します。負の添え字は、(C と同様に) ポインタの 前 のメモリから読み込み、範囲外の添え字はおそらく (幸運な場合でも) アクセス違反によりクラッシュを起こします。- _type_¶
ポイント先の型を指定します。
- contents¶
ポインタが指すオブジェクトを返します。この属性に割り当てると、ポインタが割り当てられたオブジェクトを指すようになります。