访问冲突异常,位于';Marshal.StructureToPtr';在Windows 7+.NET 4.0
本文关键字:Windows NET Marshal 异常 位于 访问冲突 StructureToPtr | 更新日期: 2023-09-27 18:21:25
这是我的代码:
internal void Show()
{
if (Parent == null)
throw new NullReferenceException();
EDITBALLOONTIP ebt = new EDITBALLOONTIP();
ebt.cbStruct = Marshal.SizeOf(ebt);
ebt.pszText = Text;
ebt.pszTitle = Caption;
ebt.ttiIcon = (int)Icon;
IntPtr ptrStruct = Marshal.AllocHGlobal(Marshal.SizeOf(ebt));
Marshal.StructureToPtr(ebt, ptrStruct, true); // Here we go.
// Access violation exception in Windows 7 + .NET 4.0
// In Windows XP + .NET 3.5, it works just fine.
// ... Some other code ...
Marshal.FreeHGlobal(ptrStruct);
}
结构如下:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct EDITBALLOONTIP
{
internal int cbStruct;
internal string pszTitle;
internal string pszText;
internal int ttiIcon;
}
为什么这在Windows XP+.NET 3.5中运行良好,而在Windows 7+.NET 4.0中引发异常?可能是CharSet的问题?
=====================已解决===================
解决方案及说明
如您所见,Marshal.StructeToPtr(ebt,ptrStruct,true)将第三个参数设置为true。这意味着系统将尝试为ptrStruct释放最后分配的内存。但当第一次调用方法Show()
时,没有为该结构分配内存(ptrStruct=IntPtr.Zero)。因此系统将尝试释放位于零指针处的内存。当然,这将引发一个例外。Windows XP只是忽略了这一点,但Windows 7没有。
这里是最好的解决方案IMHO:
Marshal.StructureToPtr(ebt, ptrStruct, false);
//Working...
//Free resources
Marshal.FreeHGlobal(ptrStruct);
我不想在这里添加答案,因为你已经解决了你的问题,我所说的不会为你的问题提供任何答案,但它不适合作为注释,因为我提供了一些代码。所以我不得不把它作为一个答案贴在这里
你可能已经知道了(并且没有这样写,所以你问题中的代码更简单),但我只想说,当分配非托管内存时,应该在任何地方使用的最佳实践是将代码封装在try/finaly块中,以确保总是释放内存,即使抛出异常:
private static void Test()
{
IntPtr ptrStruct = IntPtr.Zero;
try
{
Marshal.AllocHGlobal(0x100);
// Some code here
// At some point, an exception is thrown
throw new IndexOutOfRangeException();
}
finally
{
// Even if the exception is thrown and catch
// from the code that calls the Test() method,
// the memory will be freed.
if (ptrStruct != IntPtr.Zero)
{
Marshal.FreeHGlobal(ptrStruct);
}
}
}
try
{
Test();
}
catch (IndexOutOfRangeException)
{
// Catches the exception, so the program won't crash
// but it'll exit the Test() method, so the try/finally
// ensures it won't leave without freeing the memory
Debugger.Break();
}