Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ExceptProc not being called in Windows

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.

like image 931
Chris J Avatar asked Mar 02 '23 06:03

Chris J


1 Answers

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.

like image 54
Barry Kelly Avatar answered Mar 11 '23 00:03

Barry Kelly