私は Delphi 7 を使用しており、私のプロジェクトにはいくつかの非モーダル表示フォームがあります。問題は、そのうちの 1 つで 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;
状態の更新は通常より頻繁に行われているようです (プロファイラーを使用してどこに問題があるかを調べます)。
その上、マウスのカーソルがアプリケーションのウィンドウ上にないとき (私の DualCore Pentium では約 25%)、CPU 使用率が大幅に増加します。
私の問題とそれを解決しようとする方法についてどう思いますか? フックを使用するのは良い考えですか、それともアプリケーションのアイドル状態をキャッチするより良い方法はありますか? フックの設定中に WH_CALLWNDPROCRET を使用する必要がありますか?
MessageBoxEx が TApplication.HandleMessage をブロックするのはなぜですか? この動作を防ぐ方法はありますか? MB_APPLMODAL、MB_SYSTEMMODAL、MB_TASKMODAL フラグを付けて呼び出そうとしましたが、役に立ちませんでした。