2011-09-08 8 views
21

Estaba seguro de que esto solía funcionar para mí, y lo he visto en la red (Jolyon Smith y David Moorhouse). Después de haberlo probado en un programa simple tanto en D2007 como en XE2, no guarda el Mensaje modificado. Tan pronto como ocurre el "aumento", el mensaje vuelve a la excepción original.¿Por qué se pierden los cambios a un objeto Exception al volver a subirlo?

¿Qué cosa tan obvia me falta? La alternativa es "aumentar Exception.Create (...)", pero solo quiero propocionar la excepción original en la cadena, solo con información adicional etiquetada en cada bloque de excepción.

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; 

Respuesta

20

Bien me explique! Esto se veía tan mal que tuve que probarlo yo mismo, ¡y tienes toda la razón! Lo he reducido al hecho de que esta es una excepción de SO (dividido por cero) que es generado por el propio sistema operativo y no por Delphi. Si intentas subir un EIntError, obtienes el comportamiento esperado y no lo que ves arriba. Tenga en cuenta que el comportamiento esperado ocurre cada vez que plantea una excepción usted mismo.

Actualización: En la unidad System.pas existe el siguiente código que se llama cuando se re-lanzó la excepción:

{ 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 

lo tanto, si la excepción no es una excepción Delphi (en este caso un sistema operativo excepción), luego se libera la excepción (modificada) "Delphi" y se vuelve a generar la excepción original, descartando así cualquier cambio realizado en la excepción. ¡Caso cerrado!

Actualización 2: (no pude evitarlo). Puede reproducir esto con el siguiente código:

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); 

Have fun!

+0

Gracias Misha. ¡Pensé que estaba perdiendo la trama! – Paul

+0

La división por cero no es una excepción de sistema operativo. Es una excepción de hardware, planteada por la propia CPU (por lo tanto, es una excepción asíncrona). Las excepciones de OS y Delphi son excepciones de software, aumentan mediante llamadas de código específicas (por lo tanto, es una excepción de sincronización). Por lo tanto, el problema en cuestión no se trata de excepciones de OS y Delphi, sino de excepciones de Delphi y de Delphi. "aumento;" vuelve a subir la excepción original (que puede ser una excepción de hardware o software), por lo que cualquier cambio en el objeto Delphi solo se conservará si la excepción original fue la excepción Delphi. Eso es bastante lógico. – Alex

14

Consulte la explicación de Misha. Como solución, puede hacer esto:

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