これは、Windows内部の広範な操作なしでは不可能であり、それを乗り越える必要があります。
オペレーティングシステムが別のアクションを許可する前に、あるアクションを実行することが本当に重要である場合、毎日のコンピューターの使用には瞬間があります。そのためには、特定のウィンドウにフォーカスをロックする必要があります。Windowsでは、この動作の制御は、主に使用する個々のプログラムの開発者に委ねられています。
このトピックに関して、すべての開発者が適切な決定を下すわけではありません。
私はこれが非常にイライラし、迷惑であることを知っていますが、ケーキを持って食べることもできません。日常生活の中で、特定のUI要素にフォーカスを移動したり、フォーカスをその上に固定したままにするように要求するアプリケーションにまったく問題がない場合が多分あります。しかし、ほとんどのアプリケーションは、現在誰がリードであるかを決定することになると、いくぶん平等であり、システムが完全になることはありません。
しばらく前、私はこの問題を完全に解決するために広範な調査を行いました(そして失敗しました)。私の研究の結果は、迷惑プロジェクトのページで見つけることができます。
このプロジェクトには、次の呼び出しによって繰り返しフォーカスを取得しようとするアプリケーションも含まれています。
switch( message ) {
case WM_TIMER:
if( hWnd != NULL ) {
// Start off easy
// SetForegroundWindow will not move the window to the foreground,
// but it will invoke FlashWindow internally and, thus, show the
// taskbar.
SetForegroundWindow( hWnd );
// Our application is awesome! It must have your focus!
SetActiveWindow( hWnd );
// Flash that button!
FlashWindow( hWnd, TRUE );
}
break;
このスニペットからわかるように、私の研究は、ユーザーインターフェイスの動作の他の側面にも焦点を当てています。
これを解決しようとした方法は、すべての新しいプロセスにDLLをロードし、別のウィンドウをアクティブにするAPI呼び出しをフックすることでした。
最後の部分は簡単です。素晴らしいAPIがライブラリをフックしているおかげです。私は非常に素晴らしいmhookライブラリを使用しました:
#include "stdafx.h"
#include "mhook-2.2/mhook-lib/mhook.h"
typedef NTSTATUS( WINAPI* PNT_QUERY_SYSTEM_INFORMATION ) (
__in SYSTEM_INFORMATION_CLASS SystemInformationClass,
__inout PVOID SystemInformation,
__in ULONG SystemInformationLength,
__out_opt PULONG ReturnLength
);
// Originals
PNT_QUERY_SYSTEM_INFORMATION OriginalFlashWindow =
(PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress(
::GetModuleHandle( L"user32" ), "FlashWindow" );
PNT_QUERY_SYSTEM_INFORMATION OriginalFlashWindowEx =
(PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress(
::GetModuleHandle( L"user32" ), "FlashWindowEx" );
PNT_QUERY_SYSTEM_INFORMATION OriginalSetForegroundWindow =
(PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress(
::GetModuleHandle( L"user32" ), "SetForegroundWindow" );
// Hooks
BOOL WINAPI
HookedFlashWindow(
__in HWND hWnd,
__in BOOL bInvert
) {
return 0;
}
BOOL WINAPI
HookedFlashWindowEx(
__in PFLASHWINFO pfwi
) {
return 0;
}
BOOL WINAPI
HookedSetForegroundWindow(
__in HWND hWnd
) {
// Pretend window was brought to foreground
return 1;
}
BOOL APIENTRY
DllMain(
HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
) {
switch( ul_reason_for_call ) {
case DLL_PROCESS_ATTACH:
Mhook_SetHook( (PVOID*)&OriginalFlashWindow, HookedFlashWindow );
Mhook_SetHook( (PVOID*)&OriginalFlashWindowEx, HookedFlashWindowEx );
Mhook_SetHook( (PVOID*)&OriginalSetForegroundWindow, HookedSetForegroundWindow );
break;
case DLL_PROCESS_DETACH:
Mhook_Unhook( (PVOID*)&OriginalFlashWindow );
Mhook_Unhook( (PVOID*)&OriginalFlashWindowEx );
Mhook_Unhook( (PVOID*)&OriginalSetForegroundWindow );
break;
}
return TRUE;
}
当時の私のテストから、これはうまくいきました。DLLをすべての新しいプロセスにロードする部分を除きます。想像するかもしれませんが、それは軽すぎることではありません。私は当時AppInit_DLLsアプローチを使用していました(これは単に十分ではありません)。
基本的に、これはうまく機能します。しかし、DLLを新しいプロセスに適切に挿入するものを作成する時間はありませんでした。そして、これに費やされた時間は、フォーカスを盗むことによって私が引き起こす不快感を大きく覆い隠します。
DLLインジェクションの問題に加えて、Google Codeでの実装ではカバーしていなかったフォーカスを盗む方法もあります。同僚が実際にいくつかの追加調査を行い、その方法を取り上げました。問題はSOで議論されました:https : //stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus