1

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

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

在此处输入图像描述

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

我该如何解决这个问题,使其不会在 64 位上崩溃?

4

1 回答 1

4

我无法在 Windows Server 2003 x64(这是我目前使用的唯一 64 位环境)上使 C# 演示崩溃,但代码有问题,因此您看到意外行为是有道理的。

编辑:使用原始代码重现了 Windows Server 2008 R2 x64 中的崩溃,并验证了修复的有效性。

正如 Christian.K 所指出的,这个问题之前已经注意到了。调用该方法时,当指定的内存块不包含有效数据时才Marshal.StructureToPtr应传递true第三个fDeleteOld参数。这在文档中非常明确地指出,所以我不确定原作者是如何弄错的。

在这种情况下,由于数据只是通过调用前一行分配的Marshal.AllocHGlobal,它不包含有效数据,不应该被删除/释放。更改很简单:将第三个参数更改truefalse. 不幸的是,由于互操作代码分散在示例项目中的三个不同类中,您必须在多个地方进行更改。您正在寻找的模式是这样的:

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方法来编组包含工具提示标题的字符串作为指针。SendMessage虽然这确实有效(谢天谢地,作者在完成后很小心地释放了指针),但声明接受string对象作为第四个参数的函数的重载会容易得多,也不容易出错。这样,框架将为您透明地处理所有必要的互操作内容。

当然,真正的问题是为什么你需要这段代码。使用从一开始就可用的内置ToolTip要容易得多。我不确定您是否只是没有提及您需要的某些ToolTip未提供的功能,或者您只是不知道,但我强烈建议您重新考虑您的设计,以便您可以使用内置类并让微软程序员处理所有互操作的东西。

如果它是您要查找的气球部分,请确保设置类的IsBalloon属性ToolTip。这直到 .NET 2.0 才引入,但这与示例项目的目标版本相同。

于 2013-02-14T19:11:16.983 回答