Files
XYParser/CSharp调用说明.md

238 lines
6.2 KiB
Markdown
Raw Normal View History

2026-06-06 10:07:53 +08:00
# XYParser 的 C# 调用说明
## 1. 项目现状
当前工程已经是一个 **C++ 原生 DLL**,不是 .NET DLL。
C# 调用它的推荐方式是使用 **P/Invoke**
相关接口定义见:
- [XYParserApi.h](file:///c:/Users/xyyl666/Desktop/XYParser/XYParser/XYParserApi.h#L12-L40)
- [XYParserApi.cpp](file:///c:/Users/xyyl666/Desktop/XYParser/XYParser/XYParserApi.cpp#L59-L154)
当前主要导出函数:
- `XYParser_CreateParser`
- `XYParser_DestroyParser`
- `XYParser_SetAdcParams`
- `XYParser_SetBypassChecksum`
- `XYParser_Feed`
- `XYParser_GetLastError`
## 2. 使用方式
### 2.1 先编译 DLL
在 Visual Studio 中打开:
- [XYParser.sln](file:///c:/Users/xyyl666/Desktop/XYParser/XYParser/XYParser.sln)
建议编译配置:
- `Release | x64`
编译后得到:
- `XYParser.dll`
运行 C# 程序时,需要把 `XYParser.dll` 放到:
- C# 可执行程序同目录
- 或系统可搜索到的 DLL 路径中
## 3. C# P/Invoke 声明
```csharp
using System;
using System.Runtime.InteropServices;
internal static class NativeMethods
{
private const string DllName = "XYParser.dll";
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr XYParser_CreateParser(byte channel_count);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern void XYParser_DestroyParser(IntPtr handle);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern void XYParser_SetAdcParams(IntPtr handle, double vref, double gain);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern void XYParser_SetBypassChecksum(IntPtr handle, int bypass);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern int XYParser_Feed(
IntPtr handle,
byte[] data,
UIntPtr size,
[Out] XYParserFrameSummary[] outSummaries,
int maxSummaries);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr XYParser_GetLastError(IntPtr handle);
}
```
## 4. 结构体定义
C++ 中的结构体定义见:
- [XYParserFrameSummary](file:///c:/Users/xyyl666/Desktop/XYParser/XYParser/XYParserApi.h#L21-L29)
对应的 C# 写法:
```csharp
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct XYParserFrameSummary
{
public uint frame_index;
public byte channel_count;
public byte battery;
public byte sample_count;
// C++: double channel_values_uv[5][64]
// C#: 按一维数组接收,总长度 = 5 * 64
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5 * 64)]
public double[] channel_values_uv;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public byte[] trigger_types;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public byte[] trigger_indices;
}
```
## 5. 调用示例
```csharp
using System;
using System.IO;
using System.Runtime.InteropServices;
class Program
{
static void Main()
{
IntPtr handle = NativeMethods.XYParser_CreateParser(8);
if (handle == IntPtr.Zero)
{
throw new Exception("创建解析器失败");
}
try
{
NativeMethods.XYParser_SetAdcParams(handle, 4.5, 6.0);
NativeMethods.XYParser_SetBypassChecksum(handle, 1);
byte[] input = File.ReadAllBytes("test.bin");
XYParserFrameSummary[] summaries = new XYParserFrameSummary[8];
for (int i = 0; i < summaries.Length; i++)
{
summaries[i].channel_values_uv = new double[5 * 64];
summaries[i].trigger_types = new byte[5];
summaries[i].trigger_indices = new byte[5];
}
int count = NativeMethods.XYParser_Feed(
handle,
input,
(UIntPtr)input.Length,
summaries,
summaries.Length);
string lastError = Marshal.PtrToStringAnsi(
NativeMethods.XYParser_GetLastError(handle)) ?? "";
Console.WriteLine($"解析出的帧数: {count}");
Console.WriteLine($"最后错误: {lastError}");
if (count > 0)
{
double firstValue = summaries[0].channel_values_uv[0];
Console.WriteLine($"第一帧第一个采样点第一个通道值: {firstValue}");
}
}
finally
{
NativeMethods.XYParser_DestroyParser(handle);
}
}
}
```
## 6. 二维数组取值说明
C++ 中:
```cpp
double channel_values_uv[5][64];
```
C# 中按一维数组接收后,索引方式为:
```csharp
double value = summary.channel_values_uv[sampleIndex * 64 + channelIndex];
```
例如:
-`0` 个采样点,第 `0` 个通道:`[0 * 64 + 0]`
-`1` 个采样点,第 `3` 个通道:`[1 * 64 + 3]`
## 7. 注意事项
- `CallingConvention` 要使用 `Cdecl`
- `XYParser_GetLastError` 返回的是 `const char*`,需用 `Marshal.PtrToStringAnsi`
- C# 程序位数必须和 DLL 一致
- 你当前更适合使用 `x64`
- `channel_count` 当前只支持 `8``64`
## 8. 推荐封装方式
如果后续要长期在 C# 中使用,建议再包一层托管类,例如:
```csharp
public sealed class XYParser : IDisposable
{
private IntPtr _handle;
public XYParser(byte channelCount)
{
_handle = NativeMethods.XYParser_CreateParser(channelCount);
if (_handle == IntPtr.Zero)
throw new InvalidOperationException("创建解析器失败");
}
public void SetAdcParams(double vref, double gain)
{
NativeMethods.XYParser_SetAdcParams(_handle, vref, gain);
}
public void SetBypassChecksum(bool enabled)
{
NativeMethods.XYParser_SetBypassChecksum(_handle, enabled ? 1 : 0);
}
public void Dispose()
{
if (_handle != IntPtr.Zero)
{
NativeMethods.XYParser_DestroyParser(_handle);
_handle = IntPtr.Zero;
}
}
}
```
## 9. 总结
- 当前工程已经能生成原生 `XYParser.dll`
- C# 不需要重写解析逻辑,直接用 `DllImport` 即可调用
- 最关键的是函数声明匹配、结构体布局匹配、位数一致