XL 2016 VBA - Comment savoir si une fonction est appelée d'un UserForm ?

Dudu2

XLDnaute Barbatruc
Bonjour,

Dans une fonction, je récupère le Handle de la fenêtre active: API GetActiveWindow.
Comment savoir si ce Handle est celui d'un UserForm ou pas ? Par le ClassName ? Autre ?

Merci par avance.
 
C

Compte Supprimé 979

Guest
Salut Dudu2

Et si tu nous disais quel est le but de tout ça ?

Sinon voici un code trouvé
VB:
Public Declare Function GetForegroundWindow Lib "user32" _
    Alias "GetForegroundWindow" () As Long
Public Declare Function GetWindowText Lib "user32" _
    Alias "GetWindowTextA" (ByVal hwnd As Long, _
    ByVal lpString As String, ByVal cch As Long) As Long

Sub RecupNomActiveWindow()
    Dim WinText As String
    Dim HWnd As Long
    Dim L As Long
    HWnd = GetForegroundWindow()
    WinText = String(255, vbNullChar)
    L = GetWindowText(HWnd, WinText, 255)
    WinText = Left(WinText, InStr(1, WinText, vbNullChar) - 1)
    Debug.Print L, WinText
End Sub

A+
 

Dudu2

XLDnaute Barbatruc
Bonsoir @BrunoM45,

Merci pour ta proposition. Je vais regarder le code mais le GetWindowText il me semble que je l'avais testé, je ne récupérais ni le Caption ni le nom du UserForm. Je vais quand même vérifier mais ce qui m'intéresse c'est savoir si c'est un UserForm. Alors si je récupère le nom, ce qui m'étonnerais avec cette API, je pourrais comparer avec les UserForms visibles du Projet. Idéalement il faudrait récupérer une information de Class caractéristique d'un UserForm.

Le but est assez complexe, il s'agit, pour un utilitaire utilisant lui-même un UserForm de savoir, lorsqu'il est demandé d'exclure des interactions extérieures quand il est affiché, s'il doit se placer en vbModeless + Interactive = False car appelé directement ou en vbModal sur un UserForm vbModeles qui l'appelle, sachant que sur un UserForm vbModal il ne peut se placer lui-même qu'en vbModal. Alors il faut que je sache qui l'appelle car que je veux privilégier le vbModeless qui me permet de faire des choses comme boucler pour faire un timer ou capter des sélections sur feuille alors que le UserForm est affiché.
 

Dudu2

XLDnaute Barbatruc
Bonsoir @patricktoulon,
Merci pour ta proposition, je vais tester ça. J'ai eu la flemme d'attaquer directement par le test
1668806100899.gif
avant de poser la question à laquelle je pensais bien que tu apporterais, avec @BrunoM45 en l'occurrence, un élément de réponse.
1668806111778.gif
 

patricktoulon

XLDnaute Barbatruc
re
Le but est assez complexe, il s'agit, pour un utilitaire utilisant lui-même un UserForm de savoir, lorsqu'il est demandé d'exclure des interactions extérieures quand il est affiché, s'il doit se placer en vbModeless + Interactive = False car appelé directement ou en vbModal sur un UserForm vbModeles qui l'appelle, sachant que sur un UserForm vbModal il ne peut se placer lui-même qu'en vbModal. Alors il faut que je sache qui l'appelle car que je veux privilégier le vbModeless qui me permet de faire des choses comme boucler pour faire un timer ou capter des sélections sur feuille alors que le UserForm est affiché.

re dans ce cas là met une variable public dans le usf appellé (pas l'appelant)
du genre public QUI
substitue la fonction show par ta propre fonction show
du genre

VB:
Option Explicit

Public QUI

Public Function ShowX(parmoi, Optional ByVal vbmode = 1)

With UserForm1

Set .QUI = parmoi

.Show vbmode

End With

End Function

Private Sub UserForm_Activate()
MsgBox "Hallo!!! c'est " & QUI.Name & " qui appelle"
End Sub

dans le bouton de l'autre userform
VB:
Private Sub CommandButton1_Click()
UserForm1.ShowX Me, 1
End Sub
terminé la variable q"QUI" est dispo dans tout le userform tant qu'il reste loadé
 

Dudu2

XLDnaute Barbatruc
Il me semble bien que j'avais testé ça y a un certain temps sans arriver à un résultat.
Dans les 2 cas je récupère le Handle Excel comme Parent du UserForm.

Maintenant je vais tester avec une fonction interne qui fait le Show pour voir la différence.
 

Pièces jointes

  • Test si UserForm appelé par UserForm.xlsm
    30.5 KB · Affichages: 1

Dudu2

XLDnaute Barbatruc
Ok, quand on intercepte le Handle avant le Show on récupère bien le bonne classe.
C'est dommage qu'à partir du UserForm de 2ème niveau on ne retrouve pas le Handle du UserForm de 1er niveau.
Excel rattache systématiquement les UserForms à l'ActiveWindow apparemment.
 

Dudu2

XLDnaute Barbatruc
Et à toutes fins utiles, une petite fonction pour terminer...
VB:
Private Declare PtrSafe Function GetActiveWindow Lib "user32.dll" () As LongPtr
Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long

'--------------------------------------------------
'Retourne True si le Handle est celui d'un UserForm
'--------------------------------------------------
Function CallerIsUserForm(Optional ByVal hWndCaller As LongPtr = 0) As Boolean
    Dim Class As String
 
    If hWndCaller = 0 Then hWndCaller = GetActiveWindow
    Class = Space$(255)
    Call GetClassName(hWndCaller, Class, Len(Class))
    Class = UCase(Left(Class, InStr(Class, Chr(0)) - 1))
    If Class = "THUNDERDFRAME" Or Class = "THUNDERXFRAME" Then
        'Return value
        CallerIsUserForm = True
    End If
End Function

Edit: Et comme le précise @patricktoulon dans le message suivant, si on appelle cette fonction d'un UserForm pour savoir qui veut l'afficher, il faut intercepter le Handle de l'appelant AVANT le UserForm_Activate() car Excel ne donnera pas un UserForm appelant comme Parent du UserForm appelé, ce qui exclut de le retrouver avec l'API GetParent() !
Ce qui revient à devoir écrire une procédure Public dans le UserForm de type:
VB:
Private Declare PtrSafe Function GetActiveWindow Lib "user32.dll" () As LongPtr
Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long

Private AppelantEstUserForm As Boolean

Public Sub Display(Optional ByVal ShowMode As Integer = vbModal)
    AppelantEstUserForm = CallerIsUserForm
    Me.Show ShowMode
End Sub
Et au lieu de faire UserForm1.Show, faire UserForm1.Display (avec le paramètre Mode éventuel)
 
Dernière édition:

patricktoulon

XLDnaute Barbatruc
Et à toutes fins utiles, une petite fonction pour terminer...
VB:
Private Declare PtrSafe Function GetActiveWindow Lib "user32.dll" () As LongPtr
Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long

'--------------------------------------------------
'Retourne True si le Handle est celui d'un UserForm
'--------------------------------------------------
Function CallerIsUserForm(Optional ByVal hWndCaller As LongPtr = 0) As Boolean
    Dim Class As String
 
    If hWndCaller = 0 Then hWndCaller = GetActiveWindow
    Class = Space$(255)
    Call GetClassName(hWndCaller, Class, Len(Class))
    Class = UCase(Left(Class, InStr(Class, Chr(0)) - 1))
    If Class = "THUNDERDFRAME" Or Class = "THUNDERXFRAME" Then
        'Return value
        CallerIsUserForm = True
    End If
End Function

Edit: Et comme le précise @patricktoulon dans le message suivant, si on appelle cette fonction d'un UserForm pour savoir qui veut l'afficher, il faut intercepter le Handle de l'appelant AVANT le UserForm_Activate() car Excel ne donnera pas un UserForm appelant comme Parent du UserForm appelé, ce qui exclut de le retrouver avec l'API GetParent() !
Ce qui revient à devoir écrire une procédure Public dans le UserForm de type:
VB:
Private Declare PtrSafe Function GetActiveWindow Lib "user32.dll" () As LongPtr
Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long

Private AppelantEstUserForm As Boolean

Public Sub Display(Optional ByVal ShowMode As Integer = vbModal)
    AppelantEstUserForm = CallerIsUserForm
    Me.Show ShowMode
End Sub
Et au lieu de faire UserForm1.Show, faire UserForm1.Display (avec le paramètre Mode éventuel)
re
comme je te l'ai montré dans le message précédent #6
à utiliser une fonction pucblic perso d'affichage (show) ben tant qu'a faire utilise un argument supplémentaire object userform et utilise findwindow
comme ca on est sur
 

Discussions similaires

Statistiques des forums

Discussions
314 716
Messages
2 112 165
Membres
111 447
dernier inscrit
jasontantane