web-dev-qa-db-fra.com

Win32: mettre une fenêtre en haut

J'ai un programme Windows qui contient deux fenêtres:

hwnd (main interface)

hwnd2 (toplevel window, no parent, created by hwnd)

Lorsque je double-clique sur hwnd, j'ai besoin que hwnd2 apparaisse et affiche des données, donc j'utilise cette fonction pour amener hwnd2 en haut:

BringWindowToTop(hwnd2);

hwnd2 est ramené au sommet, mais il y a une chose étrange. Lorsque je clique à nouveau sur hwnd2, hwnd (interface principale) réapparaît automatiquement. J'ai essayé d'utiliser la fonction suivante pour résoudre ce problème, mais aucune d'entre elles ne fonctionne.

SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
                                                                  //doesn't work

BringWindowToTop(hwnd2);    //This is the function brings hwnd2 to top

SetForegroundWindow(hwnd2); //doesn't work

SetWindowPos(hwnd2, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); 
                                                                  //doesn't work

SetWindowPos(hwnd2, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
                                       // hwnd2 "always" on top, not what I want

SetActiveWindow(hwnd2); // doesn't work too (for replying to Magnus Skog, thanks)

SwitchToThisWindow(hwnd2, TRUE);// got the same problem with BringWindowToTop function
SwitchToThisWindow(hwnd2, FALSE);

Comment pourrais-je résoudre ce problème? Merci d'avance.

(pour répondre à aJ, hwnd2 n'a pas de parent car il doit être une fenêtre de niveau supérieur pour pouvoir être devant/derrière d'autres fenêtres)

(hwnd2 est un lecteur multimédia composé de plusieurs fenêtres, l'une des fenêtres est destinée à l'affichage vidéo, deux autres commandes de barre de suivi pour la barre de progression et la barre de volume, une commande de barre d'outils pour le panneau de commande.)

(Il y en a un qui pourrait aider, peu importe la fenêtre sur laquelle je clique sur hwnd2, hwnd apparaît automatiquement aussi longtemps que "la souris est au-dessus de hwnd dans l'ordre Z", y compris la barre de menus et la zone non client, etc.)

(Ce lecteur multimédia est écrit dans Direct Show. J'utilise IVideoWindow :: put_Owner pour mettre la fenêtre vidéo en tant que propriétaire de la vidéo, Direct Show crée en interne une fenêtre sous-vidéo en tant qu'enfant de la fenêtre vidéo. À l'exception de cette fenêtre sous-vidéo qui Je ne vois pas le code source, je ne vois rien de suspect dans hwnd2.)

J'ai trouvé la raison, à cause de Direct Show. J'utilise le multithread pour l'exécuter, puis le problème est résolu. Mais pourquoi??

Ce problème peut être résolu en utilisant PostMessage (plutôt que SendMessage).

31
KenC

essayez ceci , on dit qu'il vient de M $

    HWND hCurWnd = ::GetForegroundWindow();
    DWORD dwMyID = ::GetCurrentThreadId();
    DWORD dwCurID = ::GetWindowThreadProcessId(hCurWnd, NULL);
    ::AttachThreadInput(dwCurID, dwMyID, TRUE);
    ::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
    ::SetWindowPos(m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
    ::SetForegroundWindow(m_hWnd);
    ::AttachThreadInput(dwCurID, dwMyID, FALSE);
    ::SetFocus(m_hWnd);
    ::SetActiveWindow(m_hWnd);
19
bowman han

Les deux fonctionnent très bien:

::SetForegroundWindow(wnd)

ou

::SetWindowPos(m_hWnd,       // handle to window
            HWND_TOPMOST,  // placement-order handle
            0,     // horizontal position
            0,      // vertical position
            0,  // width
            0, // height
            SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE// window-positioning options
            );

Mais rappelez-vous que le dernier définit la fenêtre toujours en haut.

13
Nuno

SwitchToThisWindow fonctionne le mieux pour moi.

8
scottm

SwitchToThisWindow () n'est pas du tout obsolète.
Je l'utilise depuis 14 ans en environnement de production.
Voir le code source de Windows et vous verrez qu'il s'appelle partout ...

5
john

Après de nombreux essais et erreurs, j'ai trouvé la solution suivante à ce problème:

SendMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); // restore the minimize window
SetForegroundWindow(hwnd); 
SetActiveWindow(hwnd); 
SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE  | SWP_NOSIZE);
//redraw to prevent the window blank.
RedrawWindow(hwnd, NULL, 0, RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN );

Le hwnd est votre Windows HWND. Veuillez ne pas simplement copier et coller. Vous devez également utiliser GetLastError pour vérifier l'erreur api après chaque appel api.

J'ai confirmé le résultat suivant sur mon win7:

  • Peut restaurer minimiser la fenêtre et aucun retour d'erreur.
  • Si la fenêtre est déjà en haut, le titre de la fenêtre clignote et aucune erreur ne revient.
  • Si la fenêtre s'est fermée, elle renverra l'erreur "0x578 Handle de fenêtre non valide".
  • Il peut amener la fenêtre en haut de toutes les fenêtres qui ne sont pas en haut et sans retour d'erreur (par exemple, il se trouvera derrière le gestionnaire de tâches le plus haut).
  • Cela ne rend pas la fenêtre la plus haute. L'utilisateur peut créer une autre fenêtre par-dessus.
4
bronze man

Avez-vous essayé SetActiveWindow ()?

4
ralphtheninja