在ReturnData中``在Delphi中是什么意思?

时间:2012-01-21 03:51:56

标签: delphi exception

在浏览System.Zip(Delphi XE2)以查看其工作原理时,我发现了这个功能:

procedure VerifyWrite(Stream: TStream; var Buffer; Count: Integer);
begin
  if Stream.Write(Buffer, Count) <> Count then
    raise EZipException.CreateRes(@SZipErrorWrite) at ReturnAddress;
end;

at ReturnAddress部分让我感到困惑。

我不知道at是一个有效的关键字(语法高亮显示器似乎也无法识别它)。

根据IDE,它被声明为System.ReturnAddress,但我只能在procedure _HandleAnyException;的(asm)代码中找到它被声明为标签。系统单元虽然充满了对它的引用。

所以我想知道的是:

  1. 什么是ReturnAddress
  2. Raise Exception.Create ... at ReturnAddress究竟做了什么?
  3. 如果你可以给出一个真实世界的例子,说明这将是一个有用的结构,或者你可以建议不要使用它。

2 个答案:

答案 0 :(得分:20)

ReturnAddress是完成后VerifyWrite将返回的地址。

Raise Exception.Create... at ReturnAddress表示当显示异常对话框时,它会将异常的地址指示为ReturnAddress。换句话说,异常消息将显示为Exception <whatever> raised at <ReturnAddress>: <Exception Message>

以下是Delphi 7帮助文件的摘录。它与the online version几乎相同。

  

要引发异常对象,请使用异常的实例   带有加注声明的类。例如,

raise EMathError.Create;
     

一般来说,加注声明的形式是

raise object at address
     

其中object和at地址都是可选的;看到   重新提出例外。指定地址时   它可以是任何求值为指针的表达式   type,但通常是指向过程或函数的指针。   例如:

raise Exception.Create('Missing parameter') at @MyFunction;
     

使用此选项可以从较早的点引发异常   在堆栈中,而不是实际发生错误的那个。

特别注意最后一句话。关于at <address>的使用非常具体。

答案 1 :(得分:8)

ReturnAddr不是以前Delphi版本的谜题。考虑下一个测试(Delphi XE):

procedure RaiseTest1;

  procedure RaiseException(ReturnAddr: Pointer);
  begin
    raise Exception.Create('OOPS!') at ReturnAddr;
  end;

asm
      POP    EAX
      JMP    RaiseException
end;

procedure RaiseTest2;
begin
  raise Exception.Create('OOPS!');
end;


procedure TForm1.Button3Click(Sender: TObject);
begin
  RaiseTest1;
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  RaiseTest2;
end;

如果您在调试器下按下Button3并在异常消息框中按'Break',调试器将停在

procedure TForm1.Button3Click(Sender: TObject);
begin
  RaiseTest1; // <-- here
end;

如果按下Button4,调试器将停在

procedure RaiseTest2;
begin
  raise Exception.Create('OOPS!');  // <-- here
end;

正如您所看到的,RaiseTest1修改了默认的异常堆栈帧并使调试更加简单,因为RaiseTest1(2)过程的唯一目的是引发异常。

我想XE2中的某些内容发生了变化,因此简化了ReturnAddr语法。