14.14.2.4 関数プロトタイプ

外部関数は関数プロトタイプをインスタンス化することによって作成されます。 関数プロトタイプはCの関数プロトタイプと似ています。実装を定義せずに、 関数(戻り値、引数の型、呼び出し規約)を記述します。 ファクトリ関数は関数に要求する戻り値の型と引数の型とともに呼び出されます。

CFUNCTYPE( restype, *argtypes)
返された関数プロトタイプは標準C呼び出し規約をつかう関数を作成します。 関数は呼び出されている間GILを解放します。

WINFUNCTYPE( restype, *argtypes)
Windows用: 返された関数プロトタイプはstdcall呼び出し規約を つかう関数を作成します。ただし、WINFUNCTYPECFUNCTYPEと同じであるWindows CEを除く。 関数は呼び出されている間GILを解放します。

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メソッドは特殊な呼び出し規約を用います。このメソッドは argtypesタプルに指定されたパラメータに加えて、 第一引数としてCOMインターフェイスへのポインタを必要とします。

オプションのparamflagsパラメータは上述した機能より多機能な 外部関数ラッパーを作成します。

paramflagsargtypesと同じ長さのタプルでなければならない。

このタプルの個々の要素はパラメータについてのより詳細な情報を持ち、 1、2もしくは3要素を含むタプルでなければならない。

第一要素はパラメータについてのフラグを含んだ整数です。

1
入力パラメータを関数に指定します。

2
出力パラメータ。外部関数が値を書き込みます。

4
デフォルトで整数ゼロになる入力パラメータ。

オプションの第二要素はパラメータ名の文字列です。これが指定された場合は、 外部関数を名前付きパラメータで呼び出すことができます。

オプションの第三要素はこのパラメータのデフォルト値です。

この例では、デフォルトパラメータと名前付き引数をサポートするために Windows MessageBoxA関数をラップする方法を示します。 windowsヘッダファイルのCの宣言はこれです:

WINUSERAPI int WINAPI
MessageBoxA(
    HWND hWnd ,
    LPCSTR lpText,
    LPCSTR lpCaption,
    UINT uType);

ctypesを使ってラップします:

>>> from ctypes import c_int, WINFUNCTYPE, windll
>>> from ctypes.wintypes import HWND, LPCSTR, UINT
>>> prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT)
>>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", None), (1, "flags", 0)
>>> MessageBox = prototype(("MessageBoxA", 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インスタンスを返します。

さらに出力処理やエラーチェックを行うために、出力パラメータをerrcheckプロトコルと 組み合わせることができます。win32 GetWindowRect api関数は成功したか失敗したかを 知らせるためにBOOLを返します。そのため、この関数はエラーチェックを行って、 api呼び出しが失敗した場合に例外を発生させることができます:

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

errcheck関数が変更なしに受け取った引数タプルを返したならば、 ctypesは出力パラメータに対して通常の処理を続けます。 RECTインスタンスの代わりにwindow座標のタプルを返してほしいなら、 関数のフィールドを取り出し、代わりにそれらを返すことができます。 通常処理はもはや行われないでしょう:

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

ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。