0

Ive got a similar question to ctypes and array of structs but im not looking to return the structure. Rather, my structure is passed into the function call as a pointer and then i want the values pointed at by the pointer. see below:

from .h:

typedef struct NIComplexNumberF32_struct {
   ViReal32 real;
   ViReal32 imaginary;
} NIComplexNumberF32;

ViStatus _VI_FUNC niRFSA_FetchIQSingleRecordComplexF32(
   ViSession vi,
   ViConstString channelList,
   ViInt64 recordNumber,
   ViInt64 numberOfSamples,
   ViReal64 timeout,
   NIComplexNumberF32* data,
   niRFSA_wfmInfo* wfmInfo);

i have made several attempts, but this was my latest:

import ctypes

class NIComplexNumberF32_struct_data(ctypes.Structure):
    _fields_ = [("real", ctypes.c_float),
                ("imaginary",  ctypes.c_float)]

class niRFSA_wfmInfo_struct_data(ctypes.Structure):
    _fields_ = [("absoluteInitialX", ctypes.c_double),
                ("relativeInitialX",  ctypes.c_double),
                ("xIncrement",  ctypes.c_double),
                ("actualSamples",  ctypes.c_double),
                ("offset",  ctypes.c_double),
                ("gain",  ctypes.c_double),
                ("reserved1",  ctypes.c_double),
                ("reserved2",  ctypes.c_double)                
                ]


# ViStatus _VI_FUNC niRFSA_FetchIQSingleRecordComplexF32(
#    ViSession vi,
#    ViConstString channelList,
#    ViInt64 recordNumber,
#    ViInt64 numberOfSamples,
#    ViReal64 timeout,
#    NIComplexNumberF32* data,
#    niRFSA_wfmInfo* wfmInfo);

#create instances
data = ctypes.POINTER(NIComplexNumberF32_struct_data)()
wfmInfo = ctypes.POINTER(niRFSA_wfmInfo_struct_data)()

dll_path = r"C:\Program Files\IVI Foundation\IVI\bin\NiRFSA_64.dll" 
dll = ctypes.cdll.LoadLibrary(dll_path)
dll.niRFSA_FetchIQSingleRecordComplexF32.argtypes =(ViSession,ViString,ViReal64,ViReal64,ViReal64,ctypes.POINTER(NIComplexNumberF32_struct_data),ctypes.POINTER(niRFSA_wfmInfo_struct_data) )
dll.niRFSA_FetchIQSingleRecordComplexF32(handle,bytes('','ascii'),0,1000,1,data,wfmInfo)

Traceback (most recent call last):
RuntimeError: (-1074134952) IVI: (Hex 0xBFFA0058) Null pointer passed for parameter or attribute.

What i want are the real/imag data values from the array of data structure.

I have got to be missing something dumb. Hoping someone can point me in the right direction.

thanks all!!

1 Answer 1

0

This:

#create instances
data = ctypes.POINTER(NIComplexNumberF32_struct_data)()
wfmInfo = ctypes.POINTER(niRFSA_wfmInfo_struct_data)()

Is equivalent to the following C code:

struct NIComplexNumberF32* = NULL;
struct niRFSA_wfmInfo* = NULL;

It only creates NULL pointers and causes the RuntimeError you see. Instead, create instances of each structure and pass them by address using ctypes.byref().

Here's a working example with a simplfied API since it wasn't provided: test.c

struct NIComplexNumberF32 {
    float real;
    float imaginary;
};

struct niRFSA_wfmInfo {
    double absoluteInitialX;
    double relativeInitialX;
    double xIncrement;
    double actualSamples;
    double offset;
    double gain;
    double reserved1;
    double reserved2;
};

__declspec(dllexport)  // I'm using Windows, so needs this for function export from DLL
void niRFSA_FetchIQSingleRecordComplexF32(struct NIComplexNumberF32* p1, struct niRFSA_wfmInfo* p2) {
    p1->real = 1.5f;
    p1->imaginary = 2.75f;
    p2->absoluteInitialX = 1.5;
    p2->relativeInitialX = 2.5;
    p2->xIncrement = 3.5;
    p2->actualSamples = 4.5;
    p2->offset = 5.5;
    p2->gain = 6.5;
    p2->reserved1 = 0.0;
    p2->reserved2 = 0.0;
}

test.py

import ctypes as ct

class NIComplexNumberF32(ct.Structure):
    _fields_ = (("real", ct.c_float),
                ("imaginary",  ct.c_float))

    # helper to print fields
    def __repr__(self):
        return f'({self.real}{self.imaginary:+}j)'

class niRFSA_wfmInfo(ct.Structure):
    _fields_ = (("absoluteInitialX", ct.c_double),
                ("relativeInitialX",  ct.c_double),
                ("xIncrement",  ct.c_double),
                ("actualSamples",  ct.c_double),
                ("offset",  ct.c_double),
                ("gain",  ct.c_double),
                ("reserved1",  ct.c_double),
                ("reserved2",  ct.c_double))

dll = ct.CDLL('./test')
dll.niRFSA_FetchIQSingleRecordComplexF32.argtypes = ct.POINTER(NIComplexNumberF32), ct.POINTER(niRFSA_wfmInfo)
dll.niRFSA_FetchIQSingleRecordComplexF32.restype = None

data = NIComplexNumberF32(5.125, 7.375)  # If you want to initialize the fields to something besides default
print(data)  # Uses __str__ or _repr__ function for display if defined (in that order)
wfmInfo = niRFSA_wfmInfo()  # Init fields using defaults (0.0 for double type)

# This function doesn't use the input values.
# It returns data in both structures.
dll.niRFSA_FetchIQSingleRecordComplexF32(ct.byref(data), ct.byref(wfmInfo))

print(data)  # Uses defined representation function (__repr__)

# access attributes directly...
print(wfmInfo.absoluteInitialX)
print(wfmInfo.relativeInitialX)
print(wfmInfo.gain)

Output:

(5.125+7.375j)
(1.5+2.75j)
1.5
2.5
6.5
Sign up to request clarification or add additional context in comments.

3 Comments

This gets me closer, but the data in the data array is all zeros. Is there an additional step to extract the data within the pointer? thanks
@pyNewbie Updated answer with a working demo of passing in structures and obtaining data from a DLL.
Hi Mark, I worked through another part o the code and realized that some of the set up prior to this code was incorrect. I fixed that and things started working as they should. But, your answer is correct and should be used i anyone else runs into similar issues. Thanks for your help sir!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.