I am trying to read records from a Btrieve (v6.15) database by using btrieve API from C# code via P/Invoke.
I have managed to read records, however last character of strings are cropped while reading. If I increase the string size in my data struct then the string is read properly but this time the next variable is not read correctly.
What might be wrong here?
Btrieve function declaration:
[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);
My structure definition:
[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;
}
These are the sizes for the columns, from Btreive database manager:
- signed int, 2 bytes
- string, 15 bytes
- signed int, 2 bytes
- string, 15 bytes
- signed int, 2 bytes
- float, 8 bytes
The code:
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);
}
Edit: Changing the string to char array (thanks to weismat's answer) resolved the problem. Happy!
[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;
}