Win64下DrawText函数异常行为:为何需临时变量?
Win64环境下DrawText调用需临时变量的原因
我有一个包含单个项目'ABC'的ListBox,以下代码在Win32环境下运行正常:
h := DrawText(ListBox1.Canvas.Handle, PChar(ListBox1.Items[0]), -1, R, DT_CALCRECT);
执行该行代码后,h = 19,结果正确。但在Win64环境下运行相同代码时返回h = 0,调用SysErrorMessage(GetLastError)返回“操作已成功完成”。
若将代码修改为以下形式,则在Win32和Win64环境下均可正常运行,修改后Win32和Win64环境下h = 19:
s := ListBox1.Items[0]; h := DrawText(ListBox1.Canvas.Handle, PChar(s), -1, R, DT_CALCRECT);
原因分析
核心差异来自64位Delphi的字符串生命周期管理机制:
- 在32位Delphi中,
ListBox1.Items[0]返回的是字符串的直接引用,PChar()强制转换后能拿到有效内存指针,DrawText可以正常读取文本内容完成计算。 - 但在64位Delphi里,
ListBox1.Items[0]返回的是临时字符串实例,它的生命周期仅局限于当前表达式内部。当直接把PChar(ListBox1.Items[0])作为参数传给DrawText时,由于表达式求值顺序的问题,这个临时字符串可能在DrawText开始执行前就被销毁了——导致传入的指针指向无效内存,DrawText无法正确读取文本,最终返回0。 - 用临时变量
s接收ListBox1.Items[0]后,字符串的生命周期被延长到变量s的作用域内,PChar(s)指向的内存在DrawText执行期间始终有效,因此能正确计算出文本高度。
至于GetLastError返回“操作已成功完成”,是因为DrawText检测到指针无效时,并未触发系统级别的错误,只是返回0表示计算失败,此时系统错误码仍保留着之前操作的成功状态。
内容的提问来源于stack exchange,提问作者dwrbudr
相关产品推荐
相关产品推荐

