I have a union of structs that is returned from an unmanged C++ API.
Everything works fine until I add a specific type of struct
[EvEndBitInfo] as a member of the union. I know you can't mix value and
reference types in the same union, but I don't see the conflict because
I believe all members of the suspect struct are value types. Here's
what I have:
//TypeLoadException
Could not load type ...EventInfo from assembly MyAssembly,
Version=1.0.1847.20731, Culture=neutral, PublicKeyToken=null because it
contains an object field at offset 0 that is incorrectly aligned or
overlapped by a non-object field.
// Union Definition
[StructLayout(LayoutKind.Explicit)]
public struct EventInfo
{
[FieldOffset(0)] public EvErrorInfo ErrorReport;
[FieldOffset(0)] public EvPstnErrorInfo PSTNErrorReport;
[FieldOffset(0)] public EvEndBitInfo BITReport; // here's the culprit
// additional fields...
}
// EvErrorInfo struct
[StructLayout(LayoutKind.Sequential)]
public struct EvErrorInfo
{
public int ErrorCode;
public int DeviceID;
public int CID;
public int Origin;
public int LineInFile;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=8)]
public char[] FileName;
public byte Length;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=255)]
public char[] ErrorString;
}
// EvPstnErrorInfo struct
[StructLayout(LayoutKind.Sequential)]
public struct EvPstnErrorInfo
{
public int ErrorCode;
public int DeviceID;
public int TrunkID;
public int BChannel;
public int ConnID;
public int Origin;
public int LineInFile;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=8)]
public char[] FileName;
public byte Length;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=255)]
public char[] ErrorString;
public int CallHandle;
}
// EvEndBitInfo struct ::This is the culprit::
[StructLayout(LayoutKind.Sequential)]
public struct EvEndBitInfo
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=2)]
public int[] DSPBitReturnCode;
public int FLASHBitReturnCode;
public int SDRAMBitReturnCode;
public int DPRBitReturnCode;
public int PhyTestBitReturnCode;
public int FramersBitReturnCode;
public int PCMSwitchBitReturnCode;
public int ResetSourceReportBitReturnCode;
public int NumOfAnalogChannels;
public int BoardTempBitReturnCode;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=24)]
public int[] FXSCRAMCheckSumBitReturnCode;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=24)]
public int[] VoltageCurrentBitReturnCode;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=24)]
public int[] FXSDuslicVersionReturnCode;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=24)]
public int[] FXOAnicVersionReturnCode;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=24)]
public int[] FXSCodecValidationBitReturnCode;
}
The only thing that distinguishes these structs is the use of int[] in
the EvEndBitInfo struct in question. Am I mistaken that int[] is a
value type?
Thanks for any insight.
Mattias Sj?gren - 21 Jan 2005 19:15 GMT
Jason,
>Am I mistaken that int[] is a value type?
Yes, all arrays are reference types.
Mattias

Signature
Mattias Sjögren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Jason Cartwright - 21 Jan 2005 19:25 GMT
So why do the char[] fields work and not int[]?
Mattias Sj?gren - 23 Jan 2005 10:50 GMT
>So why do the char[] fields work and not int[]?
Don't know, I wouldn't expect either to work. But TypeLoadExceptions
tend to be somewhat unpredictable.
Mattias

Signature
Mattias Sjögren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Jason Cartwright - 24 Jan 2005 16:08 GMT
I ended up going with an IntPtr instead of trying to recreate the union
in C#. At least that will give me the flexibility of dealing with each
expected struct individually instead of dealing with object vs.
non-object conflicts.
const int BUFSIZE = 2048;
Event boardEvent = null;
IntPtr pEI = IntPtr.Zero; // pointer to EventInfo
try
{
int channelHandle, eventInfoSize;
// alloc unmanaged memory
pEI = Marshal.AllocHGlobal((int) BUFSIZE);
EventType eventType = (EventType) acGetEvent(boardHandle, out
channelHandle, 0, 0, pEI, out eventInfoSize);
switch(eventType)
{
case EventType.acEV_NONE:
boardEvent = new Event(eventType, boardHandle, channelHandle);
break;
case EventType.acEV_ERROR:
case EventType.acEV_DEBUG:
EvErrorInfo errorInfo = (EvErrorInfo) Marshal.PtrToStructure(pEI,
typeof(EvErrorInfo));
boardEvent = new ErrorEvent(errorInfo, eventType, boardHandle,
channelHandle);
break;
}
finally
{
//deallocate unmanaged memory
if(pEI != IntPtr.Zero)
Marshal.FreeHGlobal(pEI);
}