4

我目前正在尝试创建一个内置到我的 Windows 服务中的异常处理程序,当出现未处理的异常时,它会向另一个程序发送消息。我已经构建了该方法并使通信正常工作,但似乎每次我的程序抛出错误时,(我在代码中有一个 raise 调用来强制它。)windows 会捕获它而不调用 Handler。谁能解释我做错了什么?

简化代码解释:

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

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

我调用这段代码来运行它:

WriteLn('Starting');    

ExceptProc := @ExceptionHandler;    

unhandled();

我希望输出是:

起始
显示:未处理

但它所做的只是显示:

开始

然后 Windows 在大约 5 秒后返回命令提示符。

为什么没有正确调用处理程序?

PS 我一直在控制台应用程序中运行这些测试以进行测试。

编辑:

这里有一些更多信息:

显然,当您有一个分配的 exceptProc 时,您的程序不应该抛出正常的运行时 217 错误。我猜这就是windows正在捕获的东西,但是据我所见,我的程序正在抛出运行时错误,我也无法让ErrorProc来捕获它。

4

2 回答 2

8

您错过了对SetErrorMode()的调用:

SetErrorMode(SEM_NOGPFAULTERRORBOX);

这是防止操作系统未处理的异常过滤器显示对话框/显示调试器附加对话框所必需的。这是一个在我的机器上按预期运行的完整示例:

{$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.

请注意,SetErrorMode() 的效果在正在运行的进程中的所有线程中都是全局的。

于 2008-10-22T19:50:36.780 回答
0

有趣的。

如果您在 Delphi IDE 中运行应用程序(在 2007 中尝试过),则会调用自定义异常处理程序,但如果您从命令提示符运行它则不会。

另一个有趣的事情 - 我将主程序代码更改为

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

并注意到只有在我按下 Enter 键后才会显示异常消息(以获取 Readln 的一些输入)。因此,当异常发生时不会调用您的处理程序,而是在处理它时调用(在包含所有代码的隐式 try..except 中)。有道理。

必须是这个隐式尝试的东西..除了那个,但我在这台机器上缺少一个非 Delphi 调试器,无法进一步挖掘。也许其他人知道答案...

于 2008-10-22T18:45:55.537 回答