在我自己的程序中,我尝试在此处使用此代码将工具提示气球窗口添加到我的应用程序:http://www.codeproject.com/Articles/4991/Balloon-Tips-Galore (此处提供源代码)
我尝试编译演示程序,它在 32 位 Windows 7 上运行良好,但当我尝试在 64 位 Windows 7 上使用它时,程序崩溃了。如果我尝试调试 VS2010 中的崩溃,我会收到此消息:
调试器位于源代码不可用的某些区域,它显示 Call stack location: ntdll.dll!0000000076fe40f2()
如何解决此问题,使其不会在 64 位上崩溃?
最佳答案
我无法让 C# 演示在 Windows Server 2003 x64(这是我目前唯一可用的 64 位环境)上崩溃,但代码有问题,所以你看到意外行为是有道理的.
编辑:使用原始代码重现了 Windows Server 2008 R2 x64 中的崩溃,并验证了修复的有效性。
As Christian.K points out , 问题has been noted before .当调用Marshal.StructureToPtr
方法时,您应该为第三个fDeleteOld
参数传递true
only 当指定的内存块不包含有效数据。这在 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
方法将包含工具提示标题的字符串编码为指针。虽然这确实有效(值得庆幸的是,作者在完成后小心地释放了指针),但声明 SendMessage
string
对象作为第四个参数。这样,该框架将透明地为您处理所有必要的互操作内容。
当然,真正的问题是您为什么需要这段代码。 使用内置的 ToolTip
class 更容易 ,从一开始就可用。我不确定您是否只是没有提到 ToolTip
没有提供的某些您需要的功能,或者您只是不知道,但我强烈建议您重新考虑您的设计,以便您可以利用内置类,让 Microsoft 程序员处理所有互操作性内容。
如果您要查找的是气球部分,请确保设置IsBalloon
property ToolTip
类。直到 .NET 2.0 才引入它,但它与示例项目所针对的版本相同。
关于c# - 64 位 Windows 上的气球工具提示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14879568/