嗨@eryksun和Python专家:
我正在尝试使用以下命令将一个dll文件导入到cffi
的python中:
from cffi import FFI
ffi=FFI()
lib=ffi.dlopen('ATC3DG.DLL')
从前一个关于ctypes的问题,我知道DLL都是cdecl(感谢@ eryksun的提示),我能够以下列方式访问其功能:
from ctypes import *
lib=windll.LoadLibrary('ATC3DG.DLL')
lib._InitializeBIRDSystem
但是,我不确定cffi中的等效操作是什么。 lib._InitializeBIRDSystem
在ctypes下运行,但不在cffi下运行。有什么建议吗?
感谢您查看此内容,
埃里克
答案 0 :(得分:2)
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;
此外,正如一个FYI,编译器打印了一些警告,例如“从'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详细信息。