Page 1 sur 3

[API Windows] Lire la valeur d'une barre de progression ?

Publié : jeu. 28/juil./2011 12:18
par kelebrindae
Bonjour,

Pour faire une farce à un collègue, j'ai eu une idée mais je ne sais pas si c'est réalisable.
Voilà l'idée:
1 - Pendant qu'il est absent, je lui mets dans son groupe de démarrage un petit programme PB qui tourne en mode "invisible".
2 - Ce programme scanne régulièrement toutes les fenêtres ouvertes dans Windows à la recherche d'un type de gadget particulier (les barres de progressions, en l'occurrence).
3 - Si le programme trouve un gadget de ce type, j'affiche par dessus une petite image rigolote, qui se déplace en même temps que la barre progresse.
4 - Moultes LoLeries

Voilà où j'en suis (une grosse partie de ce code a été trouvé dans ce forums, donc merci aux auteurs).
Qui pourra me dire comment récupérer la valeur d'une progress bar dans l'API Windows ?

Code : Tout sélectionner

EnableExplicit

; Enumère les fenêtres filles
Procedure.l EnumChildWindowProc(hwnd.l, hParentWnd.l)
  Protected classe.s, chaine.s, rc.RECT
  Protected windowX.w,windowY.w,windowWIDTH.w,windowHEIGHT.w
  Protected chaine_coords.s
  
  If GetParent_(hWnd) = hParentWnd
    classe=Space(100)
    chaine=Space(255)
    GetClassName_(hwnd, @classe, 100)
    GetWindowText_(hwnd,@chaine,255)
    GetWindowRect_(hwnd,@rc)  

    windowX = rc\left
    windowY = rc\top
    windowWIDTH = rc\right-rc\left
    windowHEIGHT = rc\bottom-rc\top
    chaine_coords = Str(windowX)+","+Str(windowY)+","+Str(windowWIDTH)+","+Str(windowHEIGHT)
    
    If classe = "msctls_progress32"
      GetWindowText_(hParentWnd,@chaine,255)
      Debug "   Progress bar trouvée : "
      Debug "      Fenêtre : " + chaine
      Debug "      Position: " + Str(windowX)+","+Str(windowY)
      Debug "      Taille  : " + Str(windowWIDTH)+","+Str(windowHEIGHT)     
      Debug " J'ai trouvé la Progress Bar, mais comment je récupère sa valeur ?"
    EndIf
  EndIf

EndProcedure


; Parcourt toutes les fenêtre visibles
Procedure listWindows()
  Protected hwnd.l

  hWnd = FindWindow_( 0, 0 )
  
  While hWnd <> 0
    If GetWindowLong_(hWnd, #GWL_STYLE) & #WS_VISIBLE = #WS_VISIBLE
      If GetWindowLong_(hWnd, #GWL_EXSTYLE) & #WS_EX_TOOLWINDOW <> #WS_EX_TOOLWINDOW

          EnumChildWindows_(hWnd, @EnumChildWindowProc(),hWnd)

      EndIf
    EndIf
    hWnd = GetWindow_(hWnd, #GW_HWNDNEXT)
  Wend
  
EndProcedure

; Créer une fenêtre avec une barre de progression, pour le test
OpenWindow(0,0,0,320,200,"test progress bar")
ProgressBarGadget(1,5,5,200,20,0,100)
SetGadgetState(1,53) ; je la positionne arbitrairement à 53, juste pour le test

; Et là, je pars à sa recherche dans les fenêtres de Windows
listWindows()

Re: [API Windows] Lire la valeur d'une barre de progression

Publié : jeu. 28/juil./2011 19:16
par Ar-S
ça peu être drôle, je ne suis pas assez connaisseur en API pour t'aider sur ce coup mais je vais suivre ce sujet.

Re: [API Windows] Lire la valeur d'une barre de progression

Publié : jeu. 28/juil./2011 19:32
par zaphod
...

Re: [API Windows] Lire la valeur d'une barre de progression

Publié : ven. 29/juil./2011 8:41
par kelebrindae
C'est tout-à-fait ça, Zaphod. Merci ! :D

Voilà un second code pour tester le principe.
Pour l'instant, ça ne fonctionne qu'avec la barre qui se trouve dans PB (puisque je fais le dessin avec un startdrawing de base), mais le résultat est là: je peux retrouver la barre de progression, récupérer sa valeur, et calculer où je dois dessiner.

Bon, maintenant, je n'ai plus qu'à trouver comment afficher une image dans (ou par-dessus) une autre fenêtre...
Je vais fouiller un peu dans les forums, mais si vous avez des pistes, je suis preneur ! :P

Code : Tout sélectionner

EnableExplicit

Procedure redrawProgressBar(hParentWnd.l,hwnd.l)
  Protected rc.RECT
  Protected chaine.s
  Protected oldrange.q,lo.l,hi.l,valeur.l
  Protected posX.f
  
  ; récupérer les coordonnées de la barre
  GetWindowRect_(hwnd,@rc) 
  valeur = SendMessage_(hwnd,#PBM_DELTAPOS,0,0)
  
;   chaine=Space(255)
;   GetWindowText_(hParentWnd,@chaine,255)
;   Debug "   Progress bar trouvée : "
;   Debug "      Fenêtre : " + chaine
;   Debug "      Position: " + Str(rc\left)+","+Str(rc\top)
;   Debug "      Taille  : " + Str(rc\right - rc\left)+","+Str(rc\bottom - rc\top)
;   Debug "      Valeur  : " + Str(valeur)
  
  ; Pour connaitre la position du bout de la barre, il faut avoir les valeurs 
  ; minimum/maximum de la barre (ce n'est pas forcément 0 / 100)
  ; Problème: je ne sais pas comment la récupérer sans la modifier (sendMessage_ renvoie la valeur avant modif')
  ;           => je dois donc repositionner les valeurs récupérées après
  oldrange = SendMessage_(hwnd,#PBM_SETRANGE32,0,valeur+1)
  lo = oldrange & %00000000000000001111111111111111
  hi  = (oldrange & %11111111111111110000000000000000) >> 16
  SendMessage_(hwnd,#PBM_SETRANGE32,lo,hi)
;   Debug "      Low     : " + Str(lo)
;   Debug "      Hi      : " + Str(hi)
  
  posX = ((valeur - lo) / (hi - lo)) ; Pourcentage de progression
  posX * (rc\right - rc\left) ; Avancement dans la barre (en pixels)
      
  ; Temporaire pour le test: ne fonctionne qu'avec la progress bar de la fenêtre PB en cours
  StartDrawing(WindowOutput(0))
    Box(rc\left,rc\bottom + 5,(rc\right - rc\left),10,$FFFFFF)
    Circle(rc\left + posX,rc\bottom + 9,4,$0000FF)
  StopDrawing()
  
EndProcedure

; Enumère les fenêtres filles
Procedure.l EnumChildWindowProc(hwnd.l, hParentWnd.l)
  Protected classe.s
  
  ; Tester si on se trouve sur une progress bar
  If GetParent_(hWnd) = hParentWnd
    classe=Space(100)
    GetClassName_(hwnd, @classe, 100)
    If classe = "msctls_progress32"
      ; Si oui, on la redessine
      redrawProgressBar(hParentWnd,hwnd)
    EndIf
  EndIf

EndProcedure


; Parcourt toutes les fenêtre visibles
Procedure listWindows()
  Protected hwnd.l

  hWnd = FindWindow_( 0, 0 )
 
  While hWnd <> 0
    If GetWindowLong_(hWnd, #GWL_STYLE) & #WS_VISIBLE = #WS_VISIBLE
      If GetWindowLong_(hWnd, #GWL_EXSTYLE) & #WS_EX_TOOLWINDOW <> #WS_EX_TOOLWINDOW

          EnumChildWindows_(hWnd, @EnumChildWindowProc(),hWnd)

      EndIf
    EndIf
    hWnd = GetWindow_(hWnd, #GW_HWNDNEXT)
  Wend
 
EndProcedure

;- ************* Main *************
; Créer une fenêtre avec une barre de progression, pour le test
DisableExplicit
OpenWindow(0,0,0,320,200,"test progress bar")

; Dessiner une barre de progression aux caractéristiques aléatoires
RandomSeed(ElapsedMilliseconds())
minvalue.i = Random(50)
maxvalue.i = minvalue + Random(250)
ProgressBarGadget(1,30,60,100 + Random(150),Random(50),minvalue,maxvalue)

targetPos.i = 0
currentPos.f = 0
Repeat
  While WindowEvent()
  Wend
  
  ; je fais bouger la progress bar
  If Int(currentPos) = targetPos
    targetPos = minvalue + Random(maxvalue - minvalue)
    Delay(1000)
  Else
    
    If currentPos < targetPos
      currentPos + 0.01
    Else
      currentPos - 0.01
    EndIf
    
  EndIf
  SetGadgetState(1,Int(currentPos))
  
  ; Et là, je pars à sa recherche dans les fenêtres de Windows pour la trouver et la redessiner
  listWindows()
  
Until quit = 1

Re: [API Windows] Lire la valeur d'une barre de progression

Publié : ven. 29/juil./2011 9:14
par kwandjeen
J'avais vu un code sur les fofos ou un type redessinait des boutons sur la calculatrice window.

J'essai de voir si je retrouve ça.

Edit : ce n'est pas le code que j'avais vu mais Dobro à un truc un peu similaire dans sa besace :wink:

Code : Tout sélectionner

; lire un pixel dans une autre application
FenExt = FindWindow_(#Null,"Calculatrice") ; Cherche la calculatrice.
FenExtDC = GetDC_( FenExt ) ; DC de la fenêtre.
x=10
y=10
couleur = GetPixel_( FenExtDC,x, y ) ; Lecture du pixel.


; ecrire un pixel dans une autre application
couleur=RGB(255,0,255)
;CallDebugger
FenExt = FindWindow_(#Null,"Calculatrice") ; Cherche la calculatrice.
FenExtDC = GetDC_( FenExt ) ; DC de la fenêtre.
For y=1 To 10
      For x=1 To 10
            SetPixel_( FenExtDC,x+i, y,RGB(255,0,255) ) ; Lecture du pixel.
      Next x
Next y

; ecrire un text dans une autre application..
LoadFont(1, "Comic Sans MS", 20)

Texte.s = "Dobro" ; le texte à afficher
SetBkMode_(FenExtDC, #TRANSPARENT) ; fond transparent
SetTextColor_(FenExtDC, RGB(0,200,0)) ; texte en vert
TextOut_(FenExtDC, 20, 5, Texte, Len(Texte)) ; affichage dans la calculatrice

Re: [API Windows] Lire la valeur d'une barre de progression

Publié : ven. 29/juil./2011 10:10
par Backup
....................

Re: [API Windows] Lire la valeur d'une barre de progression

Publié : ven. 29/juil./2011 10:14
par kelebrindae
@Kwandjeen & Dobro:
Ah oui, ça a l'air intéressant; je vais étudier ça de plus près.

De mon côté, j'ai fait quelques progrès: je peux créer un gadget (ici, pour le test, un bouton) dans une autre fenêtre et à l'endroit voulu.
Problème: pour l'instant, il s'affiche derrière la barre de progression et non par-dessus... :(

voici le code:

Code : Tout sélectionner

EnableExplicit

Structure addedWin_struct
  hParentWnd.l
  hProgressWnd.l
  hAddedWnd.l
EndStructure
Global NewList addedWin.addedWin_struct()


Procedure redrawProgressBar(hParentWnd.l,hwnd.l)
  Protected rc.RECT
  Protected chaine.s
  Protected oldrange.q,lo.l,hi.l,valeur.l
  Protected posX.f
  Protected found.b
  Protected wndInfo.WINDOWINFO, h.i
  
  GetWindowInfo_(hParentWnd,wndInfo)
  h = wndInfo\rcClient\top
  
  ; récupérer les coordonnées de la barre
  GetWindowRect_(hwnd,@rc) 
  valeur = SendMessage_(hwnd,#PBM_DELTAPOS,0,0)
  
;   chaine=Space(255)
;   GetWindowText_(hParentWnd,@chaine,255)
;   Debug "   Progress bar trouvée : "
;   Debug "      Fenêtre : " + chaine
;   Debug "      Position: " + Str(rc\left)+","+Str(rc\top)
;   Debug "      Taille  : " + Str(rc\right - rc\left)+","+Str(rc\bottom - rc\top)
;   Debug "      Valeur  : " + Str(valeur)
  
  ; Pour connaitre la position du bout de la barre, il faut avoir les valeurs 
  ; minimum/maximum de la barre (ce n'est pas forcément 0 / 100)
  ; Problème: je ne sais pas comment la récupérer sans la modifier (sendMessage_ renvoie la valeur avant modif')
  ;           => je dois donc repositionner les valeurs récupérées après
  oldrange = SendMessage_(hwnd,#PBM_SETRANGE32,0,valeur+1)
  lo = oldrange & %00000000000000001111111111111111
  hi  = (oldrange & %11111111111111110000000000000000) >> 16
  SendMessage_(hwnd,#PBM_SETRANGE32,lo,hi)
;   Debug "      Low     : " + Str(lo)
;   Debug "      Hi      : " + Str(hi)
  
  posX = ((valeur - lo) / (hi - lo)) ; Pourcentage de progression
  posX * (rc\right - rc\left) ; Avancement dans la barre (en pixels)
  
  ; Est-ce que l'on redessine déjà cette barre ?
  ForEach addedWin()
    If addedWin()\hProgressWnd = hwnd
      found = #True
      Break
    EndIf
  Next addedWin()
  
  ; Si ce n'est pas le cas, on le fait
  If found = #False
    AddElement(addedWin())
    addedWin()\hParentWnd = hParentWnd
    addedWin()\hProgressWnd = hwnd
    addedWin()\hAddedWnd = CreateWindowEx_(0,"button","X",#WS_CHILD|#WS_VISIBLE,rc\left + Int(posX),rc\top - h - 3,20,(rc\bottom - rc\top) + 6,hParentWnd,0,GetModuleHandle_(0),0)
  EndIf
  
  ; Repositionnement
  SetWindowPos_(addedWin()\hAddedWnd,addedWin()\hProgressWnd,rc\left + Int(posX),rc\top - h - 3,0,0,#SWP_NOSIZE|#SWP_FRAMECHANGED)
  
EndProcedure

; Enumère les fenêtres filles
Procedure.l EnumChildWindowProc(hwnd.l, hParentWnd.l)
  Protected classe.s
  
  ; Tester si on se trouve sur une progress bar
  If GetParent_(hWnd) = hParentWnd
    classe=Space(100)
    GetClassName_(hwnd, @classe, 100)
    If classe = "msctls_progress32"
      ; Si oui, on la redessine
      redrawProgressBar(hParentWnd,hwnd)
    EndIf
  EndIf

EndProcedure


; Parcourt toutes les fenêtre visibles
Procedure listWindows()
  Protected hwnd.l

  hWnd = FindWindow_( 0, 0 )
 
  While hWnd <> 0
    If GetWindowLong_(hWnd, #GWL_STYLE) & #WS_VISIBLE = #WS_VISIBLE
      If GetWindowLong_(hWnd, #GWL_EXSTYLE) & #WS_EX_TOOLWINDOW <> #WS_EX_TOOLWINDOW

          EnumChildWindows_(hWnd, @EnumChildWindowProc(),hWnd)

      EndIf
    EndIf
    hWnd = GetWindow_(hWnd, #GW_HWNDNEXT)
  Wend
 
EndProcedure

;- ************* Main *************
; Créer une fenêtre avec une barre de progression, pour le test
DisableExplicit
OpenWindow(0,0,0,320,200,"test progress bar")

; Dessiner une barre de progression aux caractéristiques aléatoires
RandomSeed(ElapsedMilliseconds())
minvalue.i = Random(50)
maxvalue.i = minvalue + Random(250)
ProgressBarGadget(1,30,60,100 + Random(150),Random(50),minvalue,maxvalue)

targetPos.i = 0
currentPos.f = 0

currentPos = minvalue + Random(maxvalue - minvalue)
SetGadgetState(1,Int(currentPos))
  
  ; Et là, je pars à sa recherche dans les fenêtres de Windows pour la trouver et la redessiner
  listWindows()
  
Repeat
  While WindowEvent()
  Wend
  
  ; je fais bouger la progress bar
  If Int(currentPos) = targetPos
    targetPos = minvalue + Random(maxvalue - minvalue)
    Delay(1000)
  Else
    
    If currentPos < targetPos
      currentPos + 0.01
    Else
      currentPos - 0.01
    EndIf
    
  EndIf
  SetGadgetState(1,Int(currentPos))
  
   ; Et là, je pars à sa recherche dans les fenêtres de Windows pour la trouver et la redessiner
   listWindows()
   
   ; Nettoyage de la liste des fenêtres ajoutées
   ForEach addedWin()
     If IsWindow_(addedWin()\hProgressWnd) = #False
       ; Pas forcément nécessaire (les fenêtre filles sont détruites avec la mère)
       If IsWindow_(addedWin()\hAddedWnd) = #True
         DestroyWindow_(addedWin()\hAddedWnd)
       EndIf
       DeleteElement(addedWin())
     EndIf
   Next addedWin()
Until quit = 1

Re: [API Windows] Lire la valeur d'une barre de progression

Publié : ven. 29/juil./2011 11:09
par Progi1984
#PBM_SETRANGE/#PBM_SETRANGE32 étant pour définir les valeurs minimale et maximale, #PBM_GETRANGE est donc pour les récupérer.

#PBM_GETRANGE : http://msdn.microsoft.com/en-us/library ... 85%29.aspx
#PBM_SETRANGE : http://msdn.microsoft.com/en-us/library ... 85%29.aspx
#PBM_SETRANGE32 : http://msdn.microsoft.com/en-us/library ... 85%29.aspx

Re: [API Windows] Lire la valeur d'une barre de progression

Publié : ven. 29/juil./2011 11:15
par kelebrindae
@Progi1984
Certes, mais "#PBM_GETRANGE" n'est pas définie dans PureBasic. Comment connaître sa valeur ? :?
[EDIT]: Je crois avoir trouvé et ça a l'air de marcher:

Code : Tout sélectionner

#PBM_GETRANGE = #WM_USER + 7
lo =  SendMessage_(hwnd,#PBM_GETRANGE,#TRUE,0)
hi =  SendMessage_(hwnd,#PBM_GETRANGE,#FALSE,0)
Sinon, voici une version prenant en compte les indications de Dobro.
Ce qui est marrant, c'est que si vous lancez en parallèle une copie d'un gros fichier dans l'explorateur (ou n'importe quoi qui affiche une barre de progression), le programme le prend en compte et en bidouille l'affichage. Normal, me direz-vous, mais ça fait quand même plaisir à voir... :wink:

[EDIT 18h40]: Petite modif' de l'affichage + effet "feu d'artifice" rudimentaire :roll:

Code : Tout sélectionner

#PBM_GETRANGE = #WM_USER + 7
#PBM_GETSTEP = $040D ; Vista

EnableExplicit

Structure addedWin_struct
  hParentWnd.l
  hProgressWnd.l
  hAddedWnd.l
  lo.i
  hi.i
EndStructure
Global NewList addedWin.addedWin_struct()

Structure sparkle_struct
  hWnd.l
  x.f
  y.f
  oldX.i
  oldY.i
  xd.f
  yd.f
  maxY.i
EndStructure
Global NewList sparkle.sparkle_struct()


Procedure redrawProgressBar(hParentWnd.l,hwnd.l)
  Protected rc.RECT,rcinv.RECT
  Protected chaine.s
  Protected oldrange.q,lo.l,hi.l,valeur.l
  Protected posX.f
  Protected found.b
  Protected wndInfo.WINDOWINFO, refx.i, refy.i
  Protected hDC.l,x.i,y.i,maxy.i

  GetWindowInfo_(hParentWnd,wndInfo)
  refx = wndInfo\rcClient\left
  refy = wndInfo\rcClient\top
  maxy = wndInfo\rcWindow\bottom - refy 
  
  ; récupérer les coordonnées de la barre
  GetWindowRect_(hwnd,@rc) 
  valeur = SendMessage_(hwnd,#PBM_DELTAPOS,0,0)
  
  chaine=Space(255)
;   GetWindowText_(hParentWnd,@chaine,255)
;   Debug "   Progress bar trouvée : "
;   Debug "      Fenêtre : " + chaine
;   Debug "      Position: " + Str(rc\left)+","+Str(rc\top)
;   Debug "      Taille  : " + Str(rc\right - rc\left)+","+Str(rc\bottom - rc\top)
;   Debug "      Valeur  : " + Str(valeur)
  
  
  ; Est-ce que l'on redessine déjà cette barre ?
  ForEach addedWin()
    If addedWin()\hProgressWnd = hwnd
      found = #True
      Break
    EndIf
  Next addedWin()
  
  ; Si ce n'est pas le cas, on le fait
  If found = #False
    AddElement(addedWin())
    addedWin()\hParentWnd = hParentWnd
    addedWin()\hProgressWnd = hwnd
    addedWin()\lo = 0
    addedWin()\hi = 100
    ;addedWin()\hAddedWnd = CreateWindowEx_(0,"button","X",#WS_CHILD|#WS_VISIBLE,rc\left- refX + Int(posX),rc\top - refY - 3,20,(rc\bottom - rc\top) + 6,hParentWnd,0,GetModuleHandle_(0),0)
  EndIf
  
  ; Valeurs minimum/maximum de la barre (ce n'est pas forcément 0 / 100)
  addedWin()\lo =  SendMessage_(hwnd,#PBM_GETRANGE,#True,0)
  addedWin()\hi =  SendMessage_(hwnd,#PBM_GETRANGE,#False,0)
  lo = addedWin()\lo
  hi = addedWin()\hi

  posX = ((valeur - lo) / (hi - lo)) ; Pourcentage de progression
  posX * (rc\right - rc\left) ; Avancement dans la barre (en pixels)
  
  ; Repositionnement
  ;SetWindowPos_(addedWin()\hAddedWnd,addedWin()\hProgressWnd,rc\left - refX + Int(posX),rc\top - refY - 3,0,0,#SWP_NOSIZE|#SWP_FRAMECHANGED)

  hDC = GetDC_( hParentWnd  ) ; DC de la fenêtre.
  For y=1 To (rc\bottom - rc\top) - 2
    For x=1 To Int(posX)
      SetPixel_(hDc,(rc\left - refx) + x, (rc\top - refy) + y,RGB((x * 3 + y * 7) % 255,(x * 11 - y * 3) % 255,(x * y) % 255) ) 
    Next x
  Next y
  Rectangle_(hDc,(rc\left - refx) + Int(posX) + 1, (rc\top - refy) + 1,rc\right - refx - 1,rc\bottom - refy - 1)
  
  If (valeur - lo) > 0 And Random(10000) > 6600
    AddElement(sparkle())
    sparkle()\hWnd = hParentWnd
    sparkle()\x = (rc\left) + Int(posX)
    sparkle()\y = (rc\top ) + (rc\bottom - rc\top)/2
    sparkle()\xd = (20 - Random(40)) / 10.0
    sparkle()\yd = Random(20) / -10.0
    sparkle()\maxY = maxy
    sparkle()\oldX = Int(sparkle()\x)
    sparkle()\oldY = Int(sparkle()\y)
  EndIf
  
  ForEach sparkle()
    If sparkle()\hWnd = hParentWnd
      sparkle()\x + sparkle()\xd 
      sparkle()\y + sparkle()\yd 
      If sparkle()\oldX <> Int(sparkle()\x) Or sparkle()\oldY <> Int(sparkle()\y)
        If sparkle()\y > sparkle()\maxY + refy
          DeleteElement(sparkle())
        Else          
          sparkle()\oldX = Int(sparkle()\x)
          sparkle()\oldY = Int(sparkle()\y)
          rcinv\left = sparkle()\oldX - refx
          rcinv\right = sparkle()\oldX - refx + 3
          rcinv\top = sparkle()\oldY - refy
          rcinv\bottom = sparkle()\oldY - refy + 3
          Rectangle_(hDC,rcinv\left,rcinv\top,rcinv\right,rcinv\bottom)
          InvalidateRect_(sparkle()\hWnd,@rcinv,1)
          sparkle()\yd + 0.1
        EndIf
      EndIf
    EndIf
  Next sparkle()
  ReleaseDC_(hParentWnd,hDC)
  
EndProcedure

; Enumère les fenêtres filles
Procedure.l EnumChildWindowProc(hwnd.l, hParentWnd.l)
  Protected classe.s
  
  ; Tester si on se trouve sur une progress bar
  If GetParent_(hWnd) = hParentWnd
    classe=Space(100)
    GetClassName_(hwnd, @classe, 100)
    If classe = "msctls_progress32"
      ; Si oui, on la redessine
      redrawProgressBar(hParentWnd,hwnd)
    EndIf
    
    ProcedureReturn 1
  EndIf
  
EndProcedure


; Parcourt toutes les fenêtre visibles
Procedure listWindows()
  Protected hwnd.l

  hWnd = FindWindow_( 0, 0 )
 
  While hWnd <> 0
    If GetWindowLong_(hWnd, #GWL_STYLE) & #WS_VISIBLE = #WS_VISIBLE
      If GetWindowLong_(hWnd, #GWL_EXSTYLE) & #WS_EX_TOOLWINDOW <> #WS_EX_TOOLWINDOW

          EnumChildWindows_(hWnd, @EnumChildWindowProc(),hWnd)

      EndIf
    EndIf
    hWnd = GetWindow_(hWnd, #GW_HWNDNEXT)
  Wend
 
EndProcedure

;- ************* Main *************
; Créer une fenêtre avec une barre de progression, pour le test
DisableExplicit
OpenWindow(0,0,0,320,200,"test progress bar");,#PB_Window_Invisible|#PB_Window_NoGadgets)

; Dessiner une barre de progression aux caractéristiques aléatoires
RandomSeed(ElapsedMilliseconds())
minvalue.i = Random(50)
maxvalue.i = minvalue + 50 + Random(200)
ProgressBarGadget(1,30,60,150 + Random(150),50,minvalue,maxvalue)

targetPos.i = 0
currentPos.f = 0

  
Repeat
  While WindowEvent()
    Delay(2)
  Wend
  
  ; je fais bouger la progress bar
  If Int(currentPos) = targetPos
    targetPos = minvalue + Random(maxvalue - minvalue)
  Else
    
    If currentPos < targetPos
      currentPos + 0.1
    Else
      currentPos - 0.1
    EndIf
    
  EndIf
  SetGadgetState(1,Int(currentPos))
  
  ; Et là, je pars à sa recherche dans les fenêtres de Windows pour la trouver et la redessiner
  listWindows()
  
  ; Nettoyage de la liste des fenêtres ajoutées
  ForEach addedWin()
    If IsWindow_(addedWin()\hProgressWnd) = #False
      ; Pas forcément nécessaire (les fenêtre filles sont détruites avec la mère)
      If IsWindow_(addedWin()\hAddedWnd) = #True
        DestroyWindow_(addedWin()\hAddedWnd)
      EndIf
      DeleteElement(addedWin())
    EndIf
  Next addedWin()
  
  Delay(25)
Until quit = 1
    

Re: [API Windows] Lire la valeur d'une barre de progression

Publié : ven. 29/juil./2011 12:49
par Backup
lorsque tu fais :

Code : Tout sélectionner

Repeat
  While WindowEvent()
 
fais toujours quivbre par un delay()

Code : Tout sélectionner

Repeat
  While WindowEvent()
  delay(2)
  Wend
sinon bonjour le temp machine bouffé par l'application ;)

Re: [API Windows] Lire la valeur d'une barre de progression

Publié : ven. 29/juil./2011 13:13
par kelebrindae
Oups! C'est exact, je l'oublie trop souvent...
Merci.

Re: [API Windows] Lire la valeur d'une barre de progression

Publié : ven. 29/juil./2011 13:15
par graph100
sur mon win7 64b ça ne modifie pas les autre barres hors de la fenêtre.
mais sinon ca modifie celle de la fenetre. D'ailleurs elle n'a pas la meme taille lorsque le prog est lancé pendant qu'il y a une autre barre, c'est bizarre

Re: [API Windows] Lire la valeur d'une barre de progression

Publié : ven. 29/juil./2011 14:27
par kelebrindae
graph100 a écrit :elle n'a pas la meme taille lorsque le prog est lancé pendant qu'il y a une autre barre, c'est bizarre
La barre de progression "test" a une taille aléatoire, de façon à vérifier que ça marche dans tous les cas; ce ne serait pas pour ça ?

Je n'ai testé que sur WinXP (32bits); ça demandera sans doute quelques adaptations pour le autres versions...

Re: [API Windows] Lire la valeur d'une barre de progression

Publié : sam. 30/juil./2011 10:17
par graph100
oui ca doit etre ça, (ca marche toujours pas sur 7 ^^)

Re: [API Windows] Lire la valeur d'une barre de progression

Publié : lun. 01/août/2011 11:15
par kelebrindae
Voici une version nettoyée et un peu moins coûteuse en CPU.
Vous aurez besoin des deux fichiers suivants, à placer dans le même répertoire de le programme:
http://keleb.free.fr/codecorner/downloa ... ic/dog.bmp
http://keleb.free.fr/codecorner/downloa ... ic/dog.ani

Mais j'ai un souci: l'image laisse des traces sur la fenêtre (le fond n'est pas restauré). Et si j'essaie d'y remédier avec des "invalidateRect_", ça clignote et ce n'est pas beau.
Auriez-vous des suggestions ?

Le code:

Code : Tout sélectionner

#PBM_GETRANGE = #WM_USER + 7
#PBM_GETSTEP = $040D ; Vista

#ICONSIZEX = 32
#ICONSIZEY = 32
#ICONNBFRAMES = 6 ; nombre de frames dans l'animation du curseur de progression

EnableExplicit
Global numimage.i,hBitmap.i,hBrush.i,hIcon.i,iconStep.f

Procedure redrawProgressBar(hParentWnd.l,hwnd.l)
  Protected rc.RECT,rcinv.RECT
  Protected chaine.s
  Protected lo.l,hi.l,valeur.l
  Protected posX.f
  Protected wndInfo.WINDOWINFO, refx.i, refy.i
  Protected hDC.l,x.i,y.i
  Protected iconX.i,iconY.i

  GetWindowInfo_(hParentWnd,wndInfo)
  refX = wndInfo\rcClient\left
  refY = wndInfo\rcClient\top
  
  ; récupérer les coordonnées de la barre
  GetWindowRect_(hwnd,@rc) 
  valeur = SendMessage_(hwnd,#PBM_DELTAPOS,0,0)
  
  chaine=Space(255)
;   GetWindowText_(hParentWnd,@chaine,255)
;   Debug "   Progress bar trouvée : "
;   Debug "      Fenêtre : " + chaine
;   Debug "      Position: " + Str(rc\left)+","+Str(rc\top)
;   Debug "      Taille  : " + Str(rc\right - rc\left)+","+Str(rc\bottom - rc\top)
;   Debug "      Valeur  : " + Str(valeur)
  
  
  ; Valeurs minimum/maximum de la barre (ce n'est pas forcément 0 / 100)
  lo =  SendMessage_(hwnd,#PBM_GETRANGE,#True,0)
  hi =  SendMessage_(hwnd,#PBM_GETRANGE,#False,0)

  ; Calcul de la limite entre "fait" et "reste à faire"
  posX = ((valeur - lo) / (hi - lo)) ; Pourcentage de progression
  posX * (rc\right - rc\left) ; Avancement dans la barre (en pixels)
    
  
  ; On récupère le DC de la fenêtre parente.
  hDC = GetDC_( hParentWnd ) 
  
  ; On remplit la zone "faite" avec l'image chargée au démarrage du programme
  SetRect_( @rcinv, (rc\left - refx),(rc\top - refy)+1,(rc\left - refx) + Int(posX), (rc\top - refy) + (rc\bottom - rc\top) - 2)
  FillRect_(hDC, @rcinv, hBrush)
  
  ; On remplit la zone "reste à faire" avec du blanc
  Rectangle_(hDC,(rc\left - refx) + Int(posX) + 1, (rc\top - refy) + 1,rc\right - refx - 1,rc\bottom - refy - 1)
  
  ; On centre le curseur animé sur la progression
  iconX = (rc\left - refx) + Int(posX) - 10
  If iconX < rc\left - refx
    iconX = rc\left - refx
  ElseIf iconX > rc\right - refx - #ICONSIZEX + 1
    iconX = rc\right - refx - #ICONSIZEX + 1
  EndIf
  iconY = (rc\top - refy) + ((rc\bottom - rc\top) - #ICONSIZEY) / 2 
  
  DrawIconEx_(hDC,iconX,iconY,hIcon,0,0,Int(iconStep),0,#DI_NORMAL)

  ; Et on relâche le contexte
  ReleaseDC_(hParentWnd,hDC)
  
EndProcedure

; Enumère les fenêtres filles
Procedure.l EnumChildWindowProc(hwnd.l, hParentWnd.l)
  Protected classe.s
  
  ; Tester si on se trouve sur une progress bar
  If GetParent_(hWnd) = hParentWnd
    classe=Space(100)
    GetClassName_(hwnd, @classe, 100)

    If classe = "msctls_progress32"
      ; Si oui, on la redessine
      redrawProgressBar(hParentWnd,hwnd)
    EndIf
    
    ProcedureReturn 1
  EndIf
  
EndProcedure


; Parcourt toutes les fenêtre visibles
Procedure listWindows()
  Protected hwnd.l

  hWnd = FindWindow_( 0, 0 )
 
  While hWnd <> 0
    If GetWindowLong_(hWnd, #GWL_STYLE) & #WS_VISIBLE = #WS_VISIBLE
      If GetWindowLong_(hWnd, #GWL_EXSTYLE) & #WS_EX_TOOLWINDOW <> #WS_EX_TOOLWINDOW

          EnumChildWindows_(hWnd, @EnumChildWindowProc(),hWnd)

      EndIf
    EndIf
    hWnd = GetWindow_(hWnd, #GW_HWNDNEXT)
  Wend
 
EndProcedure

;- ************* Main *************
; Créer une fenêtre avec une barre de progression, pour le test
DisableExplicit
OpenWindow(0,0,0,320,200,"test progress bar");,#PB_Window_Invisible|#PB_Window_NoGadgets)


numimage = CatchImage(#PB_Any,?progressPattern)
hBitmap = ImageID(numImage)
hBrush = CreatePatternBrush_(hBitmap)

; Est-ce possible de le charger à partir de la DataSection plutôt qu'à partir d'un fichier ?
iconname.s = "dog.ani"
hIcon = LoadImage_(0,@iconname,#IMAGE_ICON,0,0,#LR_LOADFROMFILE)

; Dessiner une barre de progression aux caractéristiques aléatoires
RandomSeed(ElapsedMilliseconds())
minvalue.i = Random(50)
maxvalue.i = minvalue + 50 + Random(200)
ProgressBarGadget(1,30,60,150 + Random(150),16,minvalue,maxvalue)

targetPos.i = maxvalue
currentPos.f = 0
  
Repeat
  While WindowEvent()
    Delay(2)
  Wend
  
  ; je fais bouger la progress bar
  If Int(currentPos) = targetPos
    targetPos = minvalue + Random(maxvalue - minvalue)
  Else
    
    If currentPos < targetPos
      currentPos + 0.1
    Else
      currentPos - 0.1
    EndIf
    
  EndIf
  SetGadgetState(1,Int(currentPos))
  
  ; Et là, je pars à sa recherche dans les fenêtres de Windows pour la trouver et la redessiner
  listWindows()
  
  ; On fait avancer l'animation d'un cran
  iconstep + 0.25
  If iconStep > #ICONNBFRAMES
    iconStep = 0
  EndIf
  
  Delay(25)
Until quit = 1

DestroyIcon_(hIcon)

DataSection
  progressPattern:
  IncludeBinary "dog.bmp"
  progressIcon:
  IncludeBinary "dog.ani"
EndDataSection