“Marshal.StructureToPtr”处的访问冲突异常;在 Windows 7 中.NET 4.0(Windows XP + .NET 3.5 工作正常)
这是我的代码:
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 中引发异常?可能是字符集问题?
======================已解决====================== =
解决方案和解释
如您所见,Marshal.StructureToPtr(ebt, ptrStruct, true); 将第三个参数设置为 true。这意味着系统将尝试释放最后为 ptrStruct 分配的内存。但是,当第一次调用方法 Show()
时,没有为该结构分配内存 (ptrStruct = IntPtr.Zero)。因此系统将尝试释放位于零指针的内存。当然它会引发异常。 Windows XP 会忽略这一点,但 Windows 7 不会。
恕我直言,这是最好的解决方案:
Marshal.StructureToPtr(ebt, ptrStruct, false);
//Working...
//Free resources
Marshal.FreeHGlobal(ptrStruct);
Here is my code:
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);
}
And here is the structure:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct EDITBALLOONTIP
{
internal int cbStruct;
internal string pszTitle;
internal string pszText;
internal int ttiIcon;
}
Why does this work fine in Windows XP + .NET 3.5 and raises exceptions in Windows 7 + .NET 4.0? May be it's CharSet trouble?
=====================Solved=======================
Solution and explanation
As you can see Marshal.StructureToPtr(ebt, ptrStruct, true); has third parameter set to true. It means that the system will try to free the last allocated memory for ptrStruct. But when method Show()
is invoked for the first time, there was not allocated memory for that structure (ptrStruct = IntPtr.Zero). So system will try to free memory located at zero pointer. And of course it will raise an exception. Windows XP just ignores this, but Windows 7 doesn't.
And here is best solution IMHO:
Marshal.StructureToPtr(ebt, ptrStruct, false);
//Working...
//Free resources
Marshal.FreeHGlobal(ptrStruct);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不想在这里添加答案,因为你已经解决了你的问题,我所说的不会为你遇到的问题提供任何答案,但它不适合作为评论,因为我提供一些代码。
所以我有义务把它作为答案发布在这里。
你可能已经知道了(并且没有那样写,所以你问题中的代码更简单),但我只想说最好的分配非托管内存时应该到处使用的做法是将代码封装在 try/finally 块中,以确保内存始终释放,即使出现异常抛出:
I didn't want to add an answer here as you already have solved your problem and what I'll say won't provide any answer to the problem you had, but it wouldn't fit well as a comment as I provide some code.
So I'm obliged to post it here as an answer.
You may already know it (and didn't wrote it that way so the code in your question is simpler), but I just wanted to say that a best practice that should be used everywhere when unmanaged memory is allocated, is to encapsulate the code in a try/finally block to ensure the memory is always freed, even if an exception is thrown: