了解邮件处理过程的堆栈跟踪

时间:2017-05-24 10:20:09

标签: delphi delphi-2007

我在主表单上放置了一个TApplicationEvents组件并添加了此事件代码:

procedure TAniWinMainForm.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
begin
    if (ActiveMDIChild is TFormStartDialog) and
       (Msg.Message = WM_KEYDOWN) and (Msg.WParam = VK_F4) then
        Handled := True;
end;

部署应用程序后,我通过以下EurekaLog错误报告向用户报告了EInvalidOp错误:

Modul Name   : KERNELBASE.dll
Typ          : EInvalidOp


|77A4E60A|ntdll.dll   |           |               |NtCallbackReturn                        |         |
|74515EAA|win32u.dll  |           |               |NtUserGetPointerInfoList                |         |
|754595F9|user32.dll  |           |               |GetPointerTouchInfo                     |         |
|778E3923|msvcrt.dll  |           |               |sqrt                                    |         |
|778E388D|msvcrt.dll  |           |               |sqrt                                    |         |
|778E387B|msvcrt.dll  |           |               |_CIsqrt                                 |         |
|778E3870|msvcrt.dll  |           |               |_CIsqrt                                 |         |
|75460AC0|user32.dll  |           |               |SendMessageW                            |         |
|77A235DB|ntdll.dll   |           |               |RtlDeactivateActivationContextUnsafeFast|         |
|75470090|user32.dll  |           |               |CallWindowProcA                         |         |
|00CA5549|Program.exe |MAIN.pas   |TMainForm      |ApplicationEvents1Message               |700[1]   |
|7547BC0B|user32.dll  |           |               |DispatchMessageA                        |         |
|7547BC00|user32.dll  |           |               |DispatchMessageA                        |         |
|00D1376A|Program.exe |Program.dpr|               |                                        |1145[477]|
|772962C2|KERNEL32.DLL|           |               |BaseThreadInitThunk                     |         |

我猜错误与我的代码无关,但我不明白可能会发生什么。 任何人都可以解释什么可能导致这种堆栈跟踪? 难道我不知道哪个函数正在调用CallWindowProcA?

1 个答案:

答案 0 :(得分:2)

我的猜测是CallWindowProcA的来电是ActiveMDIChild。这是一个getter看起来像这样的属性:

function TCustomForm.GetActiveMDIChild: TForm;
begin
  Result := nil;
  if (FormStyle = fsMDIForm) and (FClientHandle <> 0) then
    Result := TForm(FindControl(SendMessage(FClientHandle, WM_MDIGETACTIVE, 0,
      0)));
end;

您希望在调用堆栈中看到紧随SendMessage之上的ApplicationEvents1Message,但我怀疑EurekaLog堆栈跟踪代码不足以在Win32 API函数内部找到它。现在,对SendMessage的调用将调用客户端窗口的窗口过程,因此调用CallWindowProcA非常有意义。

至于实际问题,这很像Win32代码的问题,期望浮点异常被屏蔽。我建议您在引用ActiveMDIChild之前屏蔽异常。

我还强烈建议您更改if声明中条件的顺序。为您的程序处理的每个排队消息调用此事件。你真的不想为每个人阅读ActiveMDIChild属性。像这样写if语句:

if (Msg.Message = WM_KEYDOWN) and
   (Msg.WParam = VK_F4) and
   (ActiveMDIChild is TFormStartDialog) then

所以你可以像这样重写你的事件处理程序:

procedure TAniWinMainForm.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  Save8087CW: Word;
begin
  if (Msg.Message = WM_KEYDOWN) and (Msg.WParam = VK_F4) then
  begin
    Save8087CW := Get8087CW;
    Set8087CW($027F); // this is the default Windows control word, with floating point exceptions masked
    if ActiveMDIChild is TFormStartDialog then
      Handled := True;
    Set8087CW(Save8087CW);
  end;
end;