如何用cffi调用__cdel修饰函数?

时间:2013-09-13 02:19:14

标签: python dll python-cffi

嗨@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下运行。有什么建议吗?

感谢您查看此内容,

埃里克

1 个答案:

答案 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详细信息。