Ronan Paixão Ronan Paixão - 23 days ago 6
C Question

How do I build a Type to pass to a DLL function that takes a pointer to a struct with an array inside?

I have a C DLL that defines a struct and a function that takes a pointer to it:

header:

typedef struct {
double arr[10];
double anotherParam;
double result;
} CStruct_t;

int __stdcall CFunction(CStruct_t * c_struct);


source:

int __stdcall CFunction(CStruct_t * c_struct) {
double sum = 0.0;
for (int i = 0; i < 10; ++i) {
sum += c_struct->arr[i];
}
c_struct->result = sum * c_struct->anotherParam;
}


I can properly use the DLL in C in something like:

CStruct_t my_struct = {{0,1,2,3,4,5,6,7,8,9}, 2, 0};
CFunction(&my_struct);
printf("Result = %f ", my_struct.result);


However, I want to use it inside Excel. As such, I tried this in VBA:

Private Declare Function CFunction Lib "cstruct.dll" (ByRef c_struct As CStruct_t) As Long

Type CStruct_t
arr(10) As Double
anotherParam As Double
result As Double
End Type

Sub TryCStruct()
Dim prev_path As String
prev_path = CurDir
ChDir ThisWorkbook.Path
Dim cs As CStruct_t
For i = LBound(cs.arr) To UBound(cs.arr)
cs.arr(i) = i
Next
cs.anotherParam = 2
MsgBox "Retval =" & CFunction(cs)
MsgBox "Result = " & cs.result
ChDir prev_path
End Sub


But despite working, it returns incorrect results (42988244 instead of 90). I presume this is because VBA arrays are SAFEARRAYs instead of fixed-size ones like C, but this page makes me think that fixed-size arrays should be fixed in memory too.

Anyway, I've seen examples of passing the pointer to the data in the array, but I couldn't find anything on using a mixed type.

Is there any way to correctly allocate the memory in VBA and pass the struct pointer to the DLL or must I somehow either manage it all in C or declare each array element as a member of the struct and forget easy indexing in VBA?

Answer

The VBA declaration should be:

Type CStruct_t
    arr(9) As Double
    anotherParam As Double
    result As Double
End Type

The number in the array declaration in VBA is the upper bound (base 0) of the array, not the number of elements like in C. In VBA, arr(10) As Double is equivalent to double arr[11]; in C.

Obligatory demo code:

Sub Bounds()
    Dim foo As CStruct_t, i As Long
    For i = LBound(foo.arr) To UBound(foo.arr)
        Debug.Print i
    Next
End Sub