0

嗨@eryksun 和 Python 专家:

我正在尝试cffi使用以下命令将 dll 文件导入 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 下工作。有什么建议吗?

感谢您查看这个,

埃里克

4

1 回答 1

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;

此外,作为仅供参考,编译器打印了一些警告,例如“从 ' 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 细节。

于 2013-09-13T09:02:31.390 回答