begin process at 2008 09 06 20:09:52
1 237 931 membres
313 nouveaux aujourd'hui
14 314 membres club

Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum.
Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

TUTO : TECHNIQUE POUR ATTENDRE


Information sur la source

Catégorie :Date & Heure Classé sous : méthode, attendre, sleep, doevents, boucle Niveau : Débutant Date de création : 13/03/2004 Date de mise à jour : 13/03/2004 15:36:17 Vu : 10 018

Note :
10 / 10 - par 1 personne
10,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (20)
Ajouter un commentaire et/ou une note


Description

Simples recommendations pour faire des boucles d'attente.
Dans ces exemples, on va attendre 5 secondes, mais cela marche pour des valeurs beaucoup plus grandes (par contre pas utilisable en dessous de la seconde).

Technique 1 (avec bug possible) :
---------------------------------------
La technique consiste à utiliser l'instruction (pas l'objet) Timer.
Cette instruction renvoie le nombre de secondes écoulées depuis minuit.
Dim Debut As Long
Debut = Timer
Do While Timer - Debut < 5
DoEvents  ' Repasse la main au système en attendant
Loop

Cette technique a un gros inconvénient : à minuit, Timer repasse à zéro : Si vous faites votre boucle vers cette heure là, vous risquez d'attendre longtemps.

Technique 2 (sans bug) :
-----------------------------
Là, on va utiliser la date système pour faire l'attente :

Dim Debut As Date
Debut = Now  ' renvoie la date et l'heure courante
Do While Abs(DateDiff("s", MaDate, Now)) < 5
DoEvents  ' Repasse la main au système en attendant
Loop

Cette solution a le gros avantage d'être fiable, et de pouvoir attendre des durées quelconques : Il suffit re remplacer "s" (secondes) par une des autres unités de temps :
s  Secondes
n  Minutes (et pas m)
h  Heures
d  Jours
m  Mois
y  Années

Dernière précision :
----------------------
Les puriistes vous dirons que utiliser un DoEvents mange du temps machine; en effet, la boucle est exécutée quelques milliers de fois par secondes.
Certes (y cause bien, hein !), vous pouvez toujours la remplacer la l'API "Sleep" :
Vous mettez cette déclaration dans la partie Déclaration de votre feuille ou module
Declare Sub Sleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)
et vous remplacez les "DoEvents" par des "Sleep 1000" qui demandera au système d'attendre 1 seconde (1000 millisecondes) avant de poursuivre.

Vala. En espérant que ça puisse vous servir ...
Jack
  • signaler à un administrateur
    Commentaire de Renfield le 13/03/2004 06:57:39 administrateur CS

    Sleep semble en effet bien indiquée.....

    (bonne idée de tuto...)

  • signaler à un administrateur
    Commentaire de Afyn le 14/03/2004 09:53:23

    Bien expliqué.
    Un petit bout de code en exemple pourrait être bien venu
    également

    A+
    Afyn

  • signaler à un administrateur
    Commentaire de Afyn le 14/03/2004 09:56:31

    Ha, oui ...
    Si quelqu'un sait ce que fait réellement le DoEvents (décompilé
    par exe ...) je serais curieux de savoir.

    Re A+
    Afyn

  • signaler à un administrateur
    Commentaire de Xya le 14/03/2004 15:22:32

    J'ai J'ai exécuté dans un débogueur un petit programme VB qui appelle DoEvents et voilà la procédure:

    [MSVBVM60.rtcDoEvents]

    73397BA3 &gt; 56               PUSH ESI
    73397BA4   57               PUSH EDI
    73397BA5   E8 33000000      CALL MSVBVM60.73397BDD
    73397BAA   8BF0             MOV ESI,EAX
    73397BAC   33FF             XOR EDI,EDI
    73397BAE   83FE FF          CMP ESI,-1
    73397BB1   0F84 10BA0100    JE MSVBVM60.733B35C7
    73397BB7   393D 30034873    CMP DWORD PTR DS:[73480330],EDI
    73397BBD   0F85 F8B90100    JNZ MSVBVM60.733B35BB
    73397BC3   A1 38034873      MOV EAX,DWORD PTR DS:[73480338]
    73397BC8   3BC7             CMP EAX,EDI
    73397BCA   0F85 08BA0100    JNZ MSVBVM60.733B35D8
    73397BD0   57               PUSH EDI
    73397BD1   FF15 EC113773    CALL DWORD PTR DS:[&lt;&KERNEL32.Sleep&gt;]    ; kernel32.Sleep
    73397BD7   66:8BC6          MOV AX,SI
    73397BDA   5F               POP EDI
    73397BDB   5E               POP ESI
    73397BDC   C3               RETN

    et quelques appels significatifs aux APIs en vrac:

    733848DD   8B3D 28143773    MOV EDI,DWORD PTR DS:[&lt;&USER32.PeekMessageA&gt;]      ; USER32.PeekMessageA

    7338494C   FF15 2C133773    CALL DWORD PTR DS:[&lt;&USER32.TranslateMessage&gt;]     ; USER32.TranslateMessage

    73384956   FF15 30133773    CALL DWORD PTR DS:[&lt;&USER32.DispatchMessageA&gt;]     ; USER32.DispatchMessageA

    73385BA2   FF15 28153773    CALL DWORD PTR DS:[&lt;&USER32.GetWindowLongA&gt;]       ; USER32.GetWindowLongA

    73385BE6   8B3D 94143773    MOV EDI,DWORD PTR DS:[&lt;&USER32.SendMessageA&gt;]      ; USER32.SendMessageA

    Le peu que j'en ai compris, c'est que DoEvents appellerait PeekMessage pour voir s'il y a des messages en attente pour la fenêtre, et s'il y en a les exécute (TranslateMessage, DispatchMessage). Sinon, il exécute Sleep.

    Si quelqu'un maîtrisant l'assembleur et la prog Windows voudrait bien démêler ca, peut être qu'on avancerait un peu :)


    Xya

  • signaler à un administrateur
    Commentaire de Xya le 14/03/2004 15:30:51

    Une autre précision: il semblerait que quand rtcDoEvents appelle Sleep, le paramètre passé soit toujours 0. D'après MSDN:

    VOID Sleep(
      DWORD dwMilliseconds
    );

    dwMilliseconds
        [in] Minimum time interval for which execution is to be suspended, in milliseconds.

        A value of zero causes the thread to relinquish the remainder of its time slice to any other thread of equal priority that is ready to run. If there are no other threads of equal priority ready to run, the function returns immediately, and the thread continues execution.

    Donc soit DoEvents s'occupe des messages en attente dans la file, soit s'il n'y en a pas arrête le thread en cours et laisse la main aux autres threads.


    Xya

  • signaler à un administrateur
    Commentaire de Renfield le 14/03/2004 15:54:55 administrateur CS

    Xya a tout décris me semble-t'il du fonctionnement de DoEvents....

  • signaler à un administrateur
    Commentaire de jack le 14/03/2004 18:24:43 administrateur CS

    Et beh, j'en demandais pas tant ...
    Ce qui me conforte dans l'utilisation de DoEvents qui n'est donc pas si maléfique que ça ...
    A propos de ces appels aux APIs, il y a eu récemment une brave discution dans ce lien (auteur Unreal) : http://www.vbfrance.com/code.aspx?ID=20535

  • signaler à un administrateur
    Commentaire de Renfield le 14/03/2004 20:39:00 administrateur CS

    "maléfique" ?? il est même plus qu'utile parfois !!

    evite par contre les

    for i = 0 to 9999999
       doevents
       'action
    next i

    pour privilégier par exemple :

    for i = 0 to 9999999
       if i mod 3000 = 0 then    doevents
       'action
    next i

  • signaler à un administrateur
    Commentaire de Xya le 15/03/2004 12:40:47

    Si ça interesse qqun, voilà le code IL de LocalModalMessageLoop, qui est appellée par la version .NET de DoEvents:

    Private Function LocalModalMessageLoop(ByVal form As Form) As Boolean

    .maxstack 5
    .locals (MSG V_0, Boolean V_1, Boolean V_2, Boolean V_3, Message V_4, Boolean V_5, Control V_6, Boolean V_7)
    .try L_0000 to L_0114 catch Object L_0114 to L_011a
    L_0000: ldloca.s V_0
    L_0002: initobj MSG
    L_0008: ldc.i4.0
    L_0009: stloc.1
    L_000a: ldc.i4.1
    L_000b: stloc.2
    L_000c: br L_0109
    L_0011: ldloca.s V_0
    L_0013: ldsfld NativeMethods.NullHandleRef
    L_0018: ldc.i4.0
    L_0019: ldc.i4.0
    L_001a: ldc.i4.0
    L_001b: call UnsafeNativeMethods.PeekMessage
    L_0020: stloc.3
    L_0021: ldloc.3
    L_0022: brfalse L_00f6
    L_0027: ldloc.2
    L_0028: brfalse L_0109
    L_002d: ldloca.s V_0
    L_002f: ldfld MSG.hwnd
    L_0034: ldsfld IntPtr.Zero
    L_0039: call IntPtr.op_Inequality
    L_003e: brfalse.s L_006b
    L_0040: ldnull
    L_0041: ldloca.s V_0
    L_0043: ldfld MSG.hwnd
    L_0048: newobj HandleRef..ctor
    L_004d: call SafeNativeMethods.IsWindowUnicode
    L_0052: brfalse.s L_006b
    L_0054: ldc.i4.1
    L_0055: stloc.1
    L_0056: ldloca.s V_0
    L_0058: ldsfld NativeMethods.NullHandleRef
    L_005d: ldc.i4.0
    L_005e: ldc.i4.0
    L_005f: call UnsafeNativeMethods.GetMessageW
    L_0064: brtrue.s L_0080
    L_0066: br L_0109
    L_006b: ldc.i4.0
    L_006c: stloc.1
    L_006d: ldloca.s V_0
    L_006f: ldsfld NativeMethods.NullHandleRef
    L_0074: ldc.i4.0
    L_0075: ldc.i4.0
    L_0076: call UnsafeNativeMethods.GetMessageA
    L_007b: brfalse L_0109
    L_0080: ldloca.s V_0
    L_0082: ldfld MSG.hwnd
    L_0087: ldloca.s V_0
    L_0089: ldfld MSG.message
    L_008e: ldloca.s V_0
    L_0090: ldfld MSG.wParam
    L_0095: ldloca.s V_0
    L_0097: ldfld MSG.lParam
    L_009c: call Message.Create
    L_00a1: stloc.s V_4
    L_00a3: ldc.i4.0
    L_00a4: stloc.s V_5
    L_00a6: ldloca.s V_0
    L_00a8: ldfld MSG.hwnd
    L_00ad: call Control.FromChildHandleInternal
    L_00b2: stloc.s V_6
    L_00b4: ldloc.s V_6
    L_00b6: brfalse.s L_00c6
    L_00b8: ldloc.s V_6
    L_00ba: ldloca.s V_4
    L_00bc: callvirt Control.PreProcessMessage
    L_00c1: brfalse.s L_00c6
    L_00c3: ldc.i4.1
    L_00c4: stloc.s V_5
    L_00c6: ldloc.s V_5
    L_00c8: brtrue.s L_00e7
    L_00ca: ldloca.s V_0
    L_00cc: call UnsafeNativeMethods.TranslateMessage
    L_00d1: pop
    L_00d2: ldloc.1
    L_00d3: brfalse.s L_00df
    L_00d5: ldloca.s V_0
    L_00d7: call UnsafeNativeMethods.DispatchMessageW
    L_00dc: pop
    L_00dd: br.s L_00e7
    L_00df: ldloca.s V_0
    L_00e1: call UnsafeNativeMethods.DispatchMessageA
    L_00e6: pop
    L_00e7: ldarg.1
    L_00e8: brfalse.s L_0109
    L_00ea: ldarg.1
    L_00eb: callvirt Form.CheckCloseDialog
    L_00f0: ldc.i4.0
    L_00f1: ceq
    L_00f3: stloc.2
    L_00f4: br.s L_0109
    L_00f6: ldarg.1
    L_00f7: brfalse.s L_010f
    L_00f9: ldc.i4.1
    L_00fa: ldc.i4.0
    L_00fb: ldc.i4.1
    L_00fc: ldc.i4.s 100
    L_00fe: ldc.i4 255
    L_0103: call UnsafeNativeMethods.MsgWaitForMultipleObjects
    L_0108: pop
    L_0109: ldloc.2
    L_010a: brtrue L_0011
    L_010f: ldloc.2
    L_0110: stloc.s V_7
    L_0112: leave.s L_011a
    L_0114: pop
    L_0115: ldc.i4.0
    L_0116: stloc.s V_7
    L_0118: leave.s L_011a
    L_011a: ldloc.s V_7
    L_011c: ret

    La version .NET semble faire la même chose que la version VB6: regarder s'il y a des messages en attente dans la file, en traiter un si oui et sinon attendre, là avec MsgWaitForMultipleObjects pendant 100ms.


    Xya

  • signaler à un administrateur
    Commentaire de Afyn le 15/03/2004 14:10:25

    Merci Xya pour ton "étude"...
    Je me doutais que DoEvents utilisait le système de message.
    (forcément ...)
    Ce qui reste flou dans Windows, c'est la façon dont les
    messages prennent la priorité.
    Et savoir si sleep ... rend la main immédiatement ou pas ?
    J'ai pas pour ma par réussi a mesurer, mais je pense
    sincérement qu'il rend la main immédiatement...
    C 'est cette "propriété"que j'ai exploité avec le WaitableTimer
    Et ki me semble la bonne voie... pour attendre sans consommer
    du CPU

    Encore merci a tous pour vos analyses

    Afyn
    Navedac
    Le savoir faire des cancres...

  • signaler à un administrateur
    Commentaire de Alain Proviste le 06/05/2004 00:17:56 administrateur CS

    http://www.calbay.com/doevents.htm

    zzz

    merci Xya pour ce ke tu as fait c interessant.

    Neanmoins une chose est sure, pour pouvoir conserver une maximum de "stabilité" sous windows sans trop perdre de performances sous ton soft est lutilisation d'un second thread ki doevents toutes les enièème de secondes.

  • signaler à un administrateur
    Commentaire de Alain Proviste le 06/05/2004 00:22:08 administrateur CS

    en attendant, pkoi le doevent il éxécute un sleep ? c'est une perte non ?

  • signaler à un administrateur
    Commentaire de Xya le 06/05/2004 14:10:39

    Une précision encore:
    Sleep, SleepEx, WaitForSingleOject(Ex), (Msg)WaitForMultipleOject(Ex) mettent le thread en cours en état d'attente et donc NE consomment PAS de CPU, le temps du CPU étant partagé entre tous les threads en cours d'exécution.

    (MSDN: The MsgWaitForMultipleObjects function determines whether the wait criteria have been met. If the criteria have not been met, the calling thread enters the wait state. It uses no processor time while waiting for the conditions of the wait criteria to be met. )

    A noter aussi qu'il vaut mieux ne pas utiliser Sleep(Ex) sur des threads qui s'occupent d'une fenêtre (ce qui est généralement le cas avec VB6) puisque comme le thread passe en attente il ne peut plus lire les messages qui lui arrivent, et la fenêtre reste figée.

    Xya

  • signaler à un administrateur
    Commentaire de Afyn le 06/05/2004 17:10:03

    Ca mériterait (pour celui ki aurait le courage) un petit schéma... et kelkes petits exemples pour appuyer toutes ces belles théories.

    Afyn

  • signaler à un administrateur
    Commentaire de legion91 le 11/08/2004 17:57:33

    timer repasse à 0 à minuit logik il est minuit essayez msgbox timer/3600.
    Ho!! mais c'est une heure decimal ;-)

  • signaler à un administrateur
    Commentaire de lolo31400 le 18/09/2006 19:56:05

    bonjour et en pascal une boucle d'attente vous la coderiez comment?

  • signaler à un administrateur
    Commentaire de 85bmx85 le 14/04/2008 16:14:08

    Bonjour, a tout hasard si quelqun tombe sur ceci :
    je suis en vb express (2008) et M.VB il est pas content car monsieur M.VB il conait pas abs donc tout betement :
    c'est quoi l'équivalent?

    Sinon rapport au tuto :
    pas mal du tout tres bonne idée  mais par contre il aurait fallu préciser que sleep ne fait pas juste une pause il stoppe le programme tout entier (plus aucune interaction) comme l'a dit Xya

  • signaler à un administrateur
    Commentaire de Renfield le 14/04/2008 16:30:53 administrateur CS

    Math.Abs  me semble

  • signaler à un administrateur
    Commentaire de 85bmx85 le 16/04/2008 18:52:53

    bonne réponse

  • signaler à un administrateur
    Commentaire de 85bmx85 le 16/04/2008 18:54:18

    tant qu'à faire je précise pour ce qui tournent aussi sous express que DoEvents devient Application.DoEvents
    a+

Ajouter un commentaire

Pub



Appels d'offres

CalendriCode

Septembre 2008
LMMJVSD
1234567
891011121314
15161718192021
22232425262728
2930     

Téléchargements

Boutique

Boutique de goodies CodeS-SourceS