3

我正在尝试通过 P/Invoke 使用 C# 代码中的 btrieve API 从 Btrieve (v6.15) 数据库中读取记录。

我已经设法读取记录,但是在阅读时会裁剪字符串的最后一个字符。如果我增加数据结构中的字符串大小,那么字符串会被正确读取,但这次下一个变量没有被正确读取。

这里可能有什么问题?

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. 有符号整数,2 个字节
  2. 字符串,15 个字节
  3. 有符号整数,2 个字节
  4. 字符串,15 个字节
  5. 有符号整数,2 个字节
  6. 浮点数,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);
    }

编辑:将字符串更改为 char 数组(感谢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;
    }
4

1 回答 1

1

我认为问题来自使用带有 p/invoke 的 C# 字符串时预期的 \0。
我没有使用 Btrieve 的经验,但很可能没有 \0。
你能发布原始的c结构吗?否则需要使用固定长度为 15 的字节数组,然后将其转换为字符串。
此外,我会使用 sizeof 运算符来比较两端结构的大小。

于 2012-05-10T10:22:33.527 回答