2011-09-08 71 views
21

我确定这个曾经为我工作,并且我在网上看到过(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; 

回答

20

好吧,打击我!这看起来很错,我必须自己尝试,而且你是对的!我已经缩小了这个事实,即这是操作系统本身而不是德尔福产生的操作系统异常(除以零)。如果你尝试自己提出一个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 

因此如果异常不是一个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); 

玩得开心!

+0

谢谢米莎。我以为我正在放弃情节! – Paul

+0

除零除非是操作系统异常。这是硬件异常,由CPU本身引发(因此,它是异步异常)。 OS和Delphi异常都是软件异常,通过特定的代码调用引发(因此它是同步异常)。因此,问题不在于操作系统和Delphi的异常,而在于Delphi和非Delphi的异常。 “提高;”重新引发原始异常(可能是硬件或软件异常),所以如果原始异常是Delphi异常,那么只保留Delphi对象中的任何更改。这很合乎逻辑。 – Alex

14

查看Misha的解释。作为解决方法,您可以这样做:

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