다음 호출이 필요한 네이티브 C dll에 PInvoke를 통해 마샬링하고 있습니다.C#의 유니온이 잘못 정렬되었거나 비 개체 필드와 겹침
private static extern int externalMethod(IntPtr Data, [MarshalAs(UnmanagedType.U4)] ref int dataLength);
dataLength 매개 변수는 IntPtr Data 매개 변수를 통해 전달되는 구조체의 길이입니다. 두 요소가 일치하지 않으면 예외가 발생합니다. 외부 메서드는 4 가지 유형을 함께 결합하는 C Union을 사용합니다.
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;
}
답변을 주셔서 감사합니다. 나는 PInvoke 호출에서 외부 파티의 레거시 코드를 사용하고 있습니다. 확실히 4 가지 다른 통화가 선호되지만, 전적으로 변경할 수는 없습니다. 각 문자에 대해 별도의 변수를 사용할 수 있습니까? –
@sprocketonline : 마지막 단락에서 제안을 계속 사용할 수 있습니다.폴 알렉산더 (Paul Alexander)의 대답은이 전략을 모범으로 보여줍니다. – Timwi
외부 메서드에서 길이를 전달할 것으로 예상되므로 질문을 업데이트했습니다. Union의 길이는 구조체 B에서 가장 큰 멤버의 길이가 될 것이라고 가정하고, 개별 구조체에 대해 계산하면 올바르지 않습니다. –