atc3dg.dll によってエクスポートされたシンボルは、cdecl では珍しい先頭のアンダースコアを使用します。ffi.cdef
ctypes で行ったのと同じように、で使用される定義にアンダースコアを追加する必要があります。
import cffi
ffi = cffi.FFI()
ffi.cdef('''
enum MESSAGE_TYPE
{
SIMPLE_MESSAGE, // short string describing error code
VERBOSE_MESSAGE, // long string describing error code
};
int _InitializeBIRDSystem(void);
int _GetErrorText(
int errorCode,
char *pBuffer,
int bufferSize,
enum MESSAGE_TYPE type
);
''')
lib = ffi.dlopen('atc3dg.dll')
buf = ffi.new('char[100]')
err = lib._InitializeBIRDSystem()
lib._GetErrorText(err, buf, len(buf), lib.SIMPLE_MESSAGE)
print(ffi.string(buf).decode('ascii'))
# output:
# System : No BIRDs were found anywhere
C コンパイラが構成されている場合は、ffi.verify()
. 私はcffiの経験があまりないので(まだですが、有望に見えます)、これを一粒の塩で考えてください。
ヘッダーを少し変更する必要がありました。の定義ではCOMMUNICATIONS_MEDIA_PARAMETERS
、500 行目enum
に次のように追加する必要があります。
enum COMMUNICATIONS_MEDIA_TYPE mediaType;
また、参考までに、コンパイラは「' ' から ' unsigned __int64
' への変換unsigned short
、データ損失の可能性」などのいくつかの警告を出力しました。拡張モジュールの生成されたソースでは、これについてフォローアップしていません。
import os
import cffi
import subprocess
pth = os.path.abspath(os.path.dirname(__file__))
os.environ['PATH'] += ';%s' % pth
# preprocess: modify this for your compiler
# Using Microsoft's cl.exe that comes with VC++.
# cdef chokes on __declspec, so define DEF_FILE.
cmd = 'cl.exe /DDEF_FILE /EP %s' % os.path.join(pth, 'atc3dg.h')
hdr = subprocess.check_output(cmd, universal_newlines=True)
ffi = cffi.FFI()
ffi.cdef(hdr)
# using __declspec(dllimport) links more efficiently,
# but skipping it still works fine
lib = ffi.verify(hdr, library_dirs=[pth], libraries=['atc3dg'])
buf = ffi.new('char[100]')
err = lib.InitializeBIRDSystem()
lib.GetErrorText(err, buf, len(buf), lib.SIMPLE_MESSAGE)
print(ffi.string(buf).decode('ascii'))
# output:
# System : No BIRDs were found anywhere
プラス面として、このアプローチは先頭のアンダースコアを回避します。これは、拡張モジュールのコンパイル時にリンカーによって処理される ABI の詳細です。