gpt4 book ai didi

C#调用具有复杂结构的deviceIOControl

转载 作者:行者123 更新时间:2023-11-28 02:46:03 24 4
gpt4 key购买 nike

所以我正在尝试编写一个 C# 包装器来与我们的一个设备驱动程序对话。 (创建单元测试)驱动程序是新的,但是针对旧的 c++ header 进行编码,因此定义了结构布局,并且不能真正更改。

所以我已经复制了设备期望 DeviceIOControl 传入的 c++ 结构。

更新 #3 - 将代码更改为具有相同问题的演示代码。同时清理问题以供其他人使用,请参阅下面的答案

[StructLayout(LayoutKind.Sequential, Pack=1)]
public class Points
{
public int id;

[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
public int[] x = new int[10];
[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
public int[] y = new int[10];
};

[StructLayout(LayoutKind.Sequential, Pack=1)]
public class Shape
{
public int name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
public Points[] p = new Points[10];
};

[StructLayout(LayoutKind.Sequential,Pack1)]
public class GeoShape:Shape
{
public int top;
public int left;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
public int[] v = new int[10];
};

我对 deviceIOControl 的调用失败了,因为在驱动程序端它检查传入的缓冲区的大小。在 C# 端,我的对象太小了 Marshal.SizeOf( ) 返回 52 作为大小,而当它应该是 852 时,如果我将 Size= 添加到 StructLayout 属性,该函数将“通过”,但我相当确定数据没有被正确传递。

我相当确定问题出在这个 public Points[] p = new Points[10]; 我认为 Marshal.StructToPtr() 没有正确编码它,因为它本质上是一个多维数组.

所以我想我的问题是这甚至可能吗? 似乎 C# 可能足够聪明,知道如何在内存中为该结构数组创建适量的空间......但也许不是?

我认为“可能”可行的替代方案。

  1. 编写自定义序列化程序,将对象转换为 byte[] 并返回,元数据为零。 - 不理想。

  2. 是否可以编写一个混合的 clr c++ dll 并尝试将其用作楔子。但是我担心的是,我是否会遇到同样的问题,但只是在托管 C++ 中?或者即使在混合模式下,我也必须编写一个托管类来包装非托管对象,以便在 c# 中使用它。但是问题变成了如何将它传递到 deviceIOcontrol 中,如果我从 c# 中这样做,那么当前的问题是尝试正确编码东西吗?或者,如果我将它传递到调用 DeviceIOControl 的 C++ 调用中,那么我需要知道如何获取传入的每个托管对象的非托管类型。

  3. 只需编写创建对象并调用 deviceIOControl 的 C++ 函数,因为参数可能会失控而不太了解?

  4. 放弃并在 C++ 中完成所有工作,我实际上正在尝试为我的硬件编写单元测试,而 VS 中较新的 cpp 单元测试确实集成得相当好......

我也看到了这个较早的问题,并尝试了一下,但我认为我的场景有点不同。 Un-/Marshalling nested structures containing arrays of structures

 struct Points
{
int id;
int x[10];
int y[10];
};


struct Shape
{
int name;
Points p[10];
};

struct GeoShape :Shape
{
int top;
int left;
int v[10];
};

更新 2我应该澄清一下,我正在尝试向驱动程序发送一个对象,而不是接收一个对象(至少还没有)

我是这样调用它的。

public static bool SetObject(SafeFileHandle device, DeviceControlCode ioctlCode, Object obj)
{
int size = Marshal.SizeOf(obj.GetType());
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(obj, ptr, false);

// call the dviceIOControl method
return Control(device, ref ioctlCode, ptr, size, IntPtr.Zero, 0);
}

最佳答案

我真的不知道标题上有什么,但作为起点考虑阅读 this关于何时使用 structclass

作为警告...您确定 Pack = 1 吗?你有 #pragma 将它设置为 1 吗?

如果您提供相关的 .h 代码,将更容易检查可能存在的问题。无论如何,根据可用信息,我会这样做:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct VENUS_FORMAT4
{
public uint Top;
public uint Left;
public uint Rows;
public uint Columns;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.MAX_CD_ROWS)]
public uint[] V65Rows;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.MAX_CD_COLS_DD2)]
public uint[] CDCols;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.MAX_DD_SECTIONS)]
public uint[] DDSections;
}

除了VENUS_VM4_DEVICE_FORMAT4IL,其余部分与上面基本相同,您必须“复制”字段,因为在使用结构时无法继承(在 C# 中(类型值))。

此外,如果在 C++ 方面您有 union ,这将不起作用,您应该使用LayoutKind.ExplicitFieldOffset

关于C#调用具有复杂结构的deviceIOControl,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24396540/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com