Bizarrerie HDC et AutoRedraw

Résolu
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 - 9 nov. 2006 à 16:02
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 - 12 nov. 2006 à 15:04
[VB6 SP6 sur XP Pro SP1]

bonjour bonjour....

en voilà une curiosité pour le moins dérangeante....
par une classe j'accède au HDC d'un contrôle, soit en le fournissant, soit en fournissant le hWnd qui est alors converti.

le problème est le suivant :
supposons une Form, une PictureBox ou autre, si le handle est fourni, on récupère le hDC à partir d'une API.
seulement... le hDC trouvé n'est pas le même que le vrai hDC, si l'objet est en autoredraw = True

exemple très simplifié (juste une Form) :

Option Explicit
Private Declare Function GetWindowDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long

Private Sub Form_Activate()
    Me.AutoRedraw = False '<- par défaut
    Debug.Print "HDC Form : " & vbTab & vbTab & vbTab & "[ok!]" & Me.hDC
    Debug.Print "HDC GetDC : " & vbTab & vbTab & "[ok!]" & GetDC(Me.hwnd)
    Debug.Print "HDC GetWindowDC :
" & vbTab; "[ah?]" & GetWindowDC(Me.hwnd)
    Debug.Print "-------------------"

    Me.AutoRedraw = True
    Debug.Print "HDC Form : " & vbTab & vbTab & vbTab & "[ah?]" & Me.hDC
    Debug.Print "HDC GetDC : " & vbTab & vbTab & "[...]" & GetDC(Me.hwnd)
    Debug.Print "HDC GetWindowDC :
" & vbTab; "[ah?]" & GetWindowDC(Me.hwnd)
    
    Unload Me
End Sub

<small>Coloration
syntaxique automatique [AFCK] </small>
       

et la trace donne :

HDC Form :          [ok!]-234809995
HDC GetDC :         [ok!]-234809995
HDC GetWindowDC :   [ah?]1728121069
-------------------
HDC Form :          [ah?]-402586175
HDC GetDC :         [...]-234809995
HDC GetWindowDC :   [ah?]402724366

et évidemment dans l'utilisation je ne peux/dois pas tester les propriétés de l'objet...

les questions sont donc la suivantes :
1) Pourquoi l'API GetDC donne toujours le même résultat, mais qui est alors faux si l'objet est en autoredraw =true
2) Pourquoi l'API GetWindowDC donne toujours un résultat faux
3) Pourquoi la propriété réelle Objet.hDC change si sa propriété autoredraw change

je continue à chercher de mon côté, n'hésitez pas si vous avez quelques pistes (voire solutions avec une API plus efficace )

merci
<hr size="2" width="100%" />Prenez un instant pour répondre à ce sondage svp

11 réponses

jmfmarques Messages postés 7666 Date d'inscription samedi 5 novembre 2005 Statut Membre Dernière intervention 22 août 2014 27
10 nov. 2006 à 07:43
Bonjour PCPT,


En lisant ton nouveau message, je comprends mieux ton étonnement.


Je suis encore un peu endormi (mal dormi cette nuit) et te prie de m'excuser si mon expression n'est pas des meilleures ce matin.


Je vais essayer, point par point.


1) La fonction GetDC
Elle extrait le handle d'un contexte de Device d'affichage (DC) pour la surface "cliente" de la fenêtre spécifiée. Ce DC peut alors être utilisé, par les fonctions GDI à venir, pour dessiner dans la surface "cliente" de la fenêtre.
La valeur qu'elle retourne identifie le DC dela surface "cliente" de la fenêtre spécifiée
Lorsque l'on écrit Me.hdc, VB appelle la fonction GetDC

2) La fonction GetWindowDC
Elle extrait quant à elle le contexte de Device  de la fenêtre entière (y compris donc sa barre de titre, ses menus, ses ascenseurs, etc...).Un contexte de Device  de fenêtre permet de dessiner à tout endroitde la fenêtre (l'origine du contexte de Device   étant le coin supérieur gauche de la fenêtre et non de la surface cliente).

Dans ton exemple (ton code plus haut) :

Au départ :la valeur de Me.HDC  et la valeur retournée par GetDC sont bien évidemment identiques
Mais ensuite :  cette valeur, comme nous l'explique VB, est susceptible de varier tout au long de l'exécution, notamment (mais pas uniquement) du fait de AutoRedraw.
Or, en écrivant à nouveau Me.HDC, tu as provoqué (voir plus haut) un nouvel appel de la fonction GetDC par VB et a donc obtenu la nouvelle valeur, alors que tu la compares avec celle (non recalculée) retournée par ton premier appel de GetDC

Ces deux valeurs sont donc alors différentes (seule l'une d'entre elles ayant été recalculée)

Voilà... J'espère que mes explications seront suffisamment compréhensibles.

Je te propose, si tu le souhaites, de me dire ce que tu cherches à faire et essaierai bien volontiers de mon côté (ceci pourrait se faire par MP)
3
cs_casy Messages postés 7741 Date d'inscription mercredi 1 septembre 2004 Statut Membre Dernière intervention 24 septembre 2014 40
9 nov. 2006 à 18:03
Normalement si tu est en autoredraw est à TRUE, le object.hdc devrait changer à chaque Redraw.
J'avais lu que avec AutoRedraw à  True, le Redarw ne redessine pas une fenetre, mais crée une seconde fenêtre, mise à jour, puis supprime la première.

Définition de GetDC :
The GetDC function retrieves a handle of a display device context (DC) for the client area of the specified window. The display device context can be used in subsequent GDI functions to draw in the client area of the window.

Définition de GetWindowsDC :
The GetWindowDC function retrieves the device context (DC) for the entire window, including title bar, menus, and scroll bars. A window device context permits painting anywhere in a window, because the origin of the device context is the upper-left corner of the window instead of the client area.

La différence entre les deux ? GetDC te renvoie un handle sur le contexte de périphérique de la zone de dessin de ta fenêtre (l'endroit ou tu met les controles). Tandis que GetWindowDC te renvoie un handle sur le contexte de périphérique de la totalité de la fenêtre (incluant donc bordure, menu, barre de titre, ...)

Mais bon, tout ça ne répond pas vraiment à tes questions. Dsl

---- Sevyc64  (alias Casy) ----<hr size="2" width="100%" /># LE PARTAGE EST NOTRE FORCE #
0
Dolphin Boy Messages postés 630 Date d'inscription vendredi 5 mai 2006 Statut Membre Dernière intervention 17 février 2007
9 nov. 2006 à 21:09
Salut, et si tu utilises (bien sûr avec les API correspondantes déclarées) :
GetDC(GetDesktopWindow())
à la place de
GetWindowDC(Me.hwnd)

?
0
Dolphin Boy Messages postés 630 Date d'inscription vendredi 5 mai 2006 Statut Membre Dernière intervention 17 février 2007
9 nov. 2006 à 21:11
Heu, je voulais dire :
à la place de
GetDC(Me.hwnd)
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
jmfmarques Messages postés 7666 Date d'inscription samedi 5 novembre 2005 Statut Membre Dernière intervention 22 août 2014 27
9 nov. 2006 à 21:56
Contrairement au handle hwnd, la propriété hdc est susceptible de changements tout au long de l'exécutiuon de l'application.


Il est donc nécessaire d'en déterminer la valeur juste avant de s'en servir, et ce systématiquement...


Voici (rappel) ce qu'en dit VB (à noter au passage ce que provoque Autoredraw) :

Note   The value of the hDC property can change while a program is running, so don't store the value in a variable; instead, use the hDC property each time you need it.



The AutoRedraw property can cause the hDC property setting to change. If AutoRedraw is set to True for a form or PictureBox container, hDC acts as a handle to the device context of the persistent graphic (equivalent to the Image property). When AutoRedraw is False, hDC is the actual hDC value of the Form window or the PictureBox container. The hDC property setting may change while the program is running regardless of the AutoRedraw setting.
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
10 nov. 2006 à 00:48
merci pour vos réponses, désolé de ce silence, je n'ai pas reçu d'alerte.
bref...

casy -> beh oui mais en effet, çà ne m'aide pas beaucoup. et l'exemple avec une picturebox, GetDC et GetWindowDC devraient retourner la même chose, ce qui n'est pas le cas.

pour être plus précis, ce n'est pas le cas SI l'autoredraw est changé en cours d'utilisation, ce qui n'a en réalité aucun rapport avec un cls ou un refresh, et c'est bien là mon étonnement....

Dolphin Boy -> beh pour ce cas final (rappel, ici juste un allégé pour provoquer le bug), çà ne correspond malheureusement pas du tout :-(

jmfmarques -> je suppose que tu as trouvé çà dans la MSDN en ligne, je n'y ai pas mis les pieds.
merci pour l'info très utile, celà dit, pareil, çà n'explique pas pourquoi alors le vrai hDC change, alors que le GetDC retourne toujours la même valeur, alors éronnée...

pour être un peu plus précis, je récupère une dimention en fonction du hWnd ou hDC (jmfmarques, rapport à un sujet récent qui a précédent notre rapide échange en MP). et ormis le côté ScaleMode, je ne récupère pas les même résultats selon si le hDC est "le réel" ou est celui rendu par l'API...
<hr size="2" width="100%" />Prenez un instant pour répondre à ce sondage svp
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
10 nov. 2006 à 11:59
salut jmfmarques,
endormi ou non, ta réponse est compréhensible. c'est moi qui ne doit pas faire la part des choses...

"Lorsque l'on écrit Me.hdc, VB appelle la fonction GetDC" (...) "alors que tu la compares avec celle (non recalculée) retournée par ton premier appel de GetDC"
umm, je la recalcule, si. donc comparaison correcte (il me semble)
la première fois, Me.hDC et GetDC(Me.hwnd) retournent bien la même valeur, mais pas la seconde fois.

j'ai aussi fait le test avec un usercontrol, ne retournant que le hDC et le hWnd, sans rien d'autre (ni code ni composant), je ne vois toujours pas pourquoi -dans ce cas de figure- GetWindowDC renvoie une valeur éronnée.

en fait ces questions sont pour comprendre le fonctionnement réel du DC, puisque j'ai un décalage avec le handle

ce que je cherche à faire...
très simple, juste mesurer un texte en référence à n'importe quel objet (comportant au moins un hWnd) sans utiliser d'objet font.

sur une Form, change la font pour Tahoma 16 par exemple, puis pose une PictureBox et un CommandButton
(dans cet ordre pour que leurs propriétés héritent de celle de la Form)

Option Explicit
Private Type POINTAPI
    X As Long
    Y As Long
End Type
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetTextExtentPoint32 Lib "gdi32" Alias "GetTextExtentPoint32A" (ByVal hDC As Long, ByVal lpsz As String, ByVal cbString As Long, lpSize As POINTAPI) As Long

Private Sub Form_Activate()
    Dim sRes As String, pRet As POINTAPI
    Const mText As String =  "Mon
texte"
    
    Call GetTextExtentPoint32(Picture1.hDC, mText, Len(mText), pRet)
    sRes = "Picture : " & pRet.X & " x " & pRet.Y & vbCrLf
    
    Call GetTextExtentPoint32(GetDC(Command1.hwnd), mText, Len(mText), pRet)
    sRes = sRes & "Button :
" & pRet.X & " x
" & pRet.Y & vbCrLf
    
    MsgBox "Les valeurs DEVRAIENT être les
mêmes..." & vbCrLf & sRes
    Unload Me
End Sub

<small>Coloration
syntaxique automatique [AFCK] </small>
       

voilà, vous savez tout ^^
n'hésitez pas...
<hr size ="2" width="100%" />Prenez un instant pour répondre à ce sondage svp
0
jmfmarques Messages postés 7666 Date d'inscription samedi 5 novembre 2005 Statut Membre Dernière intervention 22 août 2014 27
10 nov. 2006 à 14:15
C'est tout simplement dû au fait que le DC de Command1 n'en est pas un de surface d'affichage cliente.
Remplace dans ton test Command1 par une PictureBox Picture2 (ou par la Form elle même) et tu verras que tout va bien...

Comme tu t'y es pris, celà ne peut fonctionner : tu pourrais mettre n'importe quoi à la place de command1.hwnd et tu obtiendrais toujours  le même résultat ! Essaye de remplacer command1.hwnd par 0, 354, 28, 100, 1000, ou ce que tu voudras et tu verras : toujours le même résultat, tout simplement parce que tu ne pointeras pas vers une surface d'affichage/dessin cliente..

Il te faut nécessairement "dessiner" fictivement dans une surface cliente de dessin et donc soit une Form, soit une PictureBox, soit enfin un DC créé sur mesure par la fonction CreateDC, mais pas celà ne peut marcher directement avec un commandButton, une textbox, etc...

Maintenant, si tu veux écrire directement sur le commandButton, c'est possible, mais alors avec GetWindowDC (et alors oui, tu pourras extraire les dimensions du texte par GetTextExtentPoint32.

Si tu veux un exemple, je t'en concocte un bien volontiers et te l'envoie par MP. Tu dis...
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
10 nov. 2006 à 14:49
pas le DC de surface? et les 2 API (pour le coup) renvoient le même résultat.
compréhensible dans ce cas, ok, mais alors le DC ne devrait pas être utilisable, et pourtant :

Option Explicit
Private Declare Function ExtTextOut Lib "gdi32" Alias "ExtTextOutA" (ByVal hdc As Long, ByVal X As Long, ByVal Y As
Long, ByVal wOptions As Long, ByVal lpRect As Any, ByVal lpString As String, ByVal nCount As Long, lpDx As Long) As Long
Private Declare Function Ellipse Lib "gdi32" (ByVal hdc As Long, ByVal X1 As Long, ByVal Y1 As
Long, ByVal X2 As Long,
ByVal Y2 As Long) As
Long
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetWindowDC Lib "user32" (ByVal hwnd As Long) As Long
'
Private Sub Form_Load()
    Command1.Width =  3615
    Command1.Height = 1335
End Sub
'
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
    End
End Sub
'
Private Sub Form_Activate()
    Dim Ret As Long
    Ret = GetDC(Command1.hwnd)
'    Ret
= GetWindowDC(Command1.hwnd)
    Do
        Ellipse Ret, 0, 0, Command1.Width / 15, Command1.Height / 15
        ExtTextOut Ret, 95, 37, 0, ByVal 0&, "j'écris", Len("j'écris"), ByVal 0&
        DoEvents
    Loop
End Sub

<small>Coloration
syntaxique automatique [AFCK] </small>
       

mais le but n'est pas d'écrire...

et essayer avec des PictureBox, évidemment, çà çà marche déjà (encore une chance ), mais çà ne change pas mon problème final....

utiliser CreateDC, j'y ai pensé mais je ne pourrai pas récupérer les propriétés Font de l'objet (il me semble).
par récupérer, j'entends juste les calquer...

me faire un exemple... beh si c'est comme le code ci-dessus, tu vois que je m'en sors seul

avec CreateDC, pourquoi pas.
ne pas oublier que ce n'est pas les dimentions du contrôle que je veux, mais bien récupérer celles d'une chaîne, et ce même en passant par un objet n'ayant pas de hDC

avec ou sans résultat, merci de ton suivi, et merci à tous pour vos participations
++
<hr size ="2" width="100%" />Prenez un instant pour répondre à ce sondage svp
0
jmfmarques Messages postés 7666 Date d'inscription samedi 5 novembre 2005 Statut Membre Dernière intervention 22 août 2014 27
11 nov. 2006 à 21:43
Bonsoir PCPT,

Désolé, mais à mon âge on finit par abdiquer au bout de 48 heures sans succès.

1) Rien à faire : il faut un véritable hdc et il faut lui indiquer la Font.
2) en créer un marche mais ne sert à rien d'autre qu'à en ajouter un alors que la Form est déjà là (ou une pictureBox, si tu en veux une)...

la seule possibilité est donc hélas la suivante (mais tu la connaissais déjà) et revient simplement à se passer de textwidth de Monsieur VB en appelant soi-même ce que cet ami appelle pour nous, à savoir la   fonction GetTextExtentPoint32

Voilà pour la largeur d'affichage (remplacer .X par .Y pour la hauteur, selon le même principe)

Private Type TAILLE
    X As Long
    Y As Long
End Type


Private Declare Function GetTextExtentPoint32 Lib "gdi32" Alias   "GetTextExtentPoint32A" (ByVal hdc As Long, ByVal lpsz As String, _
ByVal cbString As Long, lpSize As TAILLE) As Long


Private Function TailleDuTexte(ByVal hdc As Long, ByVal texte As String) As TAILLE
    Dim lataille As TAILLE
    GetTextExtentPoint32 hdc, texte, Len(texte), lataille
    lataille.X = lataille.X * Screen.TwipsPerPixelX
    lataille.Y = lataille.Y * Screen.TwipsPerPixelY
    TailleDuTexte = lataille
End Function
 


Private Sub Command1_Click()
  Font.Size = Command1.FontSize
  MsgBox TailleDuTexte(Me.hdc, Command1.Caption).X
End Sub

Désolé... mais là, ...j'arrête !
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
12 nov. 2006 à 15:04
la source est posée...
http://www.vbfrance.com/code.aspx?ID=40299

un peu déçu de la manoeuvre, mais le résultat est là, et est exact.
merci pour tes tentatives ^^

je valide ta précédente réponse, même si le but final (hWnd utilisable) reste au final sans suite

++
<hr size="2" width="100%" />Prenez un instant pour répondre à ce sondage svp
0
Rejoignez-nous