我正在尝试通过 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 数据库管理器的列的大小:
- 有符号整数,2 字节
- 字符串,15 字节
- 有符号整数,2 字节
- 字符串,15 字节
- 有符号整数,2 字节
- 浮点型,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;
}
我认为问题来自将 C# 字符串与 p/调用一起使用时预期的 \0。
我对 Btrieve 没有经验,但很可能没有 \0。
你能发布原始的 c 结构吗?否则,您需要使用固定长度为 15 的字节数组,然后将其转换为字符串。
此外,我将使用 sizeof 运算符来比较两端结构的大小。