Выравнивание памяти структурных переменных для p / invoke - строки теряют последний символ

Я пытаюсь прочитать записи из базы данных Btrieve (v6.15), используя API btrieve из кода C # через P / Invoke.

Мне удалось прочитать записи, однако при чтении последний символ строк обрезается. Если я увеличиваю размер строки в своей структуре данных, то строка читается правильно, но на этот раз следующая переменная читается некорректно.

Что здесь может быть не так?

Объявление функции Btrieve:

        [DllImport("WBTRV32.dll", CharSet = CharSet.Ansi)]
    static extern short BTRCALL(ushort operation,
        [MarshalAs(UnmanagedType.LPArray, SizeConst = 128)] byte[] posBlk,
        [MarshalAs(UnmanagedType.Struct, SizeConst = 255)] 
        ref RecordBuffer databuffer, 
        ref int dataLength, 
        [MarshalAs(UnmanagedType.LPArray, SizeConst = 255)] char[] keyBffer, 
        ushort keyLength, ushort keyNum);

Определение моей структуры:

    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
    public struct RecordBuffer
    {
        public short docType;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 15)]
        public string docDescPlural;
        public short sorting;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 15)]
        public string docDescSingle;
        public short copyOtherThanSrc;
        public double defaultNotebookNo;
    }

Это размеры столбцов из менеджера баз данных Btreive:

  1. подписанное int, 2 байта
  2. строка, 15 байт
  3. подписанное int, 2 байта
  4. строка, 15 байт
  5. подписанное int, 2 байта
  6. float, 8 байт

Код:

    private void PopulateAllRecords(string fileName)
    {
        byte[] positionBlock = new byte[128];
        char[] fileNameArray = fileName.ToCharArray();

        // Open file
        RecordBuffer dataBuffer = new RecordBuffer();
        int bufferLength = System.Runtime.InteropServices.Marshal.SizeOf(dataBuffer);
        BReturnCodes status = (BReturnCodes) BTRCALL(
            BOPEN, positionBlock, ref dataBuffer, ref bufferLength, fileNameArray, 0, 0);

        if (status == BReturnCodes.NO_ERROR)
        {
            // Get first record
            dataBuffer = new RecordBuffer();
            status = (BReturnCodes) BTRCALL(
                BGETFIRST, positionBlock, ref dataBuffer, ref bufferLength, fileNameArray, 0, 0);

            if (status == BReturnCodes.NO_ERROR)
            {
                AddListViewItem(dataBuffer);
            }

            // Get subsequent records
            while (status == BReturnCodes.NO_ERROR) // BReturnCodes.END_OF_FILE or an error will occur
            {
                dataBuffer = new RecordBuffer();
                status = (BReturnCodes)BTRCALL(
                    BGETNEXT, positionBlock, ref dataBuffer, ref bufferLength, fileNameArray, 0, 0);

                if (status == BReturnCodes.NO_ERROR)
                {
                    AddListViewItem(dataBuffer);                        
                }
            }
        }
        else
        {
            MessageBox.Show("Error occured while opening file: " + status.ToString());
        }
    }

    private void AddListViewItem(RecordBuffer buffer)
    {
        ListViewItem item = new ListViewItem(buffer.docType.ToString());
        item.SubItems.Add(buffer.docDescPlural);
        item.SubItems.Add(buffer.sorting.ToString());
        item.SubItems.Add(buffer.docDescSingle);
        item.SubItems.Add(buffer.copyOtherThanSrc.ToString());
        item.SubItems.Add(buffer.defaultNotebookNo.ToString());
        listView.Items.Add(item);
    }

Изменить: изменение строки на массив символов (благодаря ответу weismat) разрешило проблему. Счастливый!

    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
    public struct RecordBuffer
    {
        public short docType;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
        public char[] docDescPlural;
        public short sorting;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
        public char[] docDescSingle;
        public short copyOtherThanSrc;
        public double defaultNotebookNo;
    }

person Eren    schedule 10.05.2012    source источник


Ответы (1)


Я предполагаю, что проблема возникает из-за \ 0, что ожидается при использовании строки C # с p / invoke.
У меня нет опыта работы с Btrieve, но вполне вероятно, что нет \ 0.
Не могли бы вы разместить исходную структуру c? В противном случае вам нужно использовать массив байтов с фиксированной длиной 15 и впоследствии преобразовать его в строку.
Кроме того, я бы использовал оператор sizeof для сравнения размера структуры на обоих концах.

person weismat    schedule 10.05.2012
comment
Спасибо! Кажется, это действительно проблема. Изменение строки на массив символов решило проблему. - person Eren; 10.05.2012