Isso não é possível sem a manipulação extensiva de componentes internos do Windows e você precisa superá-lo.
Há momentos no uso diário do computador em que é realmente importante que você execute uma ação antes que o sistema operacional permita outra. Para fazer isso, ele precisa bloquear seu foco em determinadas janelas. No Windows, o controle sobre esse comportamento é amplamente deixado para os desenvolvedores dos programas individuais que você usa.
Nem todo desenvolvedor toma as decisões corretas quando se trata deste tópico.
Sei que isso é muito frustrante e irritante, mas você não pode comer o seu bolo e também comê-lo. Provavelmente, existem muitos casos ao longo da 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 das aplicações é 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 a solução desse 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 recuperar o foco repetidamente 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 foi focada em outros aspectos do comportamento da interface do usuário que eu não gosto.
A maneira como tentei resolver isso foi carregar uma DLL em cada novo processo e ligar as chamadas da API que fazem com que outras janelas sejam ativadas.
A última parte é a mais fácil, graças às incríveis bibliotecas de conexão de API existentes. 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;
}
Dos meus testes naquela época, isso funcionou muito bem. Exceto pela parte de carregar a DLL em cada novo processo. Como se pode imaginar, isso não é nada demais. Eu usei a abordagem AppInit_DLLs naquela época (o que simplesmente não é suficiente).
Basicamente, isso funciona muito bem. Mas nunca encontrei tempo para escrever algo que injete corretamente minha DLL em novos processos. E o tempo investido nisso obscurece amplamente o aborrecimento que o foco roubado me causa.
Além do problema de injeção de DLL, também há um método de roubo de foco que não cobri na implementação no Google Code. Um colega de trabalho realmente fez algumas pesquisas adicionais e cobriu esse método. O problema foi discutido no SO: https://stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus