【发布时间】:2012-12-18 05:58:48
【问题描述】:
我使用 Delphi 7,我的项目有几个非模态可见表单。问题是,如果其中一个调用 MessageBoxEx,则应用程序的所有操作都不会更新,直到 MessageBoxEx 的表单关闭。在我的项目中,它可能会破坏应用程序的业务逻辑。
在显示 MessageBoxEx 的窗口时从不调用 TApplication.HandleMessage 方法,因此它不会调用 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 标志来调用它,但没有帮助。
【问题讨论】: