2011-09-08 43 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;