ArgumentError when trying to pass an array of unsigned char

0

Working with Python 3.8, I am trying to call the following function of a C dll:

extern void* __stdcall Reentrante_CreerNouvelleIdentification
                (
                int NumeroDuCapteur ,
                DetectorType_t  DetectorType,
                float DetectorVolume,
                float Resolution,
                float ResolutionCzt,
                float C1 , 
                float C2 , 
                float C3 , 
                float C4 , 
                unsigned char CustomLibrary[NB_ISOTOPES_CANDIDAT],  
                float FeThick,                  
                float CdThick,              
                float PbThick,                  
                int maxIsoPourReportingIdent, 
                const char* BkgPath
                    );

Using the following Python code:

# Read dll with Python.

import os
import ctypes as ct

WorkFolder = "C:/Data/SOFTS/SMI_5510"
os.add_dll_directory(WorkFolder)
SIA = ct.cdll.LoadLibrary("SIA_Identification.dll")

n = 70
CustomLib = ct.c_ubyte*n
tab = [0]*n

# Calling Reentrante_CreerNouvelleIdentification.
SIA.Reentrante_CreerNouvelleIdentification.restype = ct.c_void_p
SIA.Reentrante_CreerNouvelleIdentification.argtypes = [ct.c_int,
                                                       ct.c_int, ct.c_float, ct.c_float, ct.c_float,
                                                       ct.c_float, ct.c_float, ct.c_float, ct.c_float,
                                                       ct.c_ubyte, 
                                                       ct.c_float, ct.c_float, ct.c_float,
                                                       ct.c_int, ct.c_char_p]

s = SIA.Reentrante_CreerNouvelleIdentification(666,
    0, 250, 7.5, 12.5,   
    1, 0, 0, 0,    
    CustomLib(*tab), 
    0, 0, 0,   
    5, None) 

I get the following error message telling me that my CustomLib array is not correctly defined:

Traceback (most recent call last):

  File "C:\Users\xxxx\Desktop\code.py", line 23, in <module>
    s = SIA.Reentrante_CreerNouvelleIdentification(666,

ArgumentError: argument 10: <class 'TypeError'>: wrong type

What is the correct type?

Update

I changed my Python code as follows based on Mark Tolonen's answer:

# Read dll with Python.

import os
import ctypes as ct

WorkFolder = "C:/Data/SOFTS/SMI_5510"
os.add_dll_directory(WorkFolder)
SIA = ct.WinDLL("C:/Data/SOFTS/SMI_5510/SIA_Identification.dll")

n = 70
CustomLib = ct.c_ubyte*n
tab = [0]*n

# Calling Reentrante_CreerNouvelleIdentification.
SIA.Reentrante_CreerNouvelleIdentification.restype = ct.c_void_p
SIA.Reentrante_CreerNouvelleIdentification.argtypes = [ct.c_int,
                                                       ct.c_int, ct.c_float, ct.c_float, ct.c_float,
                                                       ct.c_float, ct.c_float, ct.c_float, ct.c_float,
                                                       ct.POINTER(ct.c_ubyte), 
                                                       ct.c_float, ct.c_float, ct.c_float,
                                                       ct.c_int, ct.c_char_p]

s2 = SIA.Reentrante_CreerNouvelleIdentification(666,
    0, 250, 7.5, 12.5,   
    1, 0, 0, 0,    
    CustomLib(*tab), 
    0, 0, 0,   
    5, None) 

I now get the following error:

Traceback (most recent call last):

  File "C:\Users\xxxx\Desktop\code.py", line 23, in <module>
    s2 = SIA.Reentrante_CreerNouvelleIdentification(666,

OSError: exception: access violation writing 0x00000014
python
ctypes
asked on Stack Overflow Aug 9, 2020 by El Pacificador • edited Aug 10, 2020 by El Pacificador

1 Answer

1

CustomLibrary is an array (unsigned char CustomLibrary[NB_ISOTOPES_CANDIDAT]), but arrays decay to pointers in parameters, so the correct type could be ct.POINTER(ct.c_ubyte), although CustomLib could be used as well. Python will do the additional size checking on the input if an array is used, but will still marshal a pointer.

As an aside, a __stdcall function should use WinDLL instead of CDLL, but you won't see an issue using the wrong one on 64-bit Python where there is only one calling convention. Below would work on 32-bit Python as well:

SIA = ct.WinDLL("C:/Data/SOFTS/SMI_5510/SIA_Identification.dll")

Example:

test.cpp

#include <stdio.h>

extern "C" {

typedef int DetectorType_t;

#define NB_ISOTOPES_CANDIDAT 70

__declspec(dllexport)
extern void* __stdcall Reentrante_CreerNouvelleIdentification(
    int NumeroDuCapteur,
    DetectorType_t DetectorType,
    float DetectorVolume,
    float Resolution,
    float ResolutionCzt,
    float C1,
    float C2,
    float C3,
    float C4,
    unsigned char CustomLibrary[NB_ISOTOPES_CANDIDAT],
    float FeThick,
    float CdThick,
    float PbThick,
    int maxIsoPourReportingIdent,
    const char* BkgPath)
{
    printf("%s\n",CustomLibrary);
    return nullptr;
}

}

test.py

import os
import ctypes as ct

SIA = ct.WinDLL('./test')

n = 70
CustomLib = ct.c_ubyte * n
tab = [104,101,108,108,111] # byte values of ASCII 'hello'

SIA.Reentrante_CreerNouvelleIdentification.restype = ct.c_void_p
SIA.Reentrante_CreerNouvelleIdentification.argtypes = (
    ct.c_int, ct.c_int, ct.c_float, ct.c_float, ct.c_float,
    ct.c_float, ct.c_float, ct.c_float, ct.c_float,
    ct.POINTER(ct.c_ubyte),
    ct.c_float, ct.c_float, ct.c_float, ct.c_int, ct.c_char_p)

s = SIA.Reentrante_CreerNouvelleIdentification(
    666, 0, 250, 7.5, 12.5,
    1, 0, 0, 0,
    CustomLib(*tab),
    0, 0, 0, 5, None)

Output:

C:\>test.py
hello
answered on Stack Overflow Aug 9, 2020 by Mark Tolonen • edited Aug 10, 2020 by Mark Tolonen

User contributions licensed under CC BY-SA 3.0