IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Discussion :

Problème de timer dans une boucle GetMessage/DispatchMessage


Sujet :

Windows

  1. #1
    Membre éclairé
    Avatar de Captain'Flam
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2011
    Messages
    273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 273
    Billets dans le blog
    1
    Par défaut Problème de timer dans une boucle GetMessage/DispatchMessage
    Bonjour,

    voici un petit problème, dont je ne comprends pas l'origine avec SetTimer dans une boucle de gestion d'événements.

    Un petit bout de code valant mieux qu'un long discourt, voici un snipet sur mesure qui expose mon problème sans vous écraser sous une montagne de code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    #include <windows.h>
    #include <cstdio>
    #include <time.h>
    #include <sys/timeb.h>
    
    int get_time_ms () // juste pour avoir l'heure : pas le sujet de ce post... 
        {              // mais je laisse l'implémentation pour ceux qui veulent tester ce code
        struct timeb t ;
        ftime( &t ) ;
        static unsigned first_sec = 0 ; 
        static unsigned first_milli ; 
        if (!first_sec)
            {
            first_sec   = (unsigned)t.time ;
            first_milli = (unsigned)t.millitm ;
            return 0 ;
            }
        unsigned sec   = (unsigned)t.time ;
        unsigned milli = (unsigned)t.millitm ;
        return (sec-first_sec)*1000 + milli - first_milli ;
        }
    
    // bonne vieille callback à la sauce Win32
    LRESULT CALLBACK win_callback ( HWND hWnd , UINT message , WPARAM wParam , LPARAM lParam )
        {
        static int last = 0 ;
        int        now  = get_time_ms() ;
        switch ( message )
            {
            case WM_MOUSEMOVE :
                printf("+") ; // affiche un '+' sur la console à chaque fois qu'on bouge la souris
                break ;
    
            case WM_TIMER : // affiche l'heure et son delta à chaque événement timer
                printf("\n%d (%d) ",now,now-last ) ;
                last = now ;
                break ;
            }
        return DefWindowProc( hWnd,message,wParam,lParam ) ;
        }
    
    int main () // le main
        {
        WNDCLASSEX wcx ;
        memset( &wcx,0,sizeof( wcx )) ;
        wcx.cbSize        = sizeof( wcx ) ;
        wcx.lpfnWndProc   = win_callback ;
        wcx.lpszClassName = "spam" ;
        RegisterClassEx( &wcx ) ;
    
        HWND hwnd = CreateWindowEx( NULL,"spam",NULL,WS_POPUP,0,0,100,100,NULL,NULL,NULL,NULL ) ;
        ShowWindow( hwnd,TRUE ) ;
        SetFocus( hwnd ) ;        // créé une fenêtre (on ne la voit pas, mais on sait qu'elle est dans le coin haut-gauche de l'écran)
    
        MSG msg ;
        int timer = 0 ;
        for (;;)         // boucle de gestion des événements
            {
            if (GetMessage( &msg,hwnd,0,0 ))
                {
                TranslateMessage( &msg ) ;
                DispatchMessage( &msg ) ;
                }
            SetTimer( hwnd,timer,100,NULL ) ; // on "créé" un événement timer toutes les 100ms
            }
        return 0 ;
        }
    et une copie de ma sortie console :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    1860 (107)
    1972 (112)
    2081 (109)
    2189 (108)
    2300 (111)
    2407 (107) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    3439 (1032)
    3545 (106)
    3655 (110)
    3763 (108)
    3874 (111)
    Donc, voici l'histoire : je voudrais un événement timer toutes les 100ms, tout en gérant les autres événements au fur et à mesure qu'ils se produisent.

    Le soucis c'est que quand d'autres événements se produisent, ils "éclipsent" le timer.
    Comme on peut le voir sur la sortie console :
    - au début, tout va bien : j'ai un événement timer toutes les 100ms (à peu près)
    - puis je fais bouger ma souris dans le coin haut-gauche de l'écran (comme l'indiquent les '+') et là, pendant 1032ms je n'ai plus de timer
    - enfin j’arrête de bouger ma souris, et les timers reviennent au bon rythme.

    Vous aurez compris ma question : qu'est ce que je fais mal ?
    Comment conserver mon rythme de timer, même pendant que d'autres événements surviennent ?

    Merci d'avance !

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 397
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 397
    Par défaut
    C'est un problème connu, consistant de deux faits combinés:
    • Les message WM_TIMER ont priorité minimale
    • Les message WM_MOUSEMOVE sont générés "aussi vite que la fenêtre peut les traiter".

    Je ne vois pas trop d'échappatoire, à part d'utiliser autre chose que SetTimer(). Ou bien, SetTimer() sur un autre thread, dont la fenêtre serait invisible et enverrait/posterait des messages à priorité normale à ta fenêtre principale.

    PS: Je suis surpris que les messages WM_TIMER "en trop" soient "sautés" au lieu de s'accumuler. C'est bon à savoir.
    Edit: Ah, ils sont apparemment eux aussi générés à la demande.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre éclairé
    Avatar de Captain'Flam
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2011
    Messages
    273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 273
    Billets dans le blog
    1
    Par défaut
    Merci de ta réponse, même si elle ne me satisfait guère...

    Toutefois, qu'est-ce que tu entends par "ils sont apparemment eux aussi générés à la demande" ?
    C'est qui "ils" ? les WM_TIMER ?
    Le "aussi" fait-il référence aux WM_MOUSEMOVE ?
    A la demande de qui ?

    Re-merci

  4. #4
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 397
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 397
    Par défaut
    Par "à la demande", je veux dire que les messages WM_MOUSEMOVE, WM_PAINT, WM_TIMER et WM_QUIT sont en fait gérés en interne par des flags, et sont générés lors de l'appel à GetMessage() lorsqu'il n'y a pas de message plus urgent à retourner.
    Mais à l'inverse des trois autres, WM_MOUSEMOVE est considéré comme ayant une priorité normale ou haute, il me semble. Encore que. Dans tous les cas, il est prioritaire sur les trois autres (je les ai listés par ordre de priorité descendante, encore que je ne sois pas parfaitement sûr pour WM_QUIT).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Expert confirmé
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 540
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 540
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    for (;;)         // boucle de gestion des événements
            {
            if (GetMessage( &msg,hwnd,0,0 ))
                {
                TranslateMessage( &msg ) ;
                DispatchMessage( &msg ) ;
                }
            SetTimer( hwnd,timer,100,NULL ) ; // on "créé" un événement timer toutes les 100ms
            }

    c'est une très mauvaise méthode de programmation et totalement inutile !
    Tu recrées à chaque fois le même type de timer je n'arrive pas à comprendre la finalité de cette logique
    Citation Envoyé par Captain'Flam Voir le message
    ]Donc, voici l'histoire : je voudrais un événement timer toutes les 100ms, tout en gérant les autres événements au fur et à mesure qu'ils se produisent.
    il faut au besoin utiliser GetTickCount ou QueryPerfomanceCounter.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [SimpleXML] Google Maps, Problème d'encoding dans une boucle
    Par yahn dans le forum Bibliothèques et frameworks
    Réponses: 1
    Dernier message: 23/09/2006, 19h40
  2. Réponses: 2
    Dernier message: 28/08/2006, 13h16
  3. Problème de SCANF dans une boucle WHILE
    Par FidoDido® dans le forum C
    Réponses: 4
    Dernier message: 30/12/2005, 17h42
  4. [Conception] Problème de test dans une boucle while
    Par Cyrius dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 26/11/2005, 18h07
  5. Problème avec TNMSMTP dans une boucle.
    Par Orgied dans le forum Web & réseau
    Réponses: 3
    Dernier message: 07/04/2004, 10h19

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo