views:

319

answers:

2

I am currently trying to create an Exception handler built into my windows service that, on an unhandled exception, sends a message to another program. I have built the method and gotten the communication working, but it seems that every time my program throws the error, (I have a raise call in the code to force it.) windows catches it instead and the Handler isn't called. Can anyone explain what I am doing wrong?.

Simplified Code to explain:

procedure unhandled();
  begin
    raise Exception.Create('Unhandled');
  end;

procedure ExceptionHandler(ExceptObject: TObject; ExceptAddr: Pointer);
  begin
    WriteLn('Display: ' + Exception(ExceptObject).Message);
    //send Message Here
  end;

I call this code to run it:

WriteLn('Starting');    

ExceptProc := @ExceptionHandler;    

unhandled();

I would expect the output to be:

Starting
Display: Unhandled

but all it does is display:

Starting

Then windows returns a command prompt after about 5 seconds.

Why isn't the handler being properly called?

P.S. I've been running these tests in a console app for testing.

EDIT:

Here's some more information:

Apparently when you have an assigned ExceptProc, your program shouldn't throw the normal runtime 217 error. I'm guessing this is what windows is catching, From what I can see however, my program is throwing that runtime error, and I can't get an ErrorProc to catch it either.

A: 

Interesting.

Custom exception handler is called if you run the app in Delphi IDE (tried with 2007) but not if you run it from the command prompt.

Another interesting thing - I changed the main program code to

begin
  WriteLn('Starting');
  try
    ExceptProc := @ExceptionHandler;
    Unhandled;
  finally Readln; end;
end.

and noticed that exception message is only displayed AFTER I press the Enter key (to get some input to the Readln). Therefore, your handler is not called when exception occurs but when it is handled (in implicit try..except that wraps all your code). Make sense.

Must be something with this implicit try..except then, but I lack a non-Delphi debugger on this machine and can't dig further. Maybe somebody else knows the answer ...

gabr
+6  A: 

You are missing a call to SetErrorMode():

SetErrorMode(SEM_NOGPFAULTERRORBOX);

This is needed to prevent the OS unhandled exception filter from showing a dialog box / displaying the debugger attach dialog box. Here's a complete sample that behaves as expected on my machine:

{$apptype console}

uses Windows, SysUtils;

procedure unhandled();
begin
  raise Exception.Create('Unhandled');
end;

procedure ExceptionHandler(ExceptObject: TObject; ExceptAddr: Pointer);
begin
  Writeln('here');
  WriteLn('Display: ' + Exception(ExceptObject).Message);
  Flush(Output);
  Halt(1);
end;

procedure Go;
begin
  unhandled;
end;

begin
  ExceptProc := @ExceptionHandler;
  SetErrorMode(SEM_NOGPFAULTERRORBOX);
  Go;
end.

Note that the effect of SetErrorMode() is global across all threads in the running process.

Barry Kelly