Im trying to populate a struct containing multiple layers of other structs from c using c#. I am very confused on how to create the structs in c# using marshalling. I have been looking at a lot of different examples but I haven't managed to get it working since the examples seem much more simple then the following structure.
I have tried the following but no luck so far.
The structs in c are defined as the following where I want to create a DATASET object i c#.
struct DATASET {
uint64_t n_tables;
uint64_t n_columns;
uint64_t n_segments;
uint64_t n_records;
struct DATATABLE **table;
};
struct DATATABLE {
unsigned int n_headers;
uint64_t n_columns;
uint64_t n_segments;
uint64_t n_records;
struct DATASEGMENT **segment;
};
struct DATASEGMENT {
uint64_t n_rows;
uint64_t n_columns;
double **data;
char *label;
char *header;
char **text;
};
I have tried the following in c#
[StructLayout(LayoutKind.Sequential)]
public class DATASET
{
public ulong n_tables;
public ulong n_columns;
public ulong n_segments;
public ulong n_records;
public DATATABLE[] table;
}
[StructLayout(LayoutKind.Sequential)]
public class DATATABLE
{
public uint n_headers;
public ulong n_columns;
public ulong n_segments;
public ulong n_records;
public DATASEGMENT[] segment;
}
[StructLayout(LayoutKind.Sequential)]
public class DATASEGMENT
{
public ulong n_rows;
public ulong n_columns;
public double[][] data;
[MarshalAs(UnmanagedType.LPStr)] public string label;
[MarshalAs(UnmanagedType.LPStr)] public string header;
[MarshalAs(UnmanagedType.LPStr)] public List<string> text;
}
And for creating the struct in c# i have used
[DllImport("Name_of_dll.dll")]
public static extern void print_dataset(DATASET D, int n_lines);
static void Main(string[] args)
{
DATATABLE[] table_array = { new DATATABLE { n_headers = 23 }, new DATATABLE { n_headers = 3 } };
DATASET D = new()
{
n_tables = 1,
n_columns = 3,
n_segments = 1,
n_records = 9,
table = table_array,
};
print_dataset(D, 2);
}
For testing the created structure in c# i have used the following function from c
extern __declspec(dllexport) void print_dataset(struct DATASET* D, int n_lines);
void print_dataset(struct DATASET* D, int n_lines)
{
// Works
printf_s("n_tables = %" PRIu64 ", n_columns = %" PRIu64 ", n_segments = %" PRIu64 ", n_records = %" PRIu64 "\n", D->n_tables, D->n_columns, D->n_segments, D->n_records);
// Works
printf_s("n_lines = %d\n", n_lines);
// Crashes whes it tries to get n_columns
printf_s("D->table[0]->n_columns = %" PRIu32 "\n", D->table[0]->n_headers);
// I haven't gotten this far yet
for (int i = 0; i < n_lines; i++) {
printf_s("%d | ", i);
for (int j = 0; j < D->n_columns; j++) {
printf_s("%f ", D->table[0]->segment[0]->data[j][i]);
}
printf_s("\n");
}
}
The problem is that it works until i hit the table struct where the program then crashes. The output i get is:
n_tables = 1, n_columns = 3, n_segments = 1, n_records = 9
n_lines = 2
Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Repeat 2 times:
at COMPLEX_STRUCT.Program.print_dataset(C_SHARP.DATASET, Int32)
at COMPLEX_STRUCT.Program.Main(System.String[])
I am still pretty new to marshalling and c# in general and don't really understand what is wrong.