【问题标题】:Access violation in delphidelphi中的访问冲突
【发布时间】:2011-11-30 09:38:10
【问题描述】:

在 delphi 应用程序中,当我将鼠标移动到具有提示的组件时,我看到此错误: “模块‘Plibrary.exe’中地址00484F3B的访问冲突。读取地址0000026C” 为什么会这样?

调用栈:

:758e9617 KERNELBASE.RaiseException + 0x54 
:458bf456 System.@UStrCmp 
:00407558 @UStrCmp + $2C 
Forms.TApplication.SetHint(???) 
Forms.TApplication.Idle(???) 
Forms.TApplication.HandleMessage 
Forms.TApplication.Run Plibrary.Plibrary 
:75ca1194 kernel32.BaseThreadInitThunk + 0x12 
:7752b3f5 ntdll.RtlInitializeExceptionChain + 0x63 
:7752b3c8 ntdll.RtlInitializeExceptionChain + 0x36" 

失败的代码在 System.pas 文件的第 17732 行:“MOV ESI,[ESP]”

编辑(来自评论):

在此过程的剩余.pas 文件中:

procedure TMainForm.ShowHint(Sender: TObject); 
begin 
  if Length(Application.Hint) > 0 then begin 
    StatusBar.SimplePanel := True; 
    StatusBar.SimpleText := Application.Hint; //this line gives error 
  end else    
    StatusBar.SimplePanel := False; 
end;

【问题讨论】:

  • 您至少需要包含一个堆栈跟踪。它可能是鼠标悬停事件中某处的空引用或其他东西。
  • 这意味着出了点问题。你有一个应用程序..写在哪个Delphi版本?您有带有提示的组件...哪个组件?该组件是在运行时创建的吗?如果您不提供更多解释,我们无法猜测为什么会出现此错误
  • 我使用“RAD Studio 2009 Version 12.0.3170.16989”,我的组件是“BitBtn”,这个组件在子窗体上,窗体是在运行时创建的。
  • 您可以显示运行时表单的创建。这很可能会搞砸。

标签: delphi delphi-2009


【解决方案1】:

读取地址 0000026C

这个非常低的地址表示nil 对象引用的成员字段的偏移量。在调试器下运行并确保调试器设置为在出现异常时中断。当它出现时,您应该能够确定哪个对象引用是nil

AV 很可能发生在 VCL 代码中,尽管它几乎可以肯定是由于您的代码中的错误。如果调试器没有在非常有用的位置中断,请在项目选项中启用调试 DCU,以便在引发异常的位置查看 VCL 源代码。

您提供的堆栈跟踪表明错误在TApplication.SetHint 中,同时执行字符串比较。 TApplication.SetHint 的第一行写着:

if FHint <> Value then

我打赌TApplicationFHint 的偏移量是$026C,而且不知何故,您的Application 变量设置为nil。也就是说,我不明白为什么在Length(Application.Hint) 之前不会提出错误。远程调试非常困难!

看了TApplication的布局,我想我们可以排除Applicationnil。也许FHint 本身已经被破坏了,或者甚至可能是Value。我认为它会访问实际代码和调试环境来跟踪它。

【讨论】:

  • 我使用“RAD Studio 2009 Version 12.0.3170.16989”,我的组件是“BitBtn”,这个组件在子窗体上,窗体是在运行时创建的。
  • 通过堆栈跟踪向我们提供异常的详细信息,我们将告诉您我们需要哪些代码来帮助您解决问题。告诉我们你用什么开发环境没用。
  • 当我在项目选项中启用调试 DCU 时,我看到此错误:“异常类 EIntOverflow 带有消息‘整数溢出’。处理 Plibrary.exe (3164)”
  • 你是在调试器下运行的吗?如果是这样,请这样做。当你这样做时,调试器应该在失败的代码处中断。
  • 调用堆栈(堆栈跟踪窗口)位于 View->Debug Windows->Call Stack,或 Ctrl+Alt+S
【解决方案2】:

根据堆栈跟踪中提供的信息:

TApplication.Idle:

Control := DoMouseIdle;
if FShowHint and (FMouseControl = nil) then
  CancelHint;
Application.Hint := GetLongHint(GetHint(Control)); // SetHint is called next:

TApplication.SetHint:

if FHint <> Value then // This is the UStrCmp which fails with a Int overflow

String + IntOverflow -> 非终止字符串。所以最可能的原因是没有终止符的字符串。

那么字符串是从哪里来的……

  • GetHint(Control) 搜索控件(位于您用光标单击的位置)及其父级以查找非空提示。

  • GetLongHint 在字符串中搜索 |如果找到,则使用 | 后面的部分否则它使用完整的字符串。

  • USrCmp,是一段很长的汇编代码,它调用其他的汇编代码。其中一些可能会引发 EIntegerOverflow 错误。

建议

使用调试器(打开调试 dcu)查看哪个字符串没有终止符(末尾为 0 个字符)。如果您找到它,请尝试解决它或扩展问题,如果您需要我们提供更多帮助。

【讨论】:

  • 肯定UStrCmp 使用字符串长度而不是零终止符?
  • 是的,UStrCmp() 确实依赖于字符串的嵌入长度字段,而不是空终止符。所以很有可能FHintValue 没有指向一个有效的String 变量开头(我猜FHint,这表明Application 对象指针为零)。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多