首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

c# 调用 c++ 的DLL 有关问题

2014-01-01 
c# 调用 c++ 的DLL 问题本帖最后由 Soja 于 2013-12-23 11:57:47 编辑c++结构:typedef struct _GLYDEPOSIT

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;
        }
    }


3、建议增加CharSet和Pack参数,这样才能保证字节的对齐。比如[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi,Pack=1)]

热点排行