我在主表单上放置了一个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?
答案 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;