P / Invoke问题编组参数

时间:2009-12-03 14:28:06

标签: c# pinvoke marshalling

在理解编组C ++ DLL时似乎还有另一个问题。

这是C ++函数的def和& struct:

#define SIZE_PLATE         (28l)
#define SIZE_HJT           (15l)
#define SIZE_DATE          (10)

typedef struct _tyrfdePlate
{
    TCharA PlateID[SIZE_PLATE];
    TInt32 NetworkID;
    TInt32 CityID;
    TCharA DateS[SIZE_DATE];
    TCharA DateE[SIZE_DATE];
    TInt32 Width;
    TInt32 Height;
    TBool  Light;
    TBool  Roll;
    TCharA CycleID[4]; 
    TInt16 OrHjt1;
    TCharA HJTID1[SIZE_HJT];
    TInt16 OrHjt2;
    TCharA HJTID2[SIZE_HJT];
    TInt16 OrHjt3;
    TCharA HJTID3[SIZE_HJT];
    TInt16 OrHjt4;
    TCharA HJTID4[SIZE_HJT];
} tyrfdePlate;

TInt32 __stdcall tyrfdeSetResults(TInt32 TargetNbr, const TInt32* pTargets, TInt32 PlateNbr, const tyrfdePlate* pPlates);

这是我根据之前提出的问题在C#中所做的:

[StructLayout(LayoutKind.Sequential, Size = 138), Serializable]
public struct Plate
{
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 28)]
    public string PlateID;
    public int NetworkID;
    public int CityID;
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string DateS;
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string DateE;
    public int Width;
    public int Height;
    public bool Light;
    public bool Roll;
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 4)]
    public string CycleID;
    public short OrHJT1;
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
    public string HJTID1;
    public short OrHJT2;
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
    public string HJTID2;
    public short OrHJT3;
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
    public string HJTID3;
    public short OrHJT4;
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
    public string HJTID4;
}

[DllImport("tyrfde.dll", EntryPoint = "tyrfdeSetResults")]
public static extern int SetResults(int targetNbr, [MarshalAs(UnmanagedType.LPArray)] int[] targetIds, int plateNbr, [MarshalAs(UnmanagedType.LPArray)] Plate[] plates);

这是一个电话示例:

List<Plate> plates = new List<Plate>();
plates.Add(new Plate() { PlateID = "56013208", NetworkID = 992038, CityID = 60010, DateS = "01012009", DateE = "31122010", Width = 400, Height = 300, Light = false, Roll = false, CycleID = "0", OrHJT1 = 2, HJTID1 = "579026356", OrHJT2 = 2, HJTID2 = "579026377", OrHJT3 = 2, HJTID3 = "58571903", OrHJT4 = 0, HJTID4 = "0" });
int[] targets = new int[]{1,2,11,12,130};

int result = SetResults(5, targets, 1, plates.ToArray());

请注意,我也尝试使用原生Array而不是通用列表,结果相同。

所以基本上我正在使用相同的数据重做用C ++制作的测试应用程序。不幸的是,函数返回-1,这意味着发生了错误,但C ++应用程序返回23.所以我猜测我的struct和/或我传递的参数有问题。可能是int []。我试图让ref的默认编组,但没有工作。有什么想法吗?

修改

由于类型定义似乎非常重要,因此def:

typedef void           TVoid;
typedef bool           TBool;
typedef char           TCharA; // character         8
typedef TCharA         TChar;  // character         8
typedef wchar_t        TCharW; // character        16
typedef signed   char  TInt08; // integer   signed  8
typedef unsigned char  TUnt08; // integer unsigned  8
typedef signed   short TInt16; // integer   signed 16
typedef unsigned short TUnt16; // integer unsigned 16
typedef signed   long  TInt32; // integer   signed 32
typedef unsigned long  TUnt32; // integer unsigned 32
typedef float          TFlt32; // float 32
typedef double         TFlt64; // float 64

4 个答案:

答案 0 :(得分:1)

你真正想要的是一种调试方法。最简单的方法是编写自己的dll,使用这种数据类型,看看另一方面结构会发生什么。

我怀疑你的真正问题是结构调整以及它是如何运作的。我在你的代码中看到的是一堆奇数大小的元素(15,28,10)。有可能是目标系统已经消失并且在至少2个字节(如果不是4个字节边界)上对齐结构元素。你不应该检查。

您还可以通过编写消耗实际结构的C并在结构元素上输出一堆offsetof()调用的结果来节省一些时间。

你的方法应该是有条不紊的,而不是霰弹枪,方法的一部分是测量和反馈。这将给你们两个。

答案 1 :(得分:1)

您在[StructLayout]属性中提供的Size属性是一个很好的提示。使用此代码段验证:

        int len = Marshal.SizeOf(typeof(Plate));
        System.Diagnostics.Debug.Assert(len == 138);

你要通过这个断言的唯一方法是用“byte”替换“bool”(所以TBool = 1个字节)并使用1的打包:

[StructLayout(LayoutKind.Sequential, Pack=1), Serializable]
public struct Plate {
  //...
}

如果仍然无效,那么你真的必须调试非托管代码。

答案 2 :(得分:0)

1)TBool有多少字节? 1? 4?

2)您可以删除StructLayout(LayoutKind.Sequential,Size = 138)属性,因为默认情况下它是Sequential,并且Size可以由运行时确定。

3)您可以删除[MarshalAs(UnmanagedType.LPArray)]属性。 marshaller知道如何编组数组,但请注意,默认情况下,数组被编组为[IN],因此如果c ++代码要编辑数组的内容,则需要使用[IN,OUT]属性。

答案 3 :(得分:0)

dll中的const TInt32* pTargets参数怎么样?我不知道它是如何使用的,但这表明指向单个TInt32实例的指针,而不是TInt32的数组。当然,这取决于它在代码中的使用方式。