本日は Python の技術調査枠です。
Python の ctypes で DLL の関数から様々な戻り値を受け取る方法について記事にします。
前回記事の続きです。
bluebirdofoz.hatenablog.com
ctypesの基本データ型
ctypes では以下の C 互換なデータ型が定義されています。
ctypes の型 | C の型 | Python の型 |
---|---|---|
c_bool | _Bool | bool (1) |
c_char | char | 1文字のバイト列オブジェクト |
c_wchar | wchar_t | 1文字の文字列 |
c_byte | char | int |
c_ubyte | unsigned char | int |
c_short | short | int |
c_ushort | unsigned short | int |
c_int | int | int |
c_uint | unsigned int | int |
c_long | long | int |
c_ulong | unsigned long | int |
c_longlong | __int64 または long long | int |
c_ulonglong | unsigned __int64 または unsigned long long | int |
c_size_t | size_t | int |
c_ssize_t | ssize_t または Py_ssize_t | int |
c_float | float | 浮動小数点数 |
c_double | double | 浮動小数点数 |
c_longdouble | long double | 浮動小数点数 |
c_char_p | char * (NUL 終端) | バイト列オブジェクトまたは None |
c_wchar_p | wchar_t * (NUL 終端) | 文字列または None |
c_void_p | void * | 整数または None |
以下の通り、型を呼び出すことで利用します。
値を取り出す場合は .value を呼び出します。
import ctypes x = c_int(123) print(x) print(x.value)
引数に整数型を指定する
試しに前回のプロジェクトを修正し、DLL に以下の long 型を扱う関数を追加します。
・TestLib.h
#pragma once #ifdef TESTLIB_EXPORTS #define TESTLIB_API extern "C" __declspec(dllexport) #else #define TESTLIB_API extern "C" __declspec(dllimport) #endif TESTLIB_API int SumInt(int, int); TESTLIB_API long SumLong(long, long);
・TestLib.cpp
#include "stdafx.h" #include "TestLib.h" int SumInt(int x, int y) { return x + y; } long SumLong(long x, long y) { return x + y; }
次に関数を呼び出す Python スクリプトを修正します。
以下の通り、c_long 型で変数を定義して引数を渡す処理を記述します。
・dllAccesstest02.py
# ctypesインポート from ctypes import * # DLLをロードする dll = cdll.LoadLibrary("TestLib.dll") # long 型の変数を作成する long_x = c_long(100) long_y = c_long(200) # SumInt関数を呼び出して結果を出力する print("SumLong Execute") print(dll.SumLong(long_x, long_y)) print(dll.SumLong(long_x.value, long_y.value))
関数を呼び出すことができ、戻り値の 300 が確認できました。
スクリプトの通り、変数をそのまま受け渡しても .value で受け渡しても正常に動作します。
戻り値の型を取得する
次に戻り値を変数で取得し、その型を確認してみます。
# ctypesインポート from ctypes import * # DLLをロードする dll = cdll.LoadLibrary("TestLib.dll") # long 型の変数を作成する long_x = c_long(100) long_y = c_long(200) # 戻り値を変数で取得する long_sum = dll.SumLong(long_x, long_y) # 型と値を確認する print("SumLong Execute") print(type(long_sum)) print(long_sum)
すると以下の通り、戻り値は c_long 型ではなく int 型で取得されていることが分かります。
SumLong Execute <class 'int'> 300
関数の戻り値の型をスクリプト中で確認したい場合は関数の .restype の参照を利用することで可能です。
・dllAccessTest03.py
# ctypesインポート from ctypes import * # DLLをロードする dll = cdll.LoadLibrary("TestLib.dll") # 関数の戻り値の型を確認する print(dll.SumLong.restype)
以下の通り、c_long の戻り値の型が示されます。
<class 'ctypes.c_long'>