【问题标题】:Memory alignment of struct variables for p/invoke - Strings lose the last characterp/invoke 的结构变量的内存对齐 - 字符串丢失最后一个字符
【发布时间】:2012-05-10 08:08:10
【问题描述】:

我正在尝试通过 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;
    }

【问题讨论】:

    标签: c# interop pinvoke btrieve


    【解决方案1】:

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

    【讨论】:

    • 谢谢!这似乎确实是问题所在。将字符串更改为 char 数组即可解决问题。
    猜你喜欢
    • 1970-01-01
    • 2010-11-18
    • 2023-03-03
    • 2013-03-17
    • 2022-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-06
    相关资源
    最近更新 更多