Reputation: 2206
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.
Upvotes: 5
Views: 859
Reputation: 42152
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.
Upvotes: 9
Reputation: 26830
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 ...
Upvotes: 0