Python の ctypes ライブラリを使用して、スキャン ライブラリSANEのいくつかのメソッドにアクセスしようとしています。これは ctypes の私の最初の経験であり、1 年以上にわたって C データ型を扱わなければならなかったのは初めてなので、ここにはかなりの学習曲線がありますが、この特定の宣言がなくても、この特定の宣言は面倒だと思います:
extern SANE_Status sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only);
まず、SANE_Status
(enum) とSANE_Bool
(typedef to c_int
) の処理に成功しました。どちらもシンプルでした。一方、その最初のパラメーターは、私にあらゆる種類の悲しみを引き起こしています. そもそも" " 表記に慣れていない***
ため、これまでのトレーサー弾はガベージ データしか生成しませんでした。Python 構造オブジェクトのリストを読み戻せるように、この関数への入力をフォーマットするにはどうすればよいですか? 参考までに、参照されている C 構造体は次のとおりです。
typedef struct
{
SANE_String_Const name; /* unique device name */
SANE_String_Const vendor; /* device vendor string */
SANE_String_Const model; /* device model name */
SANE_String_Const type; /* device type (e.g., "flatbed scanner") */
}
SANE_Device;
どこSANE_String_Const
で として定義されていc_char_p
ます。
このオブジェクトの私の Python/ctypes バージョンは次のとおりです。
class SANE_Device(Structure):
_fields_ = [
("name", c_char_p),
("vendor", c_char_p),
("model", c_char_p),
("type", c_char_p)]
これから期待される動作(構造オブジェクトのリスト)を取得できるように、何を渡す必要があるかについての提案はありますか?すべての回答に感謝します。
更新 1:
以下を使用して、正しい SANE_Device Python 構造を取得できました。
devices = pointer(pointer(pointer(SANE_Device())))
status = libsane.sane_get_devices(devices, c_int(0))
print status, devices, devices.contents.contents.contents.name
ただし、1) うーん、2) 結果が 1 つしかない場合にのみ機能するようです。devices.contents.contents
またはで len() を実行できませんdevices.contents.contents.contents
。結果の数を決定するにはどうすればよいですか? SANE のドキュメントでは、「関数が正常に実行された場合、*device_list 内の SANE_Device 構造へのポインタの NULL 終了配列へのポインタを格納する」と指定されています。提案?
更新 2:
10 項目の配列を渡し、次を使用して最初の要素にアクセスできました。
devices = pointer(pointer(pointer((SANE_Device * 10)())))
status = libsane.sane_get_devices(devices, c_int(0))
print status, devices, devices.contents.contents.contents[0].name
ただし、10 は明らかに恣意的な数であり、実際の結果の数を決定する方法はありません。devices.contents.contents.contents[1].name
デバイスが 1 つしか接続されていないときにアクセスしようとすると、セグメンテーション フォールトが発生します。ctypes では、このような可変長構造を処理する適切な方法が必要です。