Cela n'est pas possible sans une manipulation poussée des composants internes de Windows et vous devez vous en remettre.
Il y a des moments d'utilisation quotidienne de l'ordinateur où il est vraiment important de faire une action avant que le système d'exploitation ne vous permette d'en faire une autre. Pour ce faire, vous devez vous concentrer sur certaines fenêtres. Sous Windows, le contrôle de ce comportement est en grande partie laissé aux développeurs des programmes individuels que vous utilisez.
Tous les développeurs ne prennent pas les bonnes décisions concernant ce sujet.
Je sais que c'est très frustrant et énervant, mais vous ne pouvez pas avoir votre gâteau et le manger aussi. Il y a probablement de nombreux cas dans votre vie quotidienne où tout va parfaitement bien, le focus étant déplacé vers un certain élément de l'interface utilisateur ou une application demandant que le focus reste verrouillé dessus. Mais la plupart des applications sont quelque peu égales lorsqu'il s'agit de décider qui dirige actuellement et le système ne peut jamais être parfait.
Il y a quelque temps, j'ai effectué des recherches approfondies sur la résolution de ce problème une fois pour toutes (et j'ai échoué). Le résultat de mes recherches est disponible sur la page du projet de désagrément .
Le projet inclut également une application qui tente à plusieurs reprises d’attirer l’attention 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 nous pouvons le voir dans cet extrait de code, mes recherches portaient également sur d'autres aspects du comportement de l'interface utilisateur que je n'aime pas.
J'ai essayé de résoudre ce problème en chargeant une DLL dans chaque nouveau processus et en raccordant les appels d'API qui activent une autre fenêtre.
La dernière partie est la plus facile, grâce à d’impressionnantes bibliothèques d’accrochage d’API. J'ai utilisé la très grande bibliothèque 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 à l'époque, cela a très bien fonctionné. À l'exception de la partie du chargement de la DLL dans chaque nouveau processus. Comme on peut l’imaginer, rien n’est à prendre à la légère. J'ai utilisé l' approche AppInit_DLLs à l'époque (ce qui n'est tout simplement pas suffisant).
Fondamentalement, cela fonctionne très bien. Mais je n'ai jamais trouvé le temps d'écrire quelque chose qui injecte correctement ma DLL dans de nouveaux processus. Et le temps investi dans ceci masque en grande partie le désagrément que me cause le vol de la cible.
En plus du problème d'injection de DLL, il existe également une méthode de vol de focus que je n'ai pas abordée dans l'implémentation de Google Code. Un collègue a en fait fait des recherches supplémentaires et a couvert cette méthode. Le problème a été discuté sur le SO: https://stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus