214 votes

Empêcher les applications de voler la vedette

Existe-t-il des solutions pour empêcher les applications de voler le focus de la fenêtre active ?

C'est particulièrement gênant lorsque je lance une application, que je passe à autre chose et que la nouvelle application commence à recevoir la moitié d'une phrase de texte.

56voto

diegogs Points 624

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

24voto

Tamara Wijsman Points 56163

Sous Windows 7, le ForegroundLockTimeout L'entrée de registre n'est plus vérifiée, vous pouvez le vérifier avec Process Monitor. En fait, dans Windows 7, ils vous interdisent de changer la fenêtre de premier plan. Allez lire sur ses détails Il existe même depuis Windows 2000.

Cependant, la documentation est nulle et ils se pourchassent et trouvent des moyens de contourner le problème. .

Donc, il y a quelque chose de bizarre qui se passe avec SetForegroundWindow ou des fonctions API similaires...

Le seul moyen de faire cela correctement est de créer une petite application qui appelle périodiquement LockSetForegroundWindow en désactivant virtuellement tout appel à notre fonction API boguée.

Si cela ne suffit pas (encore un appel à l'API bogué ?), vous pouvez aller encore plus loin et faire du Surveillance de l'API pour voir ce qui se passe, et ensuite, il suffit de hooker les appels API sur chaque processus après quoi vous pouvez vous débarrasser de cualquier les appels qui perturbent le premier plan. Cependant, ironiquement, ceci est déconseillé par Microsoft...

18voto

deceze Points 200115

Il existe une option dans TweakUI qui fait cela. Il empêche la plupart des astuces habituelles utilisées par les développeurs de logiciels douteux pour forcer l'attention sur leur application.

C'est une guerre d'armement en cours, donc je ne sais pas si ça marche pour tout.

<strong>Update </strong>: Selon <a href="https://superuser.com/users/865/endangeredmassa">En voie de disparitionMassa </a>TweakUI ne fonctionne pas sous Windows 7.

16voto

harrymc Points 394411

Je pense qu'une certaine confusion peut exister, car il y a deux façons de "voler le focus" : (1) une fenêtre qui arrive au premier plan, et (2) la fenêtre qui reçoit les frappes au clavier.

Le problème dont il est question ici est probablement le second, où un Windows revendique le focus en se plaçant au premier plan - sans la demande ou la permission de l'utilisateur.

La discussion doit se diviser ici entre XP et 7.

Windows XP

Dans XP, il y a un piratage du registre qui permet à XP de fonctionner de la même manière que Windows 7 en empêchant les applications de voler le focus :

  1. Utilisez regedit pour aller à : HKEY_CURRENT_USER\Control Panel\Desktop .
  2. Double-cliquez sur ForegroundLockTimeout et fixer sa valeur en hexadécimal à 30d40 .
  3. Appuyez sur OK et quittez regedit.
  4. Redémarrez votre PC pour que les modifications soient prises en compte.

Windows 7

(La discussion ci-dessous s'applique principalement à XP également).

Comprenez qu'il n'existe aucun moyen pour Windows d'empêcher totalement les applications de voler le focus et de rester fonctionnel. Par exemple, si au cours de la copie d'un fichier votre antivirus a détecté une menace possible et qu'il souhaite faire apparaître une fenêtre vous demandant l'action à prendre, si cette fenêtre est bloquée alors vous ne comprendrez jamais pourquoi la copie ne se termine jamais.

Dans Windows 7, il n'y a qu'une seule modification possible du comportement de Windows lui-même, à savoir d'utiliser le MS-Windows focus-follows-mouse Hacks de registre où le focus et/ou l'activation se fait toujours sur la fenêtre située sous le curseur. Un délai peut être ajouté pour éviter que des applications ne surgissent sur tout le bureau.
Voir cet article : Windows 7 - Le passage de la souris rend la fenêtre active - Activer .

Sinon, il faut détecter et neutraliser le programme coupable : Si c'est toujours la même application qui fait le focus, alors cette application Si cette application est toujours la même que celle qui obtient le focus, alors elle est programmée pour prendre le focus et pour éviter cela, il faut soit la désactiver au démarrage de l'ordinateur, soit utiliser un paramètre fourni par cette application pour éviter ce comportement.

Vous pourriez utiliser le VBS script inclus dans Code VB qui identifie qui vole le focus que l'auteur a utilisé pour identifier le coupable comme étant un programme de mise à jour "call home" pour un logiciel d'impression.

Une mesure désespérée quand tout le reste échoue, et si vous avez identifié cette application mal programmée, est de la minimiser et d'espérer qu'elle ne se mettra pas ensuite en avant. Une forme plus forte de minimisation est le plateau en utilisant un des produits gratuits listés dans la section Meilleur minimiseur d'applications gratuit .

La dernière idée dans l'ordre du désespoir est de fracturer virtuellement votre bureau en utilisant un produit tel que Ordinateurs de bureau o Dexpot , et faire votre travail dans un autre bureau que celui par défaut.

[EDIT]

Comme Microsoft a retiré la galerie d'archives, voici le code VB ci-dessus reproduit :

Declare Auto Function GetForegroundWindow Lib "user32.dll" () As Integer
Declare Auto Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As Integer, ByRef procid As Integer) As UInteger

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.RichTextBox1.AppendText("Starting up at " & Now & vbCrLf)
    End Sub

    Private Sub GoingAway(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Deactivate, Me.LostFocus

        Dim hwnd As Integer = GetForegroundWindow()
        ' Note that process_id will be used as a ByRef argument
        ' and will be changed by GetWindowThreadProcessId
        Dim process_id As Integer = 1
        GetWindowThreadProcessId(hwnd, process_id)

        If (process_id <> 1) Then
            Dim appExePath As String = Process.GetProcessById(process_id).MainModule.FileName() 
            Me.RichTextBox1.AppendText("Lost focus at " & Now & " due to " & appExePath & vbCrLf)
        Else
            Me.RichTextBox1.AppendText("Lost focus due to unknown cause.")
        End If

    End Sub

6voto

blade Points 336

Inspiré par La réponse de Der Hochstapler J'ai donc décidé d'écrire un injecteur de DLL, qui fonctionne avec les processus 64 et 32 bits et empêche le vol de cible sur Windows 7 ou plus récent : https://blade.sk/stay-focused/

Le système fonctionne de la manière suivante : il surveille les fenêtres nouvellement créées (à l'aide de la fonction SetWinEventHook ) et injecte une DLL très similaire à celle de Der Hochstapler dans le processus de la fenêtre si elle n'est pas déjà présente. Il décharge les DLLs et restaure la fonctionnalité originale à la sortie.

D'après mes essais, cela fonctionne très bien jusqu'à présent. Cependant, le problème semble aller au-delà des appels d'applications. SetForegroundWindow . Par exemple, lorsqu'une nouvelle fenêtre est créée, elle est automatiquement placée au premier plan, ce qui interfère également avec un utilisateur qui tape dans une autre fenêtre.

Pour faire face à d'autres méthodes de détournement de l'attention, des tests supplémentaires sont nécessaires et j'apprécierais tout retour d'information sur des scénarios où cela se produit.

éditer : Code source maintenant disponible.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X