Isto não é possível sem a extensa manipulação dos componentes internos do Windows e você precisa passar por isso.
Há momentos no uso diário do computador quando é realmente importante que você faça uma ação antes que o sistema operacional permita que você faça outra. Para fazer isso, é necessário bloquear seu foco em determinadas janelas. No Windows, o controle sobre esse comportamento é largamente deixado para os desenvolvedores dos programas individuais que você usa.
Nem todo desenvolvedor toma as decisões certas quando se trata deste tópico.
Eu sei que isso é muito frustrante e chato, mas você não pode ter seu bolo e comê-lo também. Provavelmente, há muitos casos em sua vida diária em que você está perfeitamente bem com o foco sendo movido para um determinado elemento da interface do usuário ou um aplicativo solicitando que o foco permaneça bloqueado. Mas a maioria dos aplicativos é um pouco igual quando se trata de decidir quem é o líder agora e o sistema nunca pode ser perfeito.
Há algum tempo, fiz uma extensa pesquisa sobre como resolver esse problema de uma vez por todas (e falhei). O resultado da minha pesquisa pode ser encontrado na página do projeto de aborrecimento .
O projeto também inclui um aplicativo que tenta repetidamente chamar o foco chamando:
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;
Como podemos ver neste trecho, minha pesquisa também se concentrou em outros aspectos do comportamento da interface do usuário dos quais não gosto.
A maneira como tentei resolver isso foi carregar uma DLL em cada novo processo e ligar as chamadas de API que fazem com que outras janelas sejam ativadas.
A última parte é a mais fácil, graças a incríveis bibliotecas de hooking de APIs por aí. Eu usei a grande biblioteca 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;
}
De meus testes naquela época, isso funcionou muito bem. Exceto pela parte de carregar a DLL em todo novo processo. Como se pode imaginar, isso não é nada demais. Usei a abordagem AppInit_DLLs (que simplesmente não é suficiente).
Basicamente, isso funciona muito bem. Mas eu nunca encontrei tempo para escrever algo que propriamente injeta minha DLL em novos processos. E o tempo investido nisso, em grande parte, ofusca o aborrecimento que o foco roubado me causa.
Além do problema de injeção de DLL, há também um método de roubo de foco que não abordei na implementação do Google Code. Um colega de trabalho realmente fez algumas pesquisas adicionais e cobriu esse método. O problema foi discutido no SO: link