Question

J'ai une boîte de Windows qui exécute trois applications. Lorsque les applications sont lancées chaque application crée une fenêtre qui est sans marge positionnée de telle sorte qu'elles se chevauchent d'une manière particulière.

À l'heure actuelle, lorsque je clique sur un contrôle sur la fenêtre du bas, il est en haut de la pile de fenêtre.

Je dois veiller à ce que chaque fenêtre conserve son ordre dans la pile de fenêtre, même si une fenêtre reçoit l'entrée.

Je pense que je dois écrire une sorte de simple gestionnaire de fenêtre qui maintiendra le Z-ordre des fenêtres.

Le problème est, je dois savoir si une fenêtre particulière a changé de position. J'ai trouvé qu'il ya un message WM_WINDOWPOSCHANGING mais je crois comprendre que ce message est envoyé à la fenêtre dont la position a changé.

Je dois ma demande de gestionnaire de fenêtres à en quelque sorte averti que le Z-ordre a changé.

Est-il possible que je peux attraper tous les messages WM_ et déterminer si le message s'applique à l'une des fenêtres que je souhaite contrôler?

Était-ce utile?

La solution

Au lieu de l'approche de MSalter essayant d'injection DLL dans chacun des exécutant l'application, envisagez d'installer un crochet WH_CBT de Windows. Dans votre CBTProc, retour 0 quand vous obtenez un HCBT_MOVESIZE pour les trois fenêtre d'application souciez traite environ.

Lire MSDN pour la documentation sur CBTProc et SetWindowsHookEx .

Autres conseils

Le plus simple est probablement injecter une DLL dans chacune des trois applications. Cela garantit que vous suffit de traiter le sous-ensemble des messages de fenêtre que vous soucient réellement.

Ensuite, trouver la fenêtre principale dans chaque application (pas tout à fait banal, en théorie, il pourrait y avoir plus) en appelant EnumWindows() pour trouver toutes les fenêtres, et d'appeler GetWindowThreadProcessId() sur chacun pour déterminer si elle appartient au processus actuel (celui votre DLL est injecté dans).

Maintenant que vous avez le HWND correct, vous pouvez accrocher le WndProc associé et prendre toute WM_WINDOWPOSCHANGING qui lui sont envoyés.

Lorsque vous créez les deux fenêtres que vous voulez être sur le dessus, donner la fenêtre que vous voulez être sur le fond que la valeur de hWndParent à CreateWindow. Windows va alors toujours mettre les fenêtres vers l'avant lorsque la fenêtre du bas est avancée afin qu'ils restent toujours devant.

Donc, si la fenêtre du bas est la fenêtre 1. Créez d'abord, lorsque vous créez des fenêtres 2 et 3, donner la poignée de fenêtre 1 la valeur hWndParent. Le gestionnaire de fenêtres fait le reste.

vous pouvez utiliser SetWindowPos pour positionner vos fenêtres dans l'ordre Z vous voulez. Je vous suggère d'intercepter le message WM_FOCUS (ce qui est envoyé à la fenêtre quand il reçoit le focus)

Dans votre fonction WNDPROC, vous pouvez peut-être essayer quelque chose comme ceci:

LRESULT wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
    // other stuff..

    switch (msg){
        case WM_FOCUS:
        {
            HWND firstWindow; // get the first window here
            HWND secondWindow; // this would be the second window
            HWND thirdWindow; // this would be the third window
            // TODO: initialize the windows correctly, based on your priority
            SetWindowPos(firstWindow, secondWindow, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE); // position the second window below the first window
            SetWindowPos(secondWindow, thirdWindow, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE); // position the third window below the second window
        }
        return 0;
    }
    // other messages..
}

Je ne suis pas tout à fait sûr de l'ordre des arguments de SetWindowPos puisque je ne peux pas tester le code en ce moment, mais peut-être cela peut vous aider à aller?


Si vous avez besoin d'intercepter tous les messages WM_, je suggère une classe de fenêtre que les applications font appel à la place (que je suppose) d'appeler eux-mêmes CreateWindowEx. Par exemple:

class Window {
public
    Window(){
        ...
        WNDCLASSEX wc;
        ZeroMemory(&wc, sizeof(WNDCLASSEX));
        wc.cbSize        = sizeof(WNDCLASSEX);
        wc.lpfnWndProc   = wndProc;            // <- Note this one
        ...
    }

    static LRESULT WINAPI wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
        // reference: http://www.gamedev.net/community/forums/topic.asp?topic_id=303854 - Evil Steve  [Moderator]
        Window* parent;

        // Get pointer to window
        if(msg == WM_CREATE){
            parent = (Window*)((LPCREATESTRUCT)lParam)->lpCreateParams;
            SetWindowLongPtr(hwnd,GWL_USERDATA,(LONG_PTR)parent);
        }
        else{
            parent = (Window*)GetWindowLongPtr(hwnd,GWL_USERDATA);
            if(!parent) return DefWindowProc(hwnd,msg,wParam,lParam);
        }
        HWND prev = parent->mWin;
        parent->mWin = hwnd;
        LRESULT ret = parent->wndProc(msg,wParam,lParam);
        parent->mWin = prev;
        return ret;
    }

    virtual LRESULT wndProc(UINT msg, WPARAM wParam, LPARAM lParam){
    }
};

Dans cet exemple, vos applications hériteraient de la fenêtre, fournissant essentiellement une fonction WNDPROC légèrement modifiée (il manquerait HWND donc ce devrait être stocké quelque part, à moins que vous le ramasser du Userdata).

  • Everytime

    vous recevez un message de la fonction Window::wndProc(HWND, UINT, WPARAM, LPARAM) serait le ramasser. Ici, vous pouvez faire vos chèques de tous les messages, y compris (mais sans s'y limiter) WM_WINDOWPOSCHANGING.

  • L'autre chose à faire serait que: Dans le wndProc(UINT, WPARAM, LPARAM), au lieu d'appeler DefWindowProc(..)
    vous appelez Window::wndProc(UINT, WPARAM, LPARAM). Ensuite, vous pouvez faire vos chèques là-bas à la place (à ne pas cludge la première fonction wndProc) :)

L'inconvénient de cette serait que si les applications sont écrites par quelqu'un d'autre, ils doivent se conformer à votre WindowClass. Comme vous l'expliquer l'utilisateur ne devrait pas avoir besoin d'interagir avec votre gestionnaire de fenêtres, cependant, avec cette approche, la seule interaction serait de laisser votre gestionnaire de fenêtres créer la fenêtre pour l'utilisateur.
Sinon, je pense que vous devez aller avec le crochet expliqué dans les autres réponses

Je pense que je suis d'accord avec la réponse de John Knoeller. Si vous voulez que les fenêtres de rester dans un ordre particulier z, puis déterminer ce que cet ordre est et de créer vos fenêtres avec les relations entre parents et enfants appropriés.

::SetWindowLong(hwnd_child, GWL_HWNDPARENT, hwnd_parent);

Quand vous faites que les fenêtres enfants resteront toujours au-dessus du parent.

Si vous insistez toujours sur la capture des messages que vous pouvez attraper WM_ACTIVATE dans chaque fenêtre, puis transmettre ce message à votre gestionnaire de fenêtres qui aura accès aux hwnds de toutes les fenêtres et z pour les correctement en utilisant SetWindowPos. Et au lieu de SetWindowPos vous pouvez utiliser DeferWindowPos changer à la fois z pour que les fenêtres et éviter le scintillement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top