重新提升时,为什么对Exception对象的更改会丢失?

Pau*_*aul 23 delphi exception

我确信这曾经适合我,我已经在网上看到了它(Jolyon Smith和David Moorhouse).刚刚在D2007和XE2试用版中的一个简单程序中尝试过它,它不会保留修改后的消息.一旦"加注"发生,该消息将恢复为原始异常.

我错过了什么盲目明显的事情?另一种方法是"引发Exception.Create(...)",但我想只是在链上传播原始异常,只是在每个异常块上标记了附加信息.

var a: Integer;
begin
  try
    a := 0;
    Label1.Caption := IntToStr(100 div a);
  except
    on e: Exception do
    begin
      e.Message := 'Extra Info Plus the original : ' + e.Message;
      raise;
    end;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

Mis*_*sha 21

好吧吹我!这看起来很错,以至于我不得不亲自尝试,你说得对!我把它缩小到这样一个事实,即这是一个操作系统异常(除以零),它是由操作系统本身产生的,而不是由德尔福产生的.如果您尝试自己引发EIntError,则会得到预期的行为,而不是您在上面看到的行为.请注意,每当您自己引发异常时都会发生预期的行为.

更新:在System.pas单元中,重新引发异常时调用以下代码:

{ Destroy any objects created for non-delphi exceptions }

MOV     EAX,[EDX].TRaiseFrame.ExceptionRecord
AND     [EAX].TExceptionRecord.ExceptionFlags,NOT cUnwinding
CMP     [EAX].TExceptionRecord.ExceptionCode,cDelphiException
JE      @@delphiException
MOV     EAX,[EDX].TRaiseFrame.ExceptObject
CALL    TObject.Free
CALL    NotifyReRaise
Run Code Online (Sandbox Code Playgroud)

因此,如果异常不是Delphi异常(在这种情况下是OS异常),则释放(修改的)"Delphi"异常并重新引发原始异常,从而丢弃对异常所做的任何更改.案件结案!

更新2 :(无法帮助自己).您可以使用以下代码重现此:

type
  TThreadNameInfo = record
    InfoType: LongWord;  // must be $00001000
    NamePtr: PAnsiChar;  // pointer to message (in user address space)
    ThreadId: LongWord;  // thread id ($ffffffff indicates caller thread)
    Flags: LongWord;     // reserved for future use, must be zero
  end;

var
  lThreadNameInfo: TThreadNameInfo;

  with lThreadNameInfo do begin
    InfoType := $00001000;
    NamePtr := PAnsiChar(AnsiString('Division by zero'));
    ThreadId := $ffffffff;
    Flags := $00000000;
  end;
  RaiseException($C0000094, 0, sizeof(lThreadNameInfo) div sizeof(LongWord), @lThreadNameInfo);
Run Code Online (Sandbox Code Playgroud)

玩得开心!


Ond*_*lle 15

见Misha的解释.作为解决方法,您可以这样做:

except
  on E: Exception do
  begin
    E := Exception(ExceptObject);
    E.Message := '(Extra info) ' + E.Message;
    AcquireExceptionObject;
    raise E;
  end;
end;
Run Code Online (Sandbox Code Playgroud)