Pour des raisons qui m'échappent, les coordonnées d'une fenêtre ont des valeurs farfelues lorsque cette fenêtre est maximisée.
Ainsi:
VB:
With ActiveWindow
.Left
.Top
.Width
.Height
End With
ne correspondent pas à la réalité, du moins celle qui pourrait servir à position un UserForm aux limites de la fenêtre pas exemple.
Aussi, j'ai dû passer par de l'API pour déterminer l'exact RECT (pixels) d'une fenêtre qui doit rester valide en multi-moniteurs.
Et bingo, bug excel (chez moi en tous cas) lorsque la TaskBar n'est pas en bas sur la fonction API GetClientRect() qui retourne 1 pixel de moins que prévu en Bottom !
Alors j'ai 2 versions de cette fonction utilisateur GetWindowExactRECT et GetWindowExactRECTSimple et j'aimerais que quelques XLDNautes dévoués aux causes perdues fassent le test suivant.
Lancer le fichier ci-dessous
Maximiser la fenêtre Excel si elle ne l'est pas déjà
Pour chaque position de barre des tâches en bas, à gauche, en haut, à droite
a) - Vérifier que les 2 résultats affichées des RECT de la fenêtre sont identiques
b) Vérifier qu'ils sont cohérents avec la dimension de l'écran en pixels
C'est ça, en fait ça n'a pas tellement de sens de chercher ou d'utiliser le RECT de la fenêtre.
Car en Maximisé, si Excel dit que Left et Top c'est -8 ou -9 c'est que ce sont les valeurs telles qu'il les gère.
Cependant, ce RECT est inexploitable pour positionner un UserForm.
Le seule chose qui soit exploitable c'est le RECT de la fenêtre corrigé des marges qu'on trouve en calculant la différence de largeur et de hauteur entre le GetWindowRECT et le GetClientRECT corrigé du potentiel bug Excel sur le ClientRECT.Bottom quand la fenêtre est maximisée et la barre des tâches pas en bas ou en antohide. Sans bug Excel c'est moins amusant !
chez moi le post #13 corrigé
l'userform1 rentre de 1 point a vue d’œil dans la taskbar
et ça correspond bien au 2 -1 en haut et -1 en bas et c'est bon
et le rectangle m'est toujours donné -2 pour le top et 862 pour le bottom
autrement dit je rentre un peu dans la taskbar (en dessous du moins )
pour la taskbar
VB:
Option Explicit
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Private Declare PtrSafe Function GetWindowRect Lib "user32" _
(ByVal hWnd As LongPtr, ByRef lpRect As RECT) As Long
Private Declare PtrSafe Function SHAppBarMessage Lib "shell32" _
(ByVal dwMessage As Long, ByRef pData As APPBARDATA) As Long
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Type APPBARDATA
cbSize As Long
hWnd As LongPtr
uCallbackMessage As Long
uEdge As Long
rc As RECT
lParam As Long
End Type
Private Const ABM_GETSTATE As Long = &H4
Private Const ABS_AUTOHIDE As Long = &H1
Function IsTaskbarVisible() As Boolean
Dim hwndTaskbar As LongPtr
Dim rect As RECT
Dim appBarData As APPBARDATA
Dim appBarState As Long
' Trouver la fenêtre de la barre des tâches
hwndTaskbar = FindWindow("Shell_TrayWnd", vbNullString)
If hwndTaskbar = 0 Then
' Barre des tâches introuvable
IsTaskbarVisible = False
Exit Function
End If
' Vérifier si la barre des tâches est masquée automatiquement
appBarData.cbSize = LenB(appBarData)
appBarData.hWnd = hwndTaskbar
appBarState = SHAppBarMessage(ABM_GETSTATE, appBarData)
If (appBarState And ABS_AUTOHIDE) = ABS_AUTOHIDE Then
' En mode masquage automatique
IsTaskbarVisible = False
Exit Function
End If
' Obtenir la position et la taille de la barre des tâches
GetWindowRect hwndTaskbar, rect
' Si la hauteur ou la largeur est 0, elle est masquée
IsTaskbarVisible = Not (rect.Bottom - rect.Top = 0 Or rect.Right - rect.Left = 0)
End Function
Sub TestTaskbarVisibility()
If IsTaskbarVisible() Then
MsgBox "La barre des tâches est visible."
Else
MsgBox "La barre des tâches est masquée ou en mode auto-hide."
End If
End Sub
Bonsoir les encadreurs de fenêtres,
Grâce à la patience et l'assistance précieuses de @TooFatBoy que je remercie, j'ai enfin pu venir à bout de ce truc.
Remarque:
Le bug Excel qui rend une marge incorrecte à cause d'un ClientRECT.Bottom incorrect existe aussi lorsque la fenêtre n'est pas maximisée en 32 bits.
La marge totale verticale calculée avec ClientRECT.Bottom incorrect est impaire ce qui impossible car la marge totale contient les 2 marges (gauche+droite ou haute+basse) et aucune des marges ne peut être différente de sa réciproque.
SM_CYBORDER c'est 1 en haut et en bas (fenêtre pas maximisée)
SM_CXBORDER c'est 1 à gauche et à droite (fenêtre pas maximisée)
Donc c'est bien un foutu bug.
Le problème c'est que ClientRECT.Bottom incorrect c'est selon les cas +1 ou -1 pixel.
La solution est, pour la marge verticale, d'utiliser la marge horizontale qui semble toujours correcte et toujours applicable à la marge verticale.
Le fichier du Post #13 a été mis à jour en conséquence.
Edit: A noter que, mis à part le module concerné par ce sujet:
- Module_GetClientFromWindowRECT
ce fichier contient 3 modules intéressants pour des développeurs:
- Module_GetTaskBarRectPosAutoHid (pour le RECT, la position et l'autohide de la TaskBar)
- Module_GetUserFormMarginsPoints (pour connaître les marges extérieures des UserForm)
- Module_PointToPixelToPoint (pour convertir des pixels en points et inversement)
J'annonce ici le prochain sujet qui va défrayer la chronique et susciter les polémiques les plus violentes... Quoi de moins simple que de déterminer le RECT de la barre des tâches en multi-moniteurs ?
J'ai déjà 3 options qu'il faut que je présente proprement dans un fichier de test et dont je ne sais pas pour 2 d'entre elles si elles fonctionnent en multi-moniteurs dont les possesseurs seront sollicités.
Bonjour
perso je m'intéresse à celle ci de discussion
Au final tu dis que: getwindowrect ne donne pas le bon rectangle
que getclientrect t'en donne un autre et qu'une opération de soustraction ou addition permet d'avoir le bon rectangle
dans ton fichier tu ajoute même la DWM qui fait je ne sais quoi (tout du moins dans ton exemple)
et ben moi je persiste et signe de te dire que tu a tout faux
tout ce que tu fais est une approximation aussi bonne soit elle
Alors oui en effet le getwindowrect sur le handle d'une fenêtre maximisée donne( - quelque chose) en left et en top (chez moi -8 et -8), c'est un bug(si tant est que l'on puisse appeler ça un bug )c'est tout simplement parce que l'on a pas accès avec les api window a la classe UTM car l'accès N°1 que l'on a c'est le desktop
mais bon bref
quand on rectifie ce petit soucis par exemple sur la fenêtre excel ,getwindowrect te donne parfaitement le bon rectangle
et quand je contrôle avec DWM ( je parle de la version que je 'tai donné il y a au moins 2 ans)
et bien mon rectangle DWM a les mêmes données que getwindowrect sans correction
ça veux dire quoi selon toi ?
et bien je te le dis les rectangles après correction des -(pour le maximisé et rien pour le fenêtré) sont parfaitement exacts
oui mais alors que se passe til pour quoi mon userform placé au left et top de mon application n'est pas à la bonne place
la déjà là quand on observe le phénomène dans l'ordre on commence a comprendre
on comprend quoi : et bien que depuis W10 22h2 l'application excel ne subit plus le DWM comme avec windows7 par exemple
par contre les userforms OUI !!!
donc au final tu essaie de placer un userform dont l'affichage est géré par la DWM avec les coordonnées d'une fenêtre qui ne subit pas le DWM
comment tu fait ?: ben en enlevant un peu ceci ou ajoutant cela et je parle du clientrect et les bordures de getsystemmùetrics et tout icouinti qui n'ont rien avoir avec cet écart d'affichage
Alors certes oui au bout d'un moment on arrive a quelque chose encore heureux
sauf que tu zigzag pour avoir un résultat qui est à ta portée déjà sans tout ton bourrin
démonstration
mon écran paramétré a 1600 par 900
ma fonction getwindowrect pour l'application
pas de moins clientrectangle et sm_border et autres cochonneries
d'ailleurs pas un seul caractère numérique dans le code pour extraire ou ajouter quoi que ce soit
VB:
Sub testQ()
Dim Rc As RECT
Rc = ApplicationRECT
mess = "Left : " & Rc.Left & vbCrLf & _
"Top : " & Rc.Top & vbCrLf & _
"Right : " & Rc.Right & vbCrLf & _
"Bottom : " & Rc.Bottom
MsgBox mess
End Sub
Function ApplicationRECT() As RECT
Dim R1 As RECT, Tm, Lm&
R1 = WINDOWRECTANGLE(Application.hwnd)
If Application.WindowState = xlMaximized Then Tm = R1.Top: Lm = R1.Left
R1.Left = R1.Left - Lm
R1.Top = R1.Top - Tm
R1.Right = R1.Right + Lm
R1.Bottom = R1.Bottom + Tm
ApplicationRECT = R1
End Function
demo maximisé
860+les 40 de la taskbar ça me fait 900 on est bon
non maximisé c'est pas la peine que je montre le code est tellement simple hein
voyons voir maintenant en faisant simplement la comparaison donc
en mettant le userform au left top et.. comme ça en point sans api
et en corrigeant avec la simple comparaison du getwindowrect(qui est parfaitement juste je le rappelle) avec le rectangle de DWM et appliquons la correction
Alors pour conclure
quoi de moins simple que de déterminer le rect d'une fenêtre ben moi je réponds rien le getwindowrect le fait très bien tout seul à partir du moment ou on sait quand prendre en compte le DWM ou pas
voilà mon cher @Dudu2 quand tu auras compris quand et comment se servir de certaines Api tes codes deviendrons limpides