在我自己的程序中,我正在尝试使用此代码将工具提示气球窗口添加到我的应用程序:http://www.codeproject.com/Articles/4991/Balloon-Tips-Galore(此处提供源代码)
我尝试编译演示程序,它在32位Windows 7上运行正常,但是当我尝试在64位Windows 7上使用它时程序崩溃了。如果我尝试在VS2010中调试崩溃,我会收到以下消息:
调试器位于源代码不可用的某个区域,并显示Call stack location: ntdll.dll!0000000076fe40f2()
如何解决这个问题,以免在64位上崩溃?
答案 0 :(得分:4)
我无法在Windows Server 2003 x64(这是我目前唯一的64位环境)上进行C#演示崩溃,但是代码有问题所以你看到意外的行为是有道理的
编辑: 使用原始代码重现Windows Server 2008 R2 x64中的崩溃,并验证了此修复程序的效果。
As Christian.K points out,问题has been noted before。调用Marshal.StructureToPtr
方法时,如果指定的内存块不包含有效数据,则应将true
传递给第三个fDeleteOld
参数 。这在the documentation中非常明确地被称为,所以我不确定原作者是如何弄错的。
在这种情况下,由于数据刚刚通过调用Marshal.AllocHGlobal
分配了该行,因此它不包含有效数据,不应删除/释放。更改很简单:将第三个参数true
更改为false
。不幸的是,因为互操作代码分散在示例项目中的三个不同类中,所以您必须将更改放在多个位置。你正在寻找的模式是:
IntPtr ptrStruct = Marshal.AllocHGlobal(Marshal.SizeOf(ti));
Marshal.StructureToPtr(ti, ptrStruct, false /* <-- change this from true to false */);
正如一般观察:代码尝试手动处理大量的互操作(通过使用Marshal
类的方法),而不是让CLR自动处理它。我很多更喜欢后一种方法。即使我完全理解如何手动完成所有的互操作,让系统为我管理它可以减少我犯的错误数量并导致堆损坏。
RhysW说他之前从未遇到过堆损坏,但是当你开始在.NET代码和Win32 API之间进行互操作时,它变得非常普遍。 .NET Framework不再保护您。
有关我的意思的示例,请注意FMSBalloonTip.SetToolTip
方法使用Marshal.StringToHGlobalAuto
方法将包含工具提示标题的字符串编组为指针。虽然这当然有效(并且非常谨慎地将指针在完成后释放),但是声明接受{{1}的SendMessage
函数的重载会更容易且更不容易出错。 object作为第四个参数。这样,框架将透明地为您处理所有必要的互操作。
当然,真正的问题是你需要这个代码的原因。 方式更容易使用内置的ToolTip
class ,从一开始就可以使用。我不确定你是否只是没有提到string
未提供的某些功能,或者您只是不知道它,但我强烈建议您重新考虑您的设计,以便您可以使用内置类,让Microsoft程序员处理所有的互操作。
如果是您正在寻找的气球部分,请务必设置ToolTip
课程的IsBalloon
property。直到.NET 2.0才引入,但这与示例项目所针对的版本相同。