Questo non è possibile senza un'estesa manipolazione degli interni di Windows e devi superarlo.
Ci sono momenti nell'uso quotidiano del computer in cui è davvero importante eseguire un'azione prima che il sistema operativo ti consenta di eseguirne un'altra. Per fare ciò, deve bloccare l'attenzione su determinate finestre. In Windows, il controllo su questo comportamento è in gran parte lasciato agli sviluppatori dei singoli programmi che usi.
Non tutti gli sviluppatori prendono le giuste decisioni quando si tratta di questo argomento.
So che è molto frustrante e fastidioso, ma non puoi avere la tua torta e mangiarla anche tu. Probabilmente ci sono molti casi nella tua vita quotidiana in cui stai perfettamente bene che lo stato attivo venga spostato su un determinato elemento dell'interfaccia utente o un'applicazione che richiede che lo stato attivo rimanga bloccato su di esso. Ma la maggior parte delle applicazioni sono in qualche modo uguali quando si tratta di decidere chi è il leader in questo momento e il sistema non può mai essere perfetto.
Qualche tempo fa ho fatto ricerche approfondite per risolvere questo problema una volta per tutte (e ho fallito). Il risultato della mia ricerca può essere trovato nella pagina del progetto di fastidio .
Il progetto include anche un'applicazione che tenta ripetutamente di concentrarsi chiamando:
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;
Come possiamo vedere da questo frammento, la mia ricerca si è concentrata anche su altri aspetti del comportamento dell'interfaccia utente che non mi piacciono.
Il modo in cui ho cercato di risolvere questo problema è stato caricare una DLL in ogni nuovo processo e agganciare le chiamate API che causano l'attivazione di un'altra finestra.
L'ultima parte è quella facile, grazie alle fantastiche librerie di aggancio API disponibili. Ho usato l'eccezionale libreria 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;
}
Dai miei test di allora, ha funzionato alla grande. Tranne la parte di caricamento della DLL in ogni nuovo processo. Come si potrebbe immaginare, non è niente da prendere alla leggera. Allora ho usato l' approccio AppInit_DLLs (che semplicemente non è sufficiente).
Fondamentalmente, funziona alla grande. Ma non ho mai trovato il tempo di scrivere qualcosa che inietta correttamente la mia DLL in nuovi processi. E il tempo investito in questo oscura in gran parte il fastidio che il furto di attenzione mi provoca.
Oltre al problema di iniezione DLL, esiste anche un metodo per rubare l'attenzione che non ho trattato nell'implementazione su Google Code. Un collega ha effettivamente svolto ulteriori ricerche e ha coperto tale metodo. Il problema è stato discusso su SO: https://stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus