Python 3 calling external DLL with custom data type

0

I'm trying to call an external DLL with the following header definition in C.

typedef long            EPC_INT32;
typedef void*           EPC_ADDR32;
typedef struct {EPC_CHAR a [16];} EPC_Str16;

typedef struct
{
   EPC_INT32 UseUSB;
   EPC_INT32 BoardNumber;
   EPC_INT32 FIFOSamples;
   EPC_INT32 MaxProbes;
   EPC_Str16 DeviceNumber;
   EPC_Str16 SerialNumber;
   EPC_INT32 ExternalScaling;
   EPC_ADDR32 DacScaling;
   EPC_ADDR32 AdcScaling;
} LIH_OptionsType;

typedef LIH_OptionsType* LIH_OptionsPtr;

EPC_INT32 EPC_Calling LIH_InitializeInterface(
            EPC_Str256Ptr ErrorMessage,
            EPC_INT32 Amplifier, 
            EPC_INT32 ADBoard,
            LIH_OptionsPtr OptionsPtr,
            EPC_INT32 OptionsSize ) EPC_Import;


Python code:

import ctypes
import sys

class LIH_Options(ctypes.Structure):
    _fields_ = [("UseUSB",          ctypes.c_int32) ,
                ("BoardNumber",     ctypes.c_int32),
                ("FIFOSamples",     ctypes.c_int32),
                ("MaxProbes",       ctypes.c_int32),
                ("DeviceNumber",    ctypes.c_wchar_p),
                ("SerialNumber",    ctypes.c_wchar_p),
                ("ExternalScaling", ctypes.c_int32),
                ("DataScaling",     ctypes.c_void_p),
                ("AdcScaling",      ctypes.c_void_p)]

OptionsSize = sys.getsizeof(LIH_Options)

my_LIH_Options = LIH_Options(0,0,1024,0,'','',0, 0,0)  #create an instance

EPC = ctypes.WinDLL('EpcDLL.dll')


EPC.LIH_InitializeInterface.argtypes = [ctypes.c_char_p,
                                        ctypes.c_int32, ctypes.c_int32,
                                        ctypes.POINTER(LIH_Options),
                                        ctypes.c_int32]

szErrMssg  = ctypes.create_string_buffer(256)

status = EPC.LIH_InitializeInterface(szErrMssg, 0, 3, my_LIH_Options, OptionsSize)

This returns a Tracback error: status = EPC.LIH_InitializeInterface(szErrMssg, 0, int(LIH.Board), my_LIH_Options, OptionsSize) OSError: exception: access violation writing 0xFFFFFFFF

If the call is replaced by

status = EPC.LIH_InitializeInterface(szErrMssg, 0, 3, None, OptionsSize)

it works, with the default values for LIH_Options. So the problem is in passing the data type LIH_Options.

python
dll
types
ctypes
asked on Stack Overflow Oct 9, 2020 by Steve Cannon • edited Oct 10, 2020 by Mark Tolonen

1 Answer

0

The array type and size of structure were incorrect. This should work but untested as I don't have your DLL. None is typically used for NULL pointers but 0 should work too. Use byte strings (b'') for a char array.

import ctypes

# define the types for easier match to original C structure.
EPC_INT32 = ctypes.c_int32;
EPC_ADDR32 = ctypes.c_void_p; # Only 32-bit on a 32-bit OS.
EPC_CHAR = ctypes.c_char;     # Assumption...not defined in question
EPC_Str16 = EPC_CHAR * 16;    # Correct type of char[16] array

class LIH_Options(ctypes.Structure):
    _fields_ = [("UseUSB",          EPC_INT32),
                ("BoardNumber",     EPC_INT32),
                ("FIFOSamples",     EPC_INT32),
                ("MaxProbes",       EPC_INT32),
                ("DeviceNumber",    EPC_Str16),
                ("SerialNumber",    EPC_Str16),
                ("ExternalScaling", EPC_INT32),
                ("DataScaling",     EPC_ADDR32),
                ("AdcScaling",      EPC_ADDR32)]

OptionsSize = ctypes.sizeof(LIH_Options)  # sys.getsizeof returns size of Python object, not C

my_LIH_Options = LIH_Options(0,0,1024,0,b'',b'',0,None,None)  #create an instance
EPC = ctypes.WinDLL('EpcDLL.dll')
EPC.LIH_InitializeInterface.argtypes = [ctypes.c_char_p,
                                        EPC_INT32, EPC_INT32,
                                        ctypes.POINTER(LIH_Options),
                                        EPC_INT32]
szErrMssg  = ctypes.create_string_buffer(256)
status = EPC.LIH_InitializeInterface(szErrMssg, 0, 3, my_LIH_Options, OptionsSize)
answered on Stack Overflow Oct 10, 2020 by Mark Tolonen

User contributions licensed under CC BY-SA 3.0