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 に答える