工会在C# - 正确对齐或与非对象场重叠

我通过的PInvoke封送机C的dll其中有下面的电话。

private static extern int externalMethod(IntPtr Data, [MarshalAs(UnmanagedType.U4)] ref int dataLength);

该DATALENGTH参数是通过IntPtr的数据参数传递的结构的长度。 如果这两个不匹配,它抛出一个异常。 外部方法使用一个C联盟四种类型的接合在一起。

我已经成功使用FieldOffsetAttribute重新在C#中的工会。 我然后计算C#工会的长度,并呼吁用以下方法:

int len = Marshal.SizeOf(data); IntPtr ptr = Marshal.AllocCoTaskMem(len); externalMethod(ptr, len);

但是,我得到的错误System.TypeLoadException : ... Could not load type because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field.用下面的代码。 我相信这也许是字符串或整数数组(可变B7)中的任何一个? 我怎么会去改变这种使它工作 - 我必须打破了整数数组到多个变量?

[StructLayoutAttribute(LayoutKind.Explicit)] public struct Union{ [FieldOffset(0)] public A a; [FieldOffset(0)] public B b; [FieldOffset(0)] public C c; [FieldOffset(0)] public D d; } [StructLayout(LayoutKind.Sequential)] public struct A { public int A1; public int A2; public int A3; [MarshalAs(UnmanagedType.LPTStr, SizeConst = 17)] public string A4; [MarshalAs(UnmanagedType.LPTStr, SizeConst = 4)] public string A5; } [StructLayout(LayoutKind.Sequential)] public struct B { public int B1; [MarshalAs(UnmanagedType.LPTStr, SizeConst = 2)] public string B2; [MarshalAs(UnmanagedType.LPTStr, SizeConst = 4)] public string B3; [MarshalAs(UnmanagedType.LPTStr, SizeConst = 6)] public string B4; public int B5; public int B6; [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U4, SizeConst = 255)] public int[] B7; } [StructLayout(LayoutKind.Sequential)] public struct C { public int C1; public int C2; public int C3; public int C4; [MarshalAs(UnmanagedType.LPTStr, SizeConst = 32)] public string C5; public float C6; public float C7; public float C8; public float C9; public float C10; public float C11; public float C12; public float C13; public float C14; } [StructLayout(LayoutKind.Sequential)] public struct D { public int D1; [MarshalAs(UnmanagedType.LPTStr, SizeConst = 36)] public string D2; }

--------------解决方案-------------

只需直接使用A / B / C / D结构,跳过工会。 在你的extern电话,只需替换在方法声明的正确结构。

extern void UnionMethodExpectingA( A a );

如果非托管方法实际上接受工会和不同的行为根据传递的类型,那么你可以声明不同的extern方法,所有最终调用相同的非托管入口点。

[DllImport( "unmanaged.dll", EntryPoint="ScaryMethod" )]
extern void ScaryMethodExpectingA( A a );

[DllImport( "unmanaged.dll", EntryPoint="ScaryMethod" )]
extern void ScaryMethodExpectingB( B b );

更新了“长度”参数。逻辑依然适用。 只要创建一个“包装”的方法,做同样的事情。

void CallScaryMethodExpectingA( A a )
{
ScaryMethodExpectingA( a, Marshal.SizeOf( a ) );
}

这是很难回答这个问题,不知道你想达到什么目的。 一个显式layouted结构为任何正常使用情况下的一个非常不错的选择; 这才有意义,如果您使用的是本机调用(PInvoke的)的数据,在这种情况下你肯定唐娜€™吨要使用的托管类string 。 在[MarshalAs]属性才会生效在通话过程中调用,而不是不断地在每次域从读取或托管代码编写的时间。 它doesn’吨让你重叠字符串指针用int,因为这样做将允许您将指针设置为一个无意义的值,然后访问该字符串会崩溃的CLR。 这同样适用于数组真,所以你德卡尼亚€™吨使用char[]无论是。

如果你是,你需要调用本机代码的作者,那么我强烈建议写四个独立的方法,而不是单一的一个接受四个完全不同的数据结构。

如果你不能改变本机代码,那么你总是可以宣布你的四结构ABCD你现在做的方式,只是使用他们直接,没有工会。 刚刚宣布四种不同的PInvoke的声明相同的原生功能(使用EntryPoint的属性[DllImport]属性)。

分类:C# 时间:2015-03-15 人气:0
本文关键词: C#中,编组,工会
分享到:

相关文章

Copyright (C) 55228885.com, All Rights Reserved.

55228885 版权所有 京ICP备15002868号

processed in 1.139 (s). 10 q(s)