本日は Python の技術調査枠です。
Python の ctypes で DLL の関数から様々な戻り値を受け取る方法について記事にします。
前回記事の続きです。
bluebirdofoz.hatenablog.com
構造体を受け取る
次に DLL 内で定義した構造体のデータを受け取ってみます。
DLL に以下の通り、構造体を定義します。こちらも参照渡しで構造体型を受け取る関数を追加します。
・TestLib.h
#pragma once #ifdef TESTLIB_EXPORTS #define TESTLIB_API extern "C" __declspec(dllexport) #else #define TESTLIB_API extern "C" __declspec(dllimport) #endif struct vector3 { int x; int y; int z; }; struct databox { int id; char name[10]; vector3 point; }; TESTLIB_API void ReturnStruct(databox*);
・TestLib.cpp
#include "stdafx.h" #include "string.h" // memcpy #include "TestLib.h" void ReturnStruct(databox* return_databox) { vector3 vecter_result; vecter_result.x = 10; vecter_result.y = 30; vecter_result.z = 60; databox databox_result; databox_result.id = 3; strcpy_s(databox_result.name, 10, "TestData"); databox_result.point = vecter_result; memcpy(return_databox, &databox_result, sizeof(databox)); }
次に関数を呼び出す Python スクリプトを修正します。
構造体のデータ構造を Python スクリプト側で Structure の派生クラスとして定義します。
このとき、クラス内のフィールド型は ctypes 型に含まれる型である必要があります。
構造体の中に構造体を定義することも可能です。
class VECTOR3(Structure): _fields_ = [("x", c_int), ("y", c_int), ("z", c_int)] class DATABOX(Structure): _fields_ = [("id", c_int), ("name", c_char * 10), ("point", VECTOR3)]
以下の通り、構造体を受け取って表示するスクリプトを作成しました。
・dllAccesstest05.py
# ctypesインポート from ctypes import * # クラスを定義する class VECTOR3(Structure): _fields_ = [("x", c_int), ("y", c_int), ("z", c_int)] class DATABOX(Structure): _fields_ = [("id", c_int), ("name", c_char * 10), ("point", VECTOR3)] # DLLをロードする dll = cdll.LoadLibrary("TestLib.dll") # 構造体を生成する p_databox = DATABOX() # 引数に構造体を渡して関数を実行する dll.ReturnStruct(byref(p_databox)) # 収納された値を表示する print("ReturnStruct Execute") print(p_databox.id) print(p_databox.name) print(p_databox.point.x) print(p_databox.point.y) print(p_databox.point.z)
実行すると、構造体に代入された値が取得できました。