11 votes

Comprendre AttachThreadInput - détacher perdre le focus

J'ai un petit problème pour comprendre pleinement AttachThreadInput.

Je sais qu'il s'agit de "connecter" la file d'attente des messages de 2 threads, ce qui (ce que je veux faire) me permet par exemple de forcer ma fenêtre (winforms) au premier plan.

Ce que je peux faire avec cette méthode :

private void SetForegroundWindowEx(IntPtr hWnd)
{
    uint SW_SHOW = 5;
    uint appThread = GetCurrentThreadId();     
    uint foregroundThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);         

    if (foregroundThread != appThread)
    {
        AttachThreadInput(foregroundThread, appThread, true);

        BringWindowToTop(hWnd);
        ShowWindow(hWnd, SW_SHOW);       
        AttachThreadInput(foregroundThread, appThread, false);

    }
    else
    {
        BringWindowToTop(hWnd);
        ShowWindow(hWnd, SW_SHOW);
    }
}

Cependant, les deux fenêtres perdent le focus dès que les fils se détachent.

Si j'attends que la file d'attente des messages se vide (Application.DoEvents()) et que j'active ma fenêtre (qui est maintenant au premier plan mais non focalisée), elle retrouvera le focus et le conservera.

Si je le fais avant que la file d'attente des messages soit vide, il perdra à nouveau le focus.

Je suppose donc qu'un phénomène de détachement détourne l'attention de mes fenêtres, mais je n'ai aucune idée de ce que c'est ni de comment l'empêcher.

C'est la première chose que je ne comprends pas bien.

La deuxième chose que je ne comprends pas, c'est que si je ne mets pas ma fenêtre au premier plan :

AttachThreadInput(foregroundThread, appThread, true);

AttachThreadInput(foregroundThread, appThread, false);
Application.DoEvents();
this.Activate();

attendre que la file d'attente des messages se vide, et activer ma fenêtre (cette fois-ci, elle n'est pas au premier plan et l'autre fenêtre a toujours le focus), elle est effectivement activée, même si les fils ne sont plus attachés.

Peut-être que quelqu'un ayant une meilleure compréhension de AttachThreadInput peut me répondre à ces 2 questions.

INFO :
J'ai besoin de voler le focus dans ce cas, parce que mon application est appelée via une API. L'autre application qui appelle la mienne attend le retour d'information de mon application et, la plupart du temps, se fige jusqu'à ce qu'elle obtienne l'information.

Dans le cas où l'autre application est en plein écran, beaucoup d'utilisateurs ne remarquent pas le clignotement dans la barre des tâches et pensent que l'autre application a planté et la tue avec le Taskmamanger. Comme je n'ai pas nécessairement le contrôle de l'autre application, je ne peux pas lui demander de mettre le focus sur ma fenêtre.

Cette méthode ne sera pas appelée si elle n'est pas absolument nécessaire, dans ce cas ce comportement, qui est hostile, je le sais, est aussi bien voulu par moi que par l'utilisateur.

12voto

Noseratio Points 23840

Voici un morceau de code c# que j'utilise dans le même but. Je tiens à souligner qu'il existe des cas légitimes où cela peut être nécessaire. Dans notre cas, il s'agissait de l'automatisation de MS Word. Chaque fois que l'utilisateur clique sur un bouton de la barre d'outils dans notre application, nous devons immédiatement faire apparaître la fenêtre Word à l'attention de l'utilisateur.

public static void ForceWindowIntoForeground(IntPtr window)
{
    uint currentThread = Win32.GetCurrentThreadId();

    IntPtr activeWindow = Win32.GetForegroundWindow();
    uint activeProcess;
    uint activeThread = Win32.GetWindowThreadProcessId(activeWindow, out activeProcess);

    uint windowProcess;
    uint windowThread = Win32.GetWindowThreadProcessId(window, out windowProcess);

    if (currentThread != activeThread)
        Win32.AttachThreadInput(currentThread, activeThread, true);
    if (windowThread != currentThread)
        Win32.AttachThreadInput(windowThread, currentThread, true);

    uint oldTimeout = 0, newTimeout = 0;
    Win32.SystemParametersInfo(Win32.SPI_GETFOREGROUNDLOCKTIMEOUT, 0, ref oldTimeout, 0);
    Win32.SystemParametersInfo(Win32.SPI_SETFOREGROUNDLOCKTIMEOUT, 0, ref newTimeout, 0);
    Win32.LockSetForegroundWindow(LSFW_UNLOCK);
    Win32.AllowSetForegroundWindow(Win32.ASFW_ANY);

    Win32.SetForegroundWindow(window);
    Win32.ShowWindow(window, Win32.SW_RESTORE);

    Win32.SystemParametersInfo(Win32.SPI_SETFOREGROUNDLOCKTIMEOUT, 0, ref oldTimeout, 0);

    if (currentThread != activeThread)
        Win32.AttachThreadInput(currentThread, activeThread, false);
    if (windowThread != currentThread)
        Win32.AttachThreadInput(windowThread, currentThread, false);
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X