64位Windows上的气球工具提示

时间:2013-02-14 16:32:56

标签: c# .net winforms 64-bit

在我自己的程序中,我正在尝试使用此代码将工具提示气球窗口添加到我的应用程序:http://www.codeproject.com/Articles/4991/Balloon-Tips-Galore(此处提供源代码)

我尝试编译演示程序,它在32位Windows 7上运行正常,但是当我尝试在64位Windows 7上使用它时程序崩溃了。如果我尝试在VS2010中调试崩溃,我会收到以下消息:

enter image description here

调试器位于源代码不可用的某个区域,并显示Call stack location: ntdll.dll!0000000076fe40f2()

如何解决这个问题,以免在64位上崩溃?

1 个答案:

答案 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才引入,但这与示例项目所针对的版本相同。