I wrote a wrapper around a binary file (libmpsse) for use in Windows (there already exists a wrapper around this binary, but only for Linux) while maintaining compatability for an existing wrapper around a related binary (ftd2xx). This uses WinDLL to load the library (trimmed out the bit that finds the dll path):
from ctypes import (
CFUNCTYPE,
POINTER,
Structure,
c_char,
c_char_p,
c_int,
c_ubyte,
c_uint32,
c_int32,
c_ulong,
c_ulonglong,
c_void_p,
c_long
)
BOOL = c_long
DWORD = c_ulong
HANDLE = c_void_p
LPVOID = c_void_p
STRING = c_char_p
UCHAR = c_ubyte
PUCHAR = POINTER(c_ubyte)
PVOID = c_void_p
LPTSTR = STRING
LPDWORD = POINTER(DWORD)
LPUWORD = POINTER(c_uint32)
VOID: None = None
ULONGLONG = c_ulonglong
FT_HANDLE = c_void_p
FT_STATUS = c_ulong
from ctypes import WinDLL
_libraries["libmpsse.dll"] = WinDLL(str(dll_path))
import_done = True
if import_done:
from ftd2xx._ftd2xx import _ft_device_list_info_node
I2C_GetNumChannels = _libraries["libmpsse.dll"].I2C_GetNumChannels
I2C_GetNumChannels.argtypes = [LPUWORD]
I2C_GetNumChannels.restype = FT_STATUS
I2C_GetChannelInfo = _libraries["libmpsse.dll"].I2C_GetChannelInfo
I2C_GetChannelInfo.argtypes = [c_uint32, POINTER(_ft_device_list_info_node)]
I2C_GetChannelInfo.restype = FT_STATUS
I2C_OpenChannel = _libraries["libmpsse.dll"].I2C_OpenChannel
I2C_OpenChannel.argtypes = [c_uint32, POINTER(FT_HANDLE)]
I2C_OpenChannel.restype = FT_STATUS
class _ft_channel_config(Structure):
_fields_ = [
("ClockRate", c_int32, 32),
("LatencyTimer", c_ubyte, 8),
("Options", c_uint32, 32),
]
I2C_InitChannel = _libraries["libmpsse.dll"].I2C_InitChannel
I2C_InitChannel.argtypes = [FT_HANDLE, POINTER(_ft_channel_config)]
I2C_InitChannel.restype = FT_STATUS
I2C_CloseChannel = _libraries["libmpsse.dll"].I2C_CloseChannel
I2C_CloseChannel.argtypes = [FT_HANDLE]
I2C_CloseChannel.restype = FT_STATUS
I2C_DeviceRead = _libraries["libmpsse.dll"].I2C_DeviceRead
I2C_DeviceRead.argtypes = [FT_HANDLE, c_uint32, c_uint32, LPVOID, LPUWORD, c_uint32]
I2C_DeviceRead.restype = FT_STATUS
I2C_DeviceWrite = _libraries["libmpsse.dll"].I2C_DeviceWrite
I2C_DeviceWrite.argtypes = [FT_HANDLE, c_uint32, c_uint32, LPVOID, LPUWORD, c_uint32]
I2C_DeviceWrite.restype = FT_STATUS
FT_WriteGPIO = _libraries["libmpsse.dll"].FT_WriteGPIO
FT_WriteGPIO.argtypes = [FT_HANDLE, c_uint32, c_uint32]
FT_WriteGPIO.restype = FT_STATUS
FT_ReadGPIO = _libraries["libmpsse.dll"].FT_ReadGPIO
FT_ReadGPIO.argtypes = [FT_HANDLE, PUCHAR]
FT_ReadGPIO.restype = FT_STATUS
Init_libMPSSE = _libraries["libmpsse.dll"].Init_libMPSSE
Init_libMPSSE.restype = None
Cleanup_libMPSSE = _libraries["libmpsse.dll"].Cleanup_libMPSSE
Cleanup_libMPSSE.restype = None
This has been functional, but when my application is closed, there are 17 messages of GetProcAddress failed: 0x7f
. This is messing with some of our workflows and other processes. I assume it has something to do with some cleanup on exit for the WinDLL object, but I can't find where this might be happening to debug further. Moreover it is confusing as number of times it shows up doesn't correlate with anything within the code as I'm only using 11 functions.
Edit: The problem occurs from just importing this file. To boil the down problem down to it's most simple case I have been running a file like this:
if __name__ == "__main__":
print("Main Started")
import libmpsse
print("Import Done")
I can execute the methods and they perform the task(s) specified. I didn't include this code because the error is not caused by calling the methods as shown by the above example. The output for this file as shown in visual studio is this (VS is adding the thread/process exit information, if run in a terminal they are not present):
Main Started
Import DoneThe thread 'MainThread' (0x1) has exited with code 0 (0x0).
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
GetProcAddress failed: 0x7f
The program 'python.exe' has exited with code 0 (0x0).