了解消息处理过程的堆栈跟踪
Understanding stack trace for message handling procedure
我在我的主窗体上放置了一个 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 吗?
我的猜测是 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;
您希望在调用堆栈中的 ApplicationEvents1Message
上方看到 SendMessage
,但我怀疑 EurekaLog 堆栈跟踪代码不够好,无法在 Win32 API函数。现在对 SendMessage
的调用将调用客户端 window 的 window 过程,因此对 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(7F); // this is the default Windows control word, with floating point exceptions masked
if ActiveMDIChild is TFormStartDialog then
Handled := True;
Set8087CW(Save8087CW);
end;
end;
我在我的主窗体上放置了一个 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 吗?
我的猜测是 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;
您希望在调用堆栈中的 ApplicationEvents1Message
上方看到 SendMessage
,但我怀疑 EurekaLog 堆栈跟踪代码不够好,无法在 Win32 API函数。现在对 SendMessage
的调用将调用客户端 window 的 window 过程,因此对 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(7F); // this is the default Windows control word, with floating point exceptions masked
if ActiveMDIChild is TFormStartDialog then
Handled := True;
Set8087CW(Save8087CW);
end;
end;