Структура PInvoke с вложенным массивом структур

Я пытаюсь вызвать метод PInvoke, который имеет параметр структуры с указателем вложенного массива структуры. С заявлением выглядит следующим образом:

       duckdb_state duckdb_query(duckdb_connection connection, const char *query, duckdb_result *out_result);

typedef struct {
    void *data;
    bool *nullmask;
    duckdb_type type;
    char *name;
} duckdb_column;

typedef struct {
    idx_t column_count;
    idx_t row_count;
    duckdb_column *columns;
    char *error_message;
} duckdb_result;

Я объявил их на C# так:

       [DllImport("duckdb.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_query")]
public static extern DuckdbState DuckdbQuery(IntPtr connection, string query, out DuckdbResult result);

    [StructLayout(LayoutKind.Sequential)]
    public struct DuckdbColumn
    {
        IntPtr data;
        bool nullmask;  
        DuckdbType type;
        string name;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DuckdbResult
    {
        public long column_count;
        public long row_count;

        public IntPtr columns;
        public string error_message;
    }

Но когда я пытаюсь выполнить запрос и прочитать столбцы, я не получаю никаких значимых данных:

       result = DuckdbQuery(connection, "SELECT * FROM integers", out queryResult);

DuckdbColumn[] columns = new DuckdbColumn[queryResult.column_count];
var queryResultColumns = queryResult.columns;
            
var columnPointer = Marshal.ReadIntPtr(queryResultColumns);
var ptrToStructure = (DuckdbColumn)Marshal.PtrToStructure(columnPointer, typeof(DuckdbColumn));

Как мне изменить объявления PInvoke, чтобы я мог читать столбцы после выполнения запроса?

Пример кода c: Пример DuckDB c

Обновление 1

Я могу получить имена столбцов с помощью следующего кода:

       for (int i = 0; i < queryResult.column_count; i++)
{
    var column = (DuckdbColumn)Marshal.PtrToStructure(queryResult.columns + 8 + (Marshal.SizeOf<DuckdbColumn>() + 8) * i, typeof(DuckdbColumn));
    columns[i] = column;
}

но type поле все еще говорит DUCKDB_TYPE_INVALID

Обновление 2

Как предложил Дэвид в своем ответе, я изменил bool nullmask;к IntPtr nullmask; и теперь я могу читать информацию о столбцах следующим образом:

       for (int i = 0; i < queryResult.column_count; i++)
{
    var column = (DuckdbColumn)Marshal.PtrToStructure(queryResult.columns + Marshal.SizeOf<DuckdbColumn>() * i, typeof(DuckdbColumn));
    columns[i] = column;
}

1 ответ

Решение

Вы неправильно перевели это поле

bool *nullmask

Это не boolэто указатель. Объявите это как

IntPtr nullmask;

Могут быть и другие ошибки, потому что мы не видим все переводы. Кроме того, +8 в вашем массиве арифметика указателя доступа выглядит подозрительно.

Другие вопросы по тегам