XL 2021 VBA - Comment savoir dans quel mode (vbModal / vbModeless) est affiché un UserForm

  • Initiateur de la discussion Initiateur de la discussion Dudu2
  • Date de début Date de début

Boostez vos compétences Excel avec notre communauté !

Rejoignez Excel Downloads, le rendez-vous des passionnés où l'entraide fait la force. Apprenez, échangez, progressez – et tout ça gratuitement ! 👉 Inscrivez-vous maintenant !

Yes !
Par contre ce n'est pas normal qu'on puisse ouvrir un classeur quand un UserForm vbModal est affiché, alors même qu'Excel envoie un message comme quoi c'est pas possible et passe outre quand on clique OK.
1746712172478.png
 
Dernière édition:
Bonjour,
Pour revenir sur le sujet annexe des Titres de classeurs et du suivi des évènements de Move déjà évoqués au Post #31, J'ai revu le code car je pense que comme pour tous les Hookings qu'on fait (Scroll par SetWindowsHookEx() ou Scroll par TrackMouseEvent()), le Hooking par SetWinEventHook() ne supporte pas que l'Editeur VBA (le VBE) soit ouvert et génère selon les actions effectuées des plantages violents dont je crois me rappeler qu'ils sont limités au 64 bits (pas 100% sûr).

Comme pour les autres Hooking, j'ai modifié pour fermer le VBE au démarrage du tracking des évènements de Move et aussi arrêté le Hooking si le VBE est ouvert par l'utilisateur.
 

Pièces jointes

L'api windows ShowWindow permet d'afficher n'importe quelle fiche sans restriction même une forme non modal après une autre modal .
Essaie:
Code:
 Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As LongPtr, ByVal uCmd As Long) As Boolean
Private Declare PtrSafe Function IsWindowVisible Lib "user32" (ByVal hwnd As LongPtr) As Boolean
                          
Private Sub CommandButton3_Click()
Dim FWin  As LongPtr
FWin = FindWindow(vbNullString, UserForm1.Caption)
If (FWin <> 0) And Not IsWindowVisible(FWin) Then
  With UserForm1
     .Move Application.Left + (Application.Width - .Width) / 2, _
           Application.Top + (Application.Height - .Height) / 2
  End With
  ShowWindow FWin, 1
End If
End Sub
 
Pour revenir sur le sujet annexe des Titres de classeurs et du suivi des évènements de Move déjà évoqués au Post #31, J'ai revu le code car je pense que comme pour tous les Hookings qu'on fait (Scroll par SetWindowsHookEx() ou Scroll par TrackMouseEvent()),
Si le but est de placer les titres en haut des classeurs donc pas besoin de hook pour suivre les déplacements des windows juste placer les fenetres titres dans chaque window de classeur comme enfants tu peau te servir de l'api SetParent
 
Bonsoir @Rheeem,
C'est très intéressant cet affaire de ShowWindow. On peut exécuter du code après le ShowWindow d'un UserForm de 2ème niveau sur un UserForm Modal de 1er niveau alors qu'en principe on est obligé de faire un Show vbModal sur le UserForm de 2ème niveau, interdisant alors l'exécution de code après le Show vbModal.
 

Pièces jointes

Si le but est de placer les titres en haut des classeurs donc pas besoin de hook pour suivre les déplacements des windows juste placer les fenetres titres dans chaque window de classeur comme enfants tu peau te servir de l'api SetParent
C'est très juste et je me demande pourquoi je n'y ai pas pensé !
A part la modif du cadre du UserForm, ça devrait fonctionner. Je dois vérifier si je n'ai pas d'effet de bord dans le code.

Edit: Si pour le Move il n'y a pas de problème car le UserForm suit, pour le Resize il faut évidemment ajuster la position du UserForm pour qu'il reste au milieu. Mais ce n'est pas un problème car le Resize fait partie des évènement standards de l'Application, pas besoin de Hooking.
 

Pièces jointes

Dernière édition:
Bonjour,

@Rheeem,
Lorsqu'on fait un ShowWindow d'un UserForm il apparait dans la barre des tâches. Normal.
Si on lui fait un SetParent sur l'Application, il est rattaché à l'application et disparait de la barre des tâches. Normal.

Mais sais-tu comment faire pour le faire disparaitre de la barre des tâches sans un SetParent sur l'Application.
Quel est le Parent standard d'un UserForm affiché par la méthode .Show ? Ou bien est-ce un mécanisme interne non "simulable" ?
 
Mais sais-tu comment faire pour le faire disparaitre de la barre des tâches sans un SetParent sur l'Application.
En comparant les StylesEx de deux formes une lancée par Show et une autre lancée par ShowWindow j'ai trouvé que le dernier contient un paramètre de plus WS_EX_APPWINDOW en le retirant juste avant l'appel de ShowWindow la fenêtre ne s'affiche plus dans la barre des taches .
Code:
If (fwin <> 0) And (IsWindowVisible(fwin) = False) Then
  With UserForm1
     .Move Application.Left + (Application.Width - .Width) / 2, _
           Application.Top + (Application.Height - .Height) / 2
  End With
  Const GWL_EXSTYLE = -20&
  Const WS_EX_APPWINDOW = &H40000
  Dim ExStyle As Long
  ExStyle = GetWindowLongPtr(fwin, GWL_EXSTYLE)
  ExStyle = ExStyle And Not WS_EX_APPWINDOW
  SetWindowLongPtr fwin, GWL_EXSTYLE, ExStyle
  ShowWindow fwin, 1
End If

Attention au And (IsWindowVisible(fwin) = False) n'est pas la meme pour And Not IsWindowVisible(fwin)
C'est une des bizarreries de VBA en fait il y a une erreur dans la declaration de IsWindowVisible bien que elle renvoie un boolean suivant le prototype officiel mais comme le boulean en VBA ne fonctionne pas de la même manière et malgré les tests sont correctes la condition pour la version Not est toujours True du coup le code est toujours exécuté ..corriger la déclaration de IsWindowVisible afin qu'elle renvoie un long .
Quel est le Parent standard d'un UserForm affiché par la méthode .Show
Les fenêtres affichées dans bureau et qui ont le menu système les boutons min a max ainsi les dialogues n'ont pas de parent cette propriété est toujours nulle.

Les fenêtres ont aussi une autre propriété le Owner qui contrôle l'espace de travail de la fenêtre , le owner ne pourra jamais cacher ou se passionner au dessus des fenêtres qu'il contrôle et s'il est fermer tous ses fenêtres seront fermées également , pour définir le orner utilser SetWindowLongPtr via le paramètre GWL_HWNDPARENT .

Ex:
Code:
  SetWindowLongPtr fwin, -8&, FindWindow(vbNullString, Caption) ' définit l'actuelle forme comme owner pour la forme qui sera lancée
  ShowWindow fwin, 1
 
Dernière édition:
Ça fonctionne très bien.

Une remarque: avec ShowWindow() si le UserForm_Initialize() est exécuté dès le FindWindow() par la référence à la propriété Caption - FindWindow(vbNullString, UserForm.Caption) - le UserForm_Activate() n'est pas exécuté puisqu'on ne passe pas par la méthode UserForm.Show.

Il faut donc utiliser une petite astuce en déclarant une fonction Public Sub Activate() qui sera appelée si présente pour lancer le UserForm_Activate() si besoin. Voir la fonction UserFormShowWindow() dans le fichier joint.
Et attention au retour de UserForm de 2ème niveau qui lance également le UserForm_Activate(). A protéger !
 

Pièces jointes

Il faut vérifier que l'évenement Active soit correctement déclencher pour une fiche normale puisqu’il est utilisé par les développeurs .
Et pour une solution sérieuse il faut virer FindWindow elle peut renvoyer une fiche incorrecte du fait que sa portée et globale et sa recherche est basée sur le titre , déjà tu connais WindowFromAccessibleObject qui renvoie le handle du window à partir d'un IAccessible sinon tu peux essayer IUnknown_GetWindow.
 
On aussi peut imaginer la création d'une fonction Show mais qui lance une fiche en une sorte de soft modale en bloquant uniquement la fiche appelante ou un autre mode non modale mais synchronisé c'est à dire le code apres show ne sera pas exceter avant la fermeture de la fiche ..à voir
 
Bonjour,

Je suis étonné que tu ne fasses pas confiance à un FindWindow() mais si tu le dis...
Tu penses qu'il pourrait retourner un Handle d'une Window de même Caption d'une autre instance d'Excel ?

Le WindowFromAccessibleObject() ne fonctionne pas sur une UserForm seulement initialisé et pas visible.
Par contre le IUnknown_GetWindow() que je ne connaissais pas fonctionne. Très pratique pour trouver le Handle d'un UserForm !

Le même fichier que précédemment mais qui remplace le FindWindow() par cette fonction IUnknown_GetWindow().
 

Pièces jointes

On aussi peut imaginer la création d'une fonction Show mais qui lance une fiche en une sorte de soft modale en bloquant uniquement la fiche appelante ou un autre mode non modale mais synchronisé c'est à dire le code apres show ne sera pas exceter avant la fermeture de la fiche ..à voir
Je sais pas trop où tu veux en venir mais si tu as des idées de code pour obtenir ces effets, ça peut être intéressant.
 
- Navigue sans publicité
- Accède à Cléa, notre assistante IA experte Excel... et pas que...
- Profite de fonctionnalités exclusives
Ton soutien permet à Excel Downloads de rester 100% gratuit et de continuer à rassembler les passionnés d'Excel.
Je deviens Supporter XLD

Discussions similaires

  • Question Question
Microsoft 365 affichage userform
Réponses
4
Affichages
361
Retour