200分求助:c#模拟c++中的联合
有关.net的P/Invoke操作也算了解,但说不上太深,基本的函数调用还可以,但对于一些复杂的数据结构,如上面代码中的联合(union)就无法把其转换为C#以使用的结构。
注:已经看过《如何在C#中模拟C++的联合(Union)》
http://www.cnblogs.com/allenlooplee/archive/2004/12/25/81917.html
此联合是Windows CE中调用RIL接口接收短信时,短信的数据结构
代码如下,也可以参考MSDN,更清楚:
MSDN:http://msdn.microsoft.com/en-us/library/aa919458.aspx
代码:
typedef struct {
DWORD cbSize;
DWORD dwParams;
RILADDRESS raSvcCtrAddress;
DWORD dwType;
DWORD dwFlags;
UNION {
struct {
RILADDRESS raOrigAddress;
DWORD dwProtocolID;
RILMSGDCS rmdDataCoding;
SYSTEMTIME stSCReceiveTime;
DWORD cbHdrLength;
DWORD cchMsgLength;
BYTE rgbHdr[MAXLENGTH_HDR];
BYTE rgbMsg[MAXLENGTH_MSG];
} msgInDeliver;
struct {
DWORD dwTgtMsgReference;
RILADDRESS raTgtRecipAddress;
SYSTEMTIME stTgtSCReceiveTime;
SYSTEMTIME stTgtDischargeTime;
DWORD dwTgtDlvStatus;
DWORD dwProtocolID;
RILMSGDCS rmdDataCoding;
DWORD cbHdrLength;
DWORD cchMsgLength;
BYTE rgbHdr[MAXLENGTH_HDR];
BYTE rgbMsg[MAXLENGTH_MSG];
} msgInStatus;
struct {
RILADDRESS raDestAddress;
DWORD dwProtocolID;
RILMSGDCS rmdDataCoding;
DWORD dwVPFormat;
SYSTEMTIME stVP;
DWORD cbHdrLength;
DWORD cchMsgLength;
BYTE rgbHdr[MAXLENGTH_HDR];
BYTE rgbMsg[MAXLENGTH_MSG];
} msgOutSubmit;
struct {
DWORD dwProtocolID;
DWORD dwCommandType;
DWORD dwTgtMsgReference;
RILADDRESS raDestAddress;
DWORD cbCmdLength;
BYTE rgbCmd[MAXLENGTH_CMD];
} msgOutCommand;
struct {
DWORD dwGeoScope;
DWORD dwMsgCode;
DWORD dwUpdateNumber;
DWORD dwID;
RILMSGDCS rmdDataCoding;
DWORD dwTotalPages;
DWORD dwPageNumber;
DWORD cchMsgLength;
BYTE rgbMsg[MAXLENGTH_MSG];
} msgBcGeneral;
struct {
DWORD cchMsgLength;
BYTE rgbMsg[MAXLENGTH_MSG];
} msgOutRaw;
struct {
RILADDRESS raOrigAddress;
RILSUBADDRESS rsaOrigSubaddr;
SYSTEMTIME stSCReceiveTime;
SYSTEMTIME stValidityPeriodAbs;
SYSTEMTIME stValidityPeriodRel;
SYSTEMTIME stDeferredDelTimeAbs;
SYSTEMTIME stDeferredDelTimeRel;
DWORD dwNumMsgs;
RILADDRESS raCallBackNumber;
DWORD dwMsgPriority;
DWORD dwMsgPrivacy;
BOOL bUserAckRequest;
DWORD dwMsgDisplayMode;
DWORD dwTeleservice;
DWORD dwMsgID;
DWORD dwMsgLang;
DWORD dwMsgEncoding;
DWORD cchMsgLength;
BYTE rgbMsg[MAXLENGTH_MSG];
} msgIS637InDeliver;
struct {
RILADDRESS raDestAddress;
RILSUBADDRESS rsaDestSubaddr;
BOOL bDigit;
SYSTEMTIME stValidityPeriodAbs;
SYSTEMTIME stValidityPeriodRel;
SYSTEMTIME stDeferredDelTimeAbs;
SYSTEMTIME stDeferredDelTimeRel;
BOOL bDeliveryAckRequest;
BOOL bUserAckRequest;
BOOL bBearerReplyRequest;
DWORD dwReplySeqNumber;
DWORD dwMsgDisplayMode;
RILADDRESS raCallBackNumber;
DWORD dwMsgPriority;
DWORD dwMsgPrivacy;
DWORD dwTeleservice;
DWORD dwMsgID;
DWORD dwMsgLang;
DWORD dwMsgEncoding;
DWORD cchMsgLength;
BYTE rgbMsg[MAXLENGTH_MSG];
} msgIS637OutSubmit;
struct {
RILADDRESS raOrigAddress;
RILSUBADDRESS rsaOrigSubaddr;
SYSTEMTIME stSCReceiveTime;
DWORD dwCauseCode;
DWORD dwReplySeqNumber;
DWORD dwUserResponseCode;
DWORD dwMsgStatusType;
DWORD dwMsgID;
DWORD dwMsgLang;
DWORD dwMsgEncoding;
DWORD cchMsgLength;
BYTE rgbMsg[MAXLENGTH_MSG];
} msgIS637InStatus;
struct {
RILADDRESS raDestAddress;
RILSUBADDRESS rsaDestSubaddr;
BOOL bDigit;
DWORD dwReplySeqNumber;
DWORD dwUserResponseCode;
DWORD dwMsgID;
DWORD dwMsgLang;
DWORD dwMsgEncoding;
DWORD cchMsgLength;
BYTE rgbMsg[MAXLENGTH_MSG];
} msgIS637OutStatus;
}
} RILMESSAGE;
结构中使用到的其它结构,MSDN中都有,可以参考
http://msdn.microsoft.com/en-us/library/aa919130(v=MSDN.10).aspx
我自己写的C#的封装,但运行出错。
代码:
#region RILMESSAGE struct
private struct RILMESSAGE
{
public UInt32 cbSize;
public UInt32 dwParams;
public RILADDRESS raSvcCtrAddress;
public UInt32 dwType;
public UInt32 dwFlags;
public UNION Msg;
}
[StructLayout(LayoutKind.Explicit)]
private struct UNION
{
[FieldOffset(0)]
public msgInDeliver _msgInDeliver;
[FieldOffset(0)]
public msgInStatus _msgInStatus;
[FieldOffset(0)]
public msgOutSubmit _msgOutSubmit;
[FieldOffset(0)]
public msgOutCommand _msgOutCommand;
[FieldOffset(0)]
public msgBcGeneral _msgBcGeneral;
[FieldOffset(0)]
public msgOutRaw _msgOutRaw;
}
#region 用于UNION中的Struct
[StructLayout(LayoutKind.Sequential)]
private struct msgInDeliver
{
public RILADDRESS raOrigAddress;
public UInt32 dwProtocolID;
public RILMSGDCS rmdDataCoding;
public SYSTEMTIME stSCReceiveTime;
public UInt32 cbHdrLength;
public UInt32 cchMsgLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] rgbHdr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] rgbMsg;
}
[StructLayout(LayoutKind.Sequential)]
private struct msgInStatus
{
public UInt32 dwTgtMsgReference;
public RILADDRESS raTgtRecipAddress;
public SYSTEMTIME stTgtSCReceiveTime;
public SYSTEMTIME stTgtDischargeTime;
public UInt32 dwTgtDlvStatus;
public UInt32 dwProtocolID;
public RILMSGDCS rmdDataCoding;
public UInt32 cbHdrLength;
public UInt32 cchMsgLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] rgbHdr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] rgbMsg;
}
[StructLayout(LayoutKind.Sequential)]
private struct msgOutSubmit
{
public RILADDRESS raDestAddress;
public UInt32 dwProtocolID;
public RILMSGDCS rmdDataCoding;
public UInt32 dwVPFormat;
public SYSTEMTIME stVP;
public UInt32 cbHdrLength;
public UInt32 cchMsgLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] rgbHdr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] rgbMsg;
}
[StructLayout(LayoutKind.Sequential)]
private struct msgOutCommand
{
public UInt32 dwProtocolID;
public UInt32 dwCommandType;
public UInt32 dwTgtMsgReference;
public RILADDRESS raDestAddress;
public UInt32 cbCmdLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] rgbCmd;
}
[StructLayout(LayoutKind.Sequential)]
private struct msgOutRaw
{
public UInt32 cchMsgLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] rgbMsg;
}
#endregion
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
private struct RILADDRESS
{
public UInt32 cbSize;
public UInt32 dwParams;
public UInt32 dwType;
public UInt32 dwNumPlan;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public StringBuilder wszAddress;
}
[StructLayout(LayoutKind.Sequential)]
private struct RILMSGDCS
{
public UInt32 cbSize;
public UInt32 dwParams;
public UInt32 dwType;
public UInt32 dwFlags;
public UInt32 dwMsgClass;
public UInt32 dwAlphabet;
public UInt32 dwIndication;
public UInt32 dwLanguage;
}
[StructLayout(LayoutKind.Sequential)]
private struct SYSTEMTIME
{
public short wYear;
public short wMonth;
public short wDayOfWeek;
public short wDay;
public short wHour;
public short wMinute;
public short wSecond;
public short wMilliseconds;
}
#endregion
有对C#互操作有经验的前辈给于指点,如能帮助实现,不胜感激。
[解决办法]
帮顶...
[解决办法]
顶个 SF
[解决办法]
主要是结构中有联合,联合中有又有结构
[解决办法]
问题已经解决,经过查找资料,联合可以说是对一块内存的操作,反映到C#中,可以用byte[]来映射这块内存。
下面的代码是实现:
#region RILMESSAGE struct
public struct RILMESSAGE
{
public UInt32 cbSize;
public UInt32 dwParams;
[MarshalAs(UnmanagedType.Struct, SizeConst = 528)]
public RILADDRESS raSvcCtrAddress;
public UInt32 dwType;
public UInt32 dwFlags;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1356)] //最大的结构为2212。短信结构长度为1356
public byte[] Msg;
}
#region 用于UNION中的10个Struct
[StructLayout(LayoutKind.Sequential)]
public struct msgInDeliver
{
public RILADDRESS raOrigAddress;
public UInt32 dwProtocolID;
public RILMSGDCS rmdDataCoding;
public SYSTEMTIME stSCReceiveTime;
public UInt32 cbHdrLength;
public UInt32 cchMsgLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] rgbHdr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] rgbMsg;
}
[StructLayout(LayoutKind.Sequential)]
public struct msgInStatus
{
public UInt32 dwTgtMsgReference;
public RILADDRESS raTgtRecipAddress;
public SYSTEMTIME stTgtSCReceiveTime;
public SYSTEMTIME stTgtDischargeTime;
public UInt32 dwTgtDlvStatus;
public UInt32 dwProtocolID;
public RILMSGDCS rmdDataCoding;
public UInt32 cbHdrLength;
public UInt32 cchMsgLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] rgbHdr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] rgbMsg;
}
[StructLayout(LayoutKind.Sequential)]
public struct msgOutSubmit
{
public RILADDRESS raDestAddress;
public UInt32 dwProtocolID;
public RILMSGDCS rmdDataCoding;
public UInt32 dwVPFormat;
public SYSTEMTIME stVP;
public UInt32 cbHdrLength;
public UInt32 cchMsgLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] rgbHdr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] rgbMsg;
}
[StructLayout(LayoutKind.Sequential)]
public struct msgOutCommand
{
public UInt32 dwProtocolID;
public UInt32 dwCommandType;
public UInt32 dwTgtMsgReference;
public RILADDRESS raDestAddress;
public UInt32 cbCmdLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] rgbCmd;
}
[StructLayout(LayoutKind.Sequential)]
public struct msgBcGeneral
{
public UInt32 dwGeoScope;
public UInt32 dwMsgCode;
public UInt32 dwUpdateNumber;
public UInt32 dwID;
public RILMSGDCS rmdDataCoding;
public UInt32 dwTotalPages;
public UInt32 dwPageNumber;
public UInt32 cchMsgLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] rgbMsg;
}
[StructLayout(LayoutKind.Sequential)]
public struct msgOutRaw
{
public UInt32 cchMsgLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] rgbMsg;
}
[StructLayout(LayoutKind.Sequential)]
public struct msgIS637InDeliver
{
public RILADDRESS raOrigAddress;
public RILSUBADDRESS rsaOrigSubaddr;
public SYSTEMTIME stSCReceiveTime;
public SYSTEMTIME stValidityPeriodAbs;
public SYSTEMTIME stValidityPeriodRel;
public SYSTEMTIME stDeferredDelTimeAbs;
public SYSTEMTIME stDeferredDelTimeRel;
public UInt32 dwNumMsgs;
public RILADDRESS raCallBackNumber;
public UInt32 dwMsgPriority;
public UInt32 dwMsgPrivacy;
public bool bUserAckRequest;
public UInt32 dwMsgDisplayMode;
public UInt32 dwTeleservice;
public UInt32 dwMsgID;
public UInt32 dwMsgLang;
public UInt32 dwMsgEncoding;
public UInt32 cchMsgLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] rgbMsg;
}
[StructLayout(LayoutKind.Sequential)]
public struct msgIS637OutSubmit
{
public RILADDRESS raDestAddress;
public RILSUBADDRESS rsaDestSubaddr;
private bool bDigit;
public SYSTEMTIME stValidityPeriodAbs;
public SYSTEMTIME stValidityPeriodRel;
public SYSTEMTIME stDeferredDelTimeAbs;
public SYSTEMTIME stDeferredDelTimeRel;
private bool bDeliveryAckRequest;
private bool bUserAckRequest;
private bool bBearerReplyRequest;
public UInt32 dwReplySeqNumber;
public UInt32 dwMsgDisplayMode;
public RILADDRESS raCallBackNumber;
public UInt32 dwMsgPriority;
public UInt32 dwMsgPrivacy;
public UInt32 dwTeleservice;
public UInt32 dwMsgID;
public UInt32 dwMsgLang;
public UInt32 dwMsgEncoding;
public UInt32 cchMsgLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] rgbMsg;
}
[StructLayout(LayoutKind.Sequential)]
public struct msgIS637InStatus
{
public RILADDRESS raOrigAddress;
public RILSUBADDRESS rsaOrigSubaddr;
public SYSTEMTIME stSCReceiveTime;
public UInt32 dwCauseCode;
public UInt32 dwReplySeqNumber;
public UInt32 dwUserResponseCode;
public UInt32 dwMsgStatusType;
public UInt32 dwMsgID;
public UInt32 dwMsgLang;
public UInt32 dwMsgEncoding;
public UInt32 cchMsgLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] rgbMsg;
}
[StructLayout(LayoutKind.Sequential)]
public struct msgIS637OutStatus
{
public RILADDRESS raDestAddress;
public RILSUBADDRESS rsaDestSubaddr;
public bool bDigit;
public UInt32 dwReplySeqNumber;
public UInt32 dwUserResponseCode;
public UInt32 dwMsgID;
public UInt32 dwMsgLang;
public UInt32 dwMsgEncoding;
public UInt32 cchMsgLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] rgbMsg;
}
#endregion
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct RILSUBADDRESS
{
public UInt32 cbSize;
public UInt32 dwParams;
public UInt32 dwType;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string wszSubAddress;
}
[StructLayout(LayoutKind.Sequential)]
public struct RILMSGDCS
{
public UInt32 cbSize;
public UInt32 dwParams;
public UInt32 dwType;
public UInt32 dwFlags;
public UInt32 dwMsgClass;
public UInt32 dwAlphabet;
public UInt32 dwIndication;
public UInt32 dwLanguage;
}
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEMTIME
{
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMilliseconds;
public override string ToString()
{
return wYear.ToString() + "-" + wMonth.ToString() + "-" + wDay.ToString() + " "
+ wHour.ToString() + ":" + wMinute.ToString() + ":" + wSecond.ToString();
}
}
#endregion
具体调用的时候,因为同一时间联合中只有一个结构,而且可以根据dwType来确认是使用的哪一个结构,这时可以使用如下的方法,把byte[]转换成相应的结构:
lpData是IntPtr类型
RILMESSAGE msg = (RILMESSAGE) Marshal.PtrToStructure(lpData, typeof (RILMESSAGE));
以上取出了RILMESSAGE
msgInDeliver msgIn = (msgInDeliver)Ril.BytesToStruct(msg.Msg, typeof(msgInDeliver));
public static object BytesToStruct(byte[] bytes, Type type)
{
//得到结构的大小
int size = Marshal.SizeOf(type);
//byte数组长度小于结构的大小
if (size > bytes.Length)
{
//返回空
return null;
}
//分配结构大小的内存空间
IntPtr structPtr = Marshal.AllocHGlobal(size);
//将byte数组拷到分配好的内存空间
Marshal.Copy(bytes, 0, structPtr, size);
//将内存空间转换为目标结构
object obj = Marshal.PtrToStructure(structPtr, type);
//释放内存空间
Marshal.FreeHGlobal(structPtr);
//返回结构
return obj;
}
以上把byte[]类型的msg.Msg转换为结构msgInDeliver。msg.Msg也就是联合指向的内存中的数据
[解决办法]
在此感谢各位同行的回复。
备注:在解决这个问题的过程中,收集的相关资料:
RilNET 一个老外写的调用RIL接口.net实现,但并不包括本贴提到的RILMESSAGE结构
http://rilnet.codeplex.com/
RIL MSDN
http://msdn.microsoft.com/en-us/library/aa919130(v=MSDN.10).aspx
如何在C#中模拟C++的联合(Union)?[C#, C++]
http://www.cnblogs.com/allenlooplee/archive/2004/12/25/81917.html
C#中struct的内存对齐
http://qingchina.bokee.com/3399821.html
Mastering structs in C#
http://www.vsj.co.uk/articles/display.asp?id=501
[解决办法]
lpData 这个指针 在哪里定义的。。