Hi @eryksun and Python experts:
I am trying to import a dll file into python with cffi
with the following commands:
from cffi import FFI
ffi=FFI()
lib=ffi.dlopen('ATC3DG.DLL')
From a previous question about ctypes, I know that DLL are all cdecl (thanks to @eryksun's hints), and I was able to access its functions in the following fashion:
from ctypes import *
lib=windll.LoadLibrary('ATC3DG.DLL')
lib._InitializeBIRDSystem
However, I am not sure what would be the equivalent operations in cffi. lib._InitializeBIRDSystem
works under ctypes but not cffi. Any suggestion?
Thanks for looking into this,
Erik
The symbols exported by atc3dg.dll use a leading underscore, which is unusual for cdecl. You'll have to add the underscore in the definitions used in ffi.cdef
, just as you did with 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
If you have a C compiler configured, you can use ffi.verify()
. I'm not very experienced with cffi (not yet, but it looks promising), so take this with a grain of salt.
I had to make a small change to the header. In the definition of COMMUNICATIONS_MEDIA_PARAMETERS
, line 500 needs to add enum
as follows:
enum COMMUNICATIONS_MEDIA_TYPE mediaType;
Also, just as an FYI, the compiler printed a few warnings, such as "conversion from 'unsigned __int64
' to 'unsigned short
', possible loss of data". I haven't followed up on this in the generated source for the extension module.
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
On the plus side, this approach avoids the leading underscore. It's an ABI detail handled by the linker when the extension module is compiled.