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 细节。