2010-08-04 17 views
6

Actualización: Parece ser específico para D2007. Funciona en D2010 como si funcionó en una versión anterior.¿Cómo devolver un código de error con Alto (n) desde un bloque de Excepción con D2007?

me gustaría devolver un código de salida en función del tipo de excepción detectada en el bloque eception Handler como:

program test; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

var 
    Exitcode: Integer; 
begin 
    Writeln('Enter error code:'); 
    Readln(Exitcode); 
    try 
    raise EExternal.Create('sdsdkfjh'); 
    except 
    on E:EExternal do 
    begin 
     Writeln(E.Classname, ': ', E.Message); 
     Halt(Exitcode); 
    end; 
    end; 
end. 

Por desgracia, en D2007, llamando Halt (n) a partir de un bloque de excepción siempre devuelve un código de salida 1, pase lo que pase a Halt().

Al parecer debido a la salida de un controlador de excepciones llamadas Finalizar, que borra las excepciones pendientes (no renunciar), llamando SysUtils.ExceptHandler:

procedure ExceptHandler(ExceptObject: TObject; ExceptAddr: Pointer); far; 
begin 
    ShowException(ExceptObject, ExceptAddr); 
    Halt(1); // <= @#$##@#$! 
end; 

Y no importa lo que el código de salida que quería consigo que Halt(1)!

Así que la pregunta es:
Como puedo devuelva el código de salida deseada dependiendo de la excepción fue levantado?

+0

Basado en el comentario anterior de Mike, lo cual es cierto, de hecho lo hace volver el código de error correcto. Sospecho que es el método que utiliza para obtener el Código de Error que podría no funcionar como se esperaba. – zz1433

+0

@ Aldo. No, es D2007. Lo mismo se comporta de manera diferente con D2007 y D2010, donde está de vuelta como esperaba e informado por Mike. –

+0

Por favor presente un gran informe en QC (http://qc.embarcadero.com/); aunque probablemente no habrá una actualización D2007, es bueno poder ver qué errores son 'conocidos'. –

Respuesta

5

¿Funcionará?

NeedHalt := False; 
try 
    raise EExternal.Create('sdsdkfjh'); 
except 
    on E:EExternal do 
    begin 
    Writeln(E.Classname, ': ', E.Message); 
    NeedHalt := True; 
    end; 
end; 
if NeedHalt then 
    Halt(Exitcode); 

¿o este?

try 
    raise EExternal.Create('sdsdkfjh'); 
except 
    on E:EExternal do 
    begin 
    Writeln(E.Classname, ': ', E.Message); 
    AcquireExceptionObject; 
    Halt(Exitcode); 
    end; 
end; 

Anyway: it's a bug in D2007, which was fixed in D2010.

+0

¡Gracias! +1 para 'AcquireExceptionObject' está haciendo el truco para mí como una solución en D2007. Eso fue un buen insecto, de hecho ... –

2

En realidad ... parece que funciona como se esperaba ....

he utilizado el código ...

program test1; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

var 
    Exitcode: Integer; 
begin 
    Writeln('Enter error code:'); 
    Readln(Exitcode); 
    try 
    raise EExternal.Create('sdsdkfjh'); 
    except 
    on E:EExternal do 
    begin 
     Writeln(E.Classname, ': ', E.Message); 
     Halt(Exitcode); 
    end; 
    end; 
end. 

compilada en en Delphi 5, y luego corrió en una ventana DOS en XP ...

C:\>test1 
Enter error code: 
111 
EExternal: sdsdkfjh 

C:\>echo %errorlevel% 
111 

C:\> 

Tenga en cuenta que los niveles de error de DOS están restringidos a un rango de 0 a 65535. Haciéndose eco% errorlevel% es la forma más rápida para ver el nivel de error.

No olvide que leer el errorlevel lo borra.

+1

¡Ya no funciona en D2007! ¡Pero gracias por confirmar que solía funcionar! Estaba bastante seguro de haberlo hecho de esa manera antes ... ;-) –

+1

Y también funciona en D2010. El mismo código exacto, la misma forma exacta de probar errorlevel me da lo que quiero en D2010, como para ti con D5, pero con D2007, ¡siempre obtengo 1! –

2

Si desea cancelar inmediatamente el programa sin ningún tipo de limpieza y devolver un código de salida, intente ExitProcess. Sin embargo, ver el artículo para algunas advertencias sobre el uso de ExitProcess.

+0

+1 para ExitProcess. Es un poco duro para mi caso actual, pero vale la pena ser recordado. –

-1

Si la función de control de excepciones incorporada no hace lo que le gusta, entonces sustituirlo por el suyo propio:

function ExitCodeExceptHandler(ExceptObject: TObject; ExceptAddr: Pointer); 
begin 
    ShowException(ExceptObject, ExceptAddr); 
    if ExitCode = 0 then 
    ExitCode := 1; 
    Halt(ExitCode); 
end; 

Asignar a la que System.ExceptProc variable global cuando el programa comienza:

ExceptProc := @ExitCodeExceptHandler; 

Lo he implementado para usar la variable global ExitCode. Si todavía está en su valor predeterminado de 0, la función vuelve al comportamiento Delphi original de salir con 1, pero si el código de salida ya se ha establecido en otra cosa, se detendrá con ese valor. Lo primero que hace Halt es establecer la variable global ExitCode, por lo que su código no debería necesitar más cambios (aunque elegiría un nombre diferente para la variable Exitcode). Su llamada al Halt configurará la variable global ExitCode y luego procederá a cerrar el programa. El manejador de excepciones notará que ExitCode ya está configurado y vuelve a llamar al Halt con ese valor en lugar de 1.

+5

Desafortunadamente, no funciona. Primero, debe ser un procedimiento, no una función, pero más importante al llegar a 'DoneExceptions', el código reinicia' ExceptProc: = nil' y luego llama directamente 'if (ExceptObject <> nil) y no (ExceptObject es EAbort) luego ExceptHandler (ExceptObject, ExceptAddr); ' –

0

Usando alto (I) genera pérdidas de memoria (puede ver que si habilitó las MemoryLeaks FastMM con ReportMemoryLeaksOnShutdown: = true;)

Es mucho mejor usar una salida "limpia" y establecer ExitCode antes de salir .

En una sección principal de una aplicación de consola, por ejemplo:

ExitCode:=I; 
exit; 
Cuestiones relacionadas