c# 调用 c++ 的DLL 问题
本帖最后由 Soja 于 2013-12-23 11:57:47 编辑 c++结构:
typedef struct _GLYDEPOSITCOUNTER {
unsigned int EventNumber;
struct tm Time;
unsigned int dwSquentialNo;
unsigned int dwUserID;
GLYCOUNTERS DepositData;
} GLYDEPOSITCOUNTER, *LPGLYDEPOSITCOUNTER;
struct tm Time:
Each data range is as described below.
tm_year: 2000 to 2099, tm_mon: 1 to 12, tm_mday: 1 to 31,
tm_hour: 0 to 23, tm_min: 00 to 59, tm_sec: 00 to 59
typedef struct _GLYCOUNTERS {
unsigned int ulArraySize;
LPGLYCOUNTER lpCounters;
} GLYCOUNTERS, *LPGLYCOUNTERS;
typedef struct _GLYCOUNTER {
unsigned int dwID;
unsigned int dwStatus;
GLYDENOMINATION Denomination;
void* misc;
} GLYCOUNTER, *LPGLYCOUNTER;
typedef struct _GLYDENOMINATION {
unsigned int ulArraySize;
LPGLYCURRENCY lpCurrencies;
} GLYDENOMINATION, *LPGLYDENOMINATION;
typedef struct _GLYCURRENCY {
unsigned int ulValue;
unsigned int ulCounts;
char cCurrencyID[4];
int Rev;
GLYVALUEEXP ValueExp;
int Category;
GLYSIGNATURE** ppSignature;
void* misc;
} GLYCURRENCY, *LPGLYCURRENCY;
typedef struct _GLYVALUEEXP {
int Factor;
int Exp;
} GLYVALUEEXP, *LPGLYVALUEEXP;
typedef struct _GLYSIGNATURE {
char* SerialNumber;
char* SerialNumberAttrib;
int DataSize;
unsigned char* Data;
void* misc;
} GLYSIGNATURE, *LPGLYSIGNATURE;
我的c#转换是:
[StructLayout(LayoutKind.Sequential)]
public struct GlyDepositCounter
{
public uint EventNumber;
public Tm Time;
public uint dwSquentialNo;
public uint dwUserID;
public GlyCounters DepositData;
}
[StructLayout(LayoutKind.Sequential)]
public struct Tm
{
public int tm_year;
public int tm_mon;
public int tm_mday;
public int tm_hour;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string tm_min;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string tm_sec;
}
[StructLayout(LayoutKind.Sequential)]
public struct GlyCounters
{
public uint ulArraySize;
public GlyCounter lpCounters;
}
[StructLayout(LayoutKind.Sequential)]
public struct GlyCounter
{
public uint dwID;
public uint dwStatus;
public GlyDenomination Denomination;
public IntPtr misc;
}
[StructLayout(LayoutKind.Sequential)]
public struct GlyDenomination
{
public uint ulArraySize;
public GlyCurrency lpCurrencies;
}
[StructLayout(LayoutKind.Sequential)]
public struct GlyCurrency
{
public uint ulValue;
public uint ulCounts;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
public string cCurrencyID;
public int Rev;
public GlyValueExp ValueExp;
public int Category;
public GlySignature ppSignature;
public IntPtr misc;
}
[StructLayout(LayoutKind.Sequential)]
public struct GlyValueExp
{
public int Factor;
public int Exp;
}
[StructLayout(LayoutKind.Sequential)]
public struct GlySignature
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string SerialNumber;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string SerialNumberAttrib;
public int DataSize;
[MarshalAs(UnmanagedType.LPArray)]
public byte[] Data;
public IntPtr misc;
}
请高手指点,我的转换有什么问题吗?
我的C#代码
GlyDepositCounter glyDepositCounter = (GlyDepositCounter)Marshal.PtrToStructure(param.lpBuffer, typeof(GlyDepositCounter));
param.lpBuffer是IntPtr类型的指针地址
运行代码出错:Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
[解决办法]
1、GlyDepositCounter里面的定义又套了结构,而且还套了几层,这样会导致Marshal在分配大小时,无法计算。你可以用Marsh.sizeof(typeof(GlyDepositCounter))来测试看看。因为无法分配大小,自然就读写不进去了。
2、可以考虑将需要套结构的地方转换成类来做,然后进行封装。到最终没有套结构的地方,再使用字节转换成结构。这样才比较保险。
public class ObjectSp
{
#region bytesToStruct
/// <summary>
/// Byte array to struct or classs.
/// </summary>
/// <param name="bytes">Byte array</param>
/// <param name="type">Struct type or class type.
/// Egg:class Human{...};
/// Human human=new Human();
/// Type type=human.GetType();</param>
/// <param name="startIndex">Byte array start index.</param>
/// <returns>Destination struct or class.</returns>
public static object bytesToStruct(byte[] bytes, Type type, int startIndex = 0)
{
int size = Marshal.SizeOf(type);//Get size of the struct or class.
if (bytes.Length < size)
{
return null;
}
IntPtr structPtr = Marshal.AllocHGlobal(size);//Allocate memory space of the struct or class.
Marshal.Copy(bytes, startIndex, structPtr, size);//Copy byte array to the memory space.
object obj = Marshal.PtrToStructure(structPtr, type);//Convert memory space to destination struct or class.
Marshal.FreeHGlobal(structPtr);//Release memory space.
return obj;
}
#endregion
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public class GlyDepositCounter
{
public uint EventNumber;
public Tm Time;
public uint dwSquentialNo;
public uint dwUserID;
public GlyCounters DepositData;
public GlyDepositCounter(byte[] buff)
{
int offset = 0;
EventNumber = BitConverter.ToUInt32(buff, 0);
offset += sizeof(uint);
Time = (Tm)ObjectSp.bytesToStruct(buff, typeof(Tm), offset);
offset += Marshal.SizeOf(typeof(Tm));
dwSquentialNo = BitConverter.ToUInt32(buff, offset);
offset += sizeof(uint);
dwUserID = BitConverter.ToUInt32(buff, offset);
offset += sizeof(uint);
DepositData = analyDepositData(buff, offset);
}
private GlyCounters analyDepositData(byte[] buff, int offset)
{
GlyCounters DepositData = null;
//仿照GlyDepositCounter进一步分析DepositData
return DepositData;
}
}