666
This commit is contained in:
237
CSharp调用说明.md
Normal file
237
CSharp调用说明.md
Normal file
@@ -0,0 +1,237 @@
|
||||
# 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` 即可调用
|
||||
- 最关键的是函数声明匹配、结构体布局匹配、位数一致
|
||||
Reference in New Issue
Block a user