最近在开发过程中需要使用C#调用C写的DLL,但在调用过程中遇到这个问题:“尝试读取或写入受保护的内存 这通常指示其它内存已损坏”,出现错误的地方可能为C#定义的结构体与C定义的结构体转换错误。详细如下:
1、引用外部C的DLL:
[DllImport("UniAPIDll.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, EntryPoint = "InitSgipAPI")]
private static extern int InitSgipAPI(StringBuilder path, loginInfo _LoginInfo);2、C#中定义的loginInfo: public const int LOGINFO_IP_LEN = 15;
public const int LOGINFO_USER_LEN = 16;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct loginInfo
{
[MarshalAs(UnmanagedType.U4)]
public uint spNodeId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = LOGINFO_IP_LEN + 1)]
public string gwIp;
[MarshalAs(UnmanagedType.I4)]
public int gwPort;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = LOGINFO_USER_LEN + 1)]
public string loginGwUser;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = LOGINFO_USER_LEN + 1)]
public string loginGwPwd;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = LOGINFO_IP_LEN + 1)]
public string appIp;
[MarshalAs(UnmanagedType.I4)]
public int appPort;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = LOGINFO_USER_LEN + 1)]
public string gwLinkUser;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = LOGINFO_USER_LEN + 1)]
public string gwLinkPwd;
}
3、C的loginInfo的结构如下:#define LOGINFO_IP_LEN ((int)15)
#define LOGINFO_USER_LEN ((int)16)
#define LOGINFO_PWD_LEN ((int)16)typedef struct loginInfo_tag
{
unsigned int spNodeId; // sp node code, should be assigned by gw
char gwIp[LOGINFO_IP_LEN + 1];
int gwPort;
char loginGwUser[LOGINFO_USER_LEN + 1];
char loginGwPwd[LOGINFO_PWD_LEN + 1];
char appIp[LOGINFO_IP_LEN + 1]; // provide sgip server on the ip.
int appPort; // provide sgip server at the port
char gwLinkUser[LOGINFO_USER_LEN + 1]; // gw use the username to link app
char gwLinkPwd[LOGINFO_PWD_LEN + 1]; // gw use the password to link app
} LoginInfo;
4、在使用
public int InitAPI(loginInfo _LoginInfo)
{
if (this._path == "" || this._path == null) return -1;
StringBuilder _StringBuilderPath = new StringBuilder(this._path);
return InitSgipAPI(_StringBuilderPath, _LoginInfo);
}
抛出“尝试读取或写入受保护的内存 这通常指示其它内存已损坏”的异常,请问大师们这为何?如何解决?
1、引用外部C的DLL:
[DllImport("UniAPIDll.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, EntryPoint = "InitSgipAPI")]
private static extern int InitSgipAPI(StringBuilder path, loginInfo _LoginInfo);2、C#中定义的loginInfo: public const int LOGINFO_IP_LEN = 15;
public const int LOGINFO_USER_LEN = 16;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct loginInfo
{
[MarshalAs(UnmanagedType.U4)]
public uint spNodeId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = LOGINFO_IP_LEN + 1)]
public string gwIp;
[MarshalAs(UnmanagedType.I4)]
public int gwPort;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = LOGINFO_USER_LEN + 1)]
public string loginGwUser;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = LOGINFO_USER_LEN + 1)]
public string loginGwPwd;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = LOGINFO_IP_LEN + 1)]
public string appIp;
[MarshalAs(UnmanagedType.I4)]
public int appPort;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = LOGINFO_USER_LEN + 1)]
public string gwLinkUser;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = LOGINFO_USER_LEN + 1)]
public string gwLinkPwd;
}
3、C的loginInfo的结构如下:#define LOGINFO_IP_LEN ((int)15)
#define LOGINFO_USER_LEN ((int)16)
#define LOGINFO_PWD_LEN ((int)16)typedef struct loginInfo_tag
{
unsigned int spNodeId; // sp node code, should be assigned by gw
char gwIp[LOGINFO_IP_LEN + 1];
int gwPort;
char loginGwUser[LOGINFO_USER_LEN + 1];
char loginGwPwd[LOGINFO_PWD_LEN + 1];
char appIp[LOGINFO_IP_LEN + 1]; // provide sgip server on the ip.
int appPort; // provide sgip server at the port
char gwLinkUser[LOGINFO_USER_LEN + 1]; // gw use the username to link app
char gwLinkPwd[LOGINFO_PWD_LEN + 1]; // gw use the password to link app
} LoginInfo;
4、在使用
public int InitAPI(loginInfo _LoginInfo)
{
if (this._path == "" || this._path == null) return -1;
StringBuilder _StringBuilderPath = new StringBuilder(this._path);
return InitSgipAPI(_StringBuilderPath, _LoginInfo);
}
抛出“尝试读取或写入受保护的内存 这通常指示其它内存已损坏”的异常,请问大师们这为何?如何解决?
参考一下吧using System;
using System.Text;
using System.Runtime.InteropServices;namespace testStructureToPtr
...{
public static class define //define some constant
...{
public const int MAX_LENGTH_OF_IDENTICARDID = 20; //maximum length of identicardid
public const int MAX_LENGTH_OF_NAME = 50; //maximum length of name
public const int MAX_LENGTH_OF_COUNTRY = 50; //maximum length of country
public const int MAX_LENGTH_OF_NATION = 50; //maximum length of nation
public const int MAX_LENGTH_OF_BIRTHDAY = 8; //maximum length of birthday
public const int MAX_LENGTH_OF_ADDRESS = 200; //maximum length of address
} public struct PERSON //person structure
...{
//MarshalAs:指示如何在托管代码和非托管代码之间封送数据
//UnmanagedType:指定如何将参数或字段封送到非托管内存块
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_IDENTICARDID)]
public byte[] identicardid;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NAME)]
public byte[] name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_COUNTRY)]
public byte[] country;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_NATION)]
public byte[] nation;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_BIRTHDAY)]
public byte[] birthday;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = define.MAX_LENGTH_OF_ADDRESS)]
public byte[] address;
} class testProgram
...{
private static byte _fillChar = 0; //the fill character //convert string to byte array in Ascii with length is len
public static byte[] CodeBytes(string str, int len)
...{
if (string.IsNullOrEmpty(str))
...{
str = string.Empty;
}
byte[] result = new byte[len];
byte[] strBytes = Encoding.Default.GetBytes(str); //copy the array converted into result, and fill the remaining bytes with 0
for (int i = 0; i < len; i++)
result[i] = ((i < strBytes.Length) ? strBytes[i] : _fillChar);
return result;
} //show the person information
public static void ShowPerson(PERSON person)
...{
Console.WriteLine("cardid :" + Encoding.ASCII.GetString(person.identicardid));
Console.WriteLine("name :" + Encoding.ASCII.GetString(person.name));
Console.WriteLine("country :" + Encoding.ASCII.GetString(person.country));
Console.WriteLine("nation :" + Encoding.ASCII.GetString(person.nation));
Console.WriteLine("birthday :" + Encoding.ASCII.GetString(person.birthday));
Console.WriteLine("address :" + Encoding.ASCII.GetString(person.address));
} static void Main(string[] args)
...{
PERSON person;
person.identicardid = CodeBytes("123456198001011111", define.MAX_LENGTH_OF_IDENTICARDID);
person.name = CodeBytes("jackson", define.MAX_LENGTH_OF_NAME);
person.country = CodeBytes("China", define.MAX_LENGTH_OF_COUNTRY);
person.nation = CodeBytes("HanZu", define.MAX_LENGTH_OF_NATION);
person.birthday = CodeBytes("19800101", define.MAX_LENGTH_OF_BIRTHDAY);
person.address = CodeBytes("Luoshan Road, Shanghai", define.MAX_LENGTH_OF_ADDRESS); int nSizeOfPerson = Marshal.SizeOf(person);
IntPtr intPtr = Marshal.AllocHGlobal(nSizeOfPerson);
Console.WriteLine("The person infomation is as follows:");
ShowPerson(person); try
...{
//将数据从托管对象封送到非托管内存块,该内存块开始地址为intPtr
Marshal.StructureToPtr(person, intPtr, true); //将数据从非托管内存块封送到新分配的指定类型的托管对象anotherPerson
PERSON anotherPerson = (PERSON)Marshal.PtrToStructure(intPtr, typeof(PERSON)); Console.WriteLine("The person after copied is as follows:");
ShowPerson(anotherPerson);
}
catch (ArgumentException)
...{
throw;
}
finally
...{
Marshal.FreeHGlobal(intPtr); //free tha memory
}
}
}
}
要用ref LoginInfo。