我使用 Delphi 7,我的项目有几种非模态可见形式。问题是如果在其中一个 MessageBoxEx 被调用,则应用程序的所有操作都不会更新,直到 MessageBoxEx 的表单关闭。在我的项目中,它可能会破坏应用程序的业务逻辑。
TApplication.HandleMessage 方法在显示 MessageBoxEx 的窗口时永远不会被调用,因此它不会调用 DoActionIdle 并且不会更新操作。
我认为我需要的是在应用程序空闲时捕获它的状态并更新所有操作的状态。
首先我实现了 TApplication。OnIdle 处理程序:
procedure TKernel.OnIdle(Sender: TObject; var Done: Boolean);
begin
{It’s only to switch off the standard updating from TApplication.Idle. It's to make the CPU usage lower while MessageBoxEx's window isn't shown }
Done := False;
end;
implementation
var
MsgHook: HHOOK;
{Here is a hook}
function GetMsgHook(nCode: Integer; wParam: Longint; var Msg: TMsg): Longint; stdcall;
var
m: TMsg;
begin
Result := CallNextHookEx(MsgHook, nCode, wParam, Longint(@Msg));
if (nCode >= 0) and (_instance <> nil) then
begin
{If there aren’t the messages in the application's message queue then the application is in idle state.}
if not PeekMessage(m, 0, 0, 0, PM_NOREMOVE) then
begin
_instance.DoActionIdle;
WaitMessage;
end;
end;
end;
initialization
MsgHook := SetWindowsHookEx(WH_GETMESSAGE, @GetMsgHook, 0, GetCurrentThreadID);
finalization
if MsgHook <> 0 then
UnhookWindowsHookEx(MsgHook);
这是一种用于更新应用程序所有操作的状态的方法。它只是 TApplication.DoActionIdle 的修改版本:
type
TCustomFormAccess = class(TCustomForm);
procedure TKernel.DoActionIdle;
var
i: Integer;
begin
for I := 0 to Screen.CustomFormCount - 1 do
with Screen.CustomForms[i] do
if HandleAllocated and IsWindowVisible(Handle) and
IsWindowEnabled(Handle) then
TCustomFormAccess(Screen.CustomForms[i]).UpdateActions;
end;
状态的更新似乎比平时更频繁(我将使用分析器找出问题所在)。
此外,当鼠标光标不在应用程序的窗口上时,CPU 使用率会严重增加(在我的 DualCore Pentium 上约为 25%)。
您如何看待我的问题以及我尝试解决它的方式?使用钩子是个好主意还是有更好的方法来捕获应用程序空闲状态?在设置挂钩期间我是否需要使用 WH_CALLWNDPROCRET ?
为什么 MessageBoxEx 会阻止 TApplication.HandleMessage?有没有办法防止这种行为?我尝试使用 MB_APPLMODAL、MB_SYSTEMMODAL、MB_TASKMODAL 标志来调用它,但它没有帮助。