Cela n'est pas possible sans extensive manipulation des internes de Windows et tu dois t'en remettre.
Il y a des moments dans l'utilisation quotidienne de l'ordinateur où il est vraiment important que vous fassiez une action avant que le système d'exploitation ne vous permette d'en faire une autre. Pour ce faire, il doit verrouiller votre attention sur certaines fenêtres. Dans Windows, le contrôle de ce comportement est largement laissé aux développeurs des programmes individuels que vous utilisez.
Tous les développeurs ne prennent pas les bonnes décisions en la matière.
Je sais que c'est très frustrant et ennuyeux, mais on ne peut pas avoir le beurre et l'argent du beurre. Il y a probablement de nombreux cas dans votre vie quotidienne où vous êtes parfaitement d'accord pour que le focus soit déplacé vers un certain élément de l'interface utilisateur ou qu'une application demande que le focus reste verrouillé sur elle. Mais la plupart des applications sont quelque peu égales lorsqu'il s'agit de décider qui est le chef de file en ce moment et le système ne pourra jamais être parfait.
Il y a quelque temps, j'ai fait des recherches approfondies pour résoudre ce problème une fois pour toutes (et j'ai échoué). Le résultat de mes recherches peut être trouvé sur le site de la page du projet nuisances .
Le projet comprend également une application qui tente à plusieurs reprises d'obtenir le focus en appelant :
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;
Comme on peut le voir dans cet extrait, mes recherches ont également porté sur d'autres aspects du comportement de l'interface utilisateur que je n'aime pas.
La façon dont j'ai essayé de résoudre ce problème était de charger une DLL dans chaque nouveau processus et d'accrocher les appels API qui provoquent l'activation d'un autre Windows.
La dernière partie est la plus facile, grâce aux superbes bibliothèques d'accrochage d'API qui existent. J'ai utilisé la très bonne bibliothèque de 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;
}
D'après mes tests de l'époque, cela a très bien fonctionné. Sauf en ce qui concerne le chargement de la DLL dans chaque nouveau processus. Comme on peut l'imaginer, ce n'est pas une tâche à prendre à la légère. J'ai utilisé la AppInit_DLLs à l'époque (ce qui n'est tout simplement pas suffisant).
En gros, ça marche très bien. Mais je n'ai jamais trouvé le temps d'écrire quelque chose qui correctement injecte ma DLL dans de nouveaux processus. Et le temps investi dans cette opération éclipse largement le désagrément que me cause le vol de focus.
En plus du problème d'injection de DLL, il y a aussi une méthode de vol de focus que je n'ai pas couverte dans l'implémentation sur Google Code. Un collègue de travail a effectué des recherches supplémentaires et a couvert cette méthode. Le problème a été discuté sur SO : https://stackoverflow.com/questions/7430864/Windows-7-prevent-application-from-losing-focus