1、是否运用到了unsafe模式下的非托管内存,是否有两个线程共同访问一个公共对象的情况
在unsafe模式操作非托管内存的情况下,第一个线程使用完这个对象就把这个对象清空,这时候第二个线程正在使用这个对象,就会因为内存中找不到这个内存区域而报错:“尝试读取或写入受保护的内存。这通常指示其他内存已损坏”。
在C#托管内存中,内存回收一般是有GC自动完成的,如果遇到找不到找不到对象的情况,报错信息是“未将对象引用设置到对象的实例”,而非托管内存的找不到对象报错信息是:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。
因为一个非托管对象的操作方式是指针,当内存中的对象被清理掉时,这段内存地址就拒绝指针随意访问,这事指针如果继续访问这段内存,就会报尝试读取或写入受保护的内存这个错误
2、读取或写入受保护
dll文件应该是C++写的。封装了之后供我的C#程序调用,结果就提示了错误:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。错误类型为:System.AccessViolationException。
跨线程操作引起的?因为我的dll控制的是硬件,应该绑定的是窗体句柄。我操作的时候是在一个事件event中操作的,大家知道event是另开线程的。
private delegate void CloseDevDelegate();
private void CloseDev()
{
if (this.InvokeRequired)
{
CloseDevDelegate closeDev = new CloseDevDelegate(CloseDev);
this.BeginInvoke(closeDev);
}
else
{
Program.DEVICE.CloseDev();
}
}
在事件中使用:CloseDev()
在事件中使用:CloseDev()
3、在C#中调用别人的DLL的时候有时候出现 尝试读取或写入受保护的内存 。这通常指示其他内存已损坏。
在传值的时候还是用指针,再在C#中做转换就好了。
[DllImport("APPLISTCC.dll")]
public static extern string TestFunc1(string param1);
string ret1 = TestFunc1("text");
改成:
[DllImport("APPLISTCC.dll")]
public static extern IntPtr TestFunc1(IntPtr par1);
IntPtr ptrIn = Marshal.StringToHGlobalAnsi("text");
IntPtr ptrRet = TestFunc1(ptrIn);
string retlust = Marshal.PtrToStringAnsi(ptrRet);
自己在程序里强制释放COM资源,调用Marshal.ReleaseComObject()方法将不再使用的对象释放掉
4、测试的可执行文件与 Windows 数据执行保护功能兼容
调用dll的程序,在运行时会出现 “尝试读取或写入受保护的内存。这通常指示其他内存已损坏。"
有关更多信息,请参见 /NXCOMPAT(与数据执行保护兼容)。
编译器中加入了对DEP的安全性检查,在编译完后的exe文件中取消NXCOMPAT位可解决该问题
editbin.exe /NXCOMPAT:NO myexe
5、调用dll动态链接库的时候,参数类型是非常重要的,如果类型不对,就会出现本文这样的错误
C#中开始是这样的引入DLL的,参数分别是long类型与结构体类型,本身和DLL api里面的类型一样
在C#调用DLL动态链接库方法的时候,传值的时候自然也要做一些改变,引用类型的值要加入“ref”关键字,值类型(如com)则直接传入数字或变量名即可