我在主窗体上放置了一个 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
的调用将调用客户端窗口的窗口过程,因此对 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;
关于delphi - 了解消息处理过程的堆栈跟踪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44155569/