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

C++/CLI Discussion :

Fonction "atomique" en C++ ?


Sujet :

C++/CLI

  1. #1
    Membre chevronné Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 041
    Par défaut Fonction "atomique" en C++ ?
    Bonjour,

    Je suis confronté à un bug étrange

    J'ai une application graphique, qui dessine des rectangles de selection sur une image avec la technique bien connue NOT XOR PEN

    Le rectangle n'est pas assez visible.
    J'ai donc fait une petite modification pour en dessiner un plus épais :

    Le code original :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    					if (selektion_vorhanden>1) {
    						pDC->SetROP2(R2_NOTXORPEN);
    						pDC->Rectangle(&m_rect);
    					}
    					selektion_vorhanden = 1;
    					m_rect.top = y;
    					m_rect.left = x;
    Le code modifié :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    					if (selektion_vorhanden>1) {
    						pDC->SetROP2(R2_NOTXORPEN);
    						trace_rect_rect2(pDC); //pDC->Rectangle(&m_rect);
    					}
    					selektion_vorhanden = 1;
    					m_rect.top = y;
    					m_rect.left = x;
    J'ai remplacé partout les appels de

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    pDC->Rectangle(&m_rect);
    par

    qui est une fonction que j'ai créé dont voici le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void trace_rect_rect2(CDC* pDC) {
    	m_rect2.CopyRect(m_rect);
    	m_rect2.InflateRect(1, 1);
    	pDC->Rectangle(&m_rect);
    	pDC->Rectangle(&m_rect2);
    }
    Cette fonction est appelée par différentes procédures qui gèrent les évenements liés à la souris et à l'affichage :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void CShiftNView::OnDraw(CDC* pDC)
    void CShiftNView::OnLButtonDown(UINT nFlags, CPoint point) 
    void CShiftNView::OnMouseMove(UINT nFlags, CPoint point) 
    void CShiftNView::OnRButtonDown(UINT nFlags, CPoint point) 
    void CShiftNView::OnLButtonUp(UINT nFlags, CPoint point)
    void CShiftNView::OnRButtonUp(UINT nFlags, CPoint point)
    Le bug est le suivant : quand je manipule la souris un peu vite, les rectangles précédents se sont pas bien effacés :

    Nom : 2026_07_14_bug.jpg
Affichages : 163
Taille : 1,19 Mo

    Le bug ne se produit pas si je trace pas m_rect tout seul :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void trace_rect_rect2(CDC* pDC) {
    	m_rect2.CopyRect(m_rect);
    	m_rect2.InflateRect(1, 1);
    	pDC->Rectangle(&m_rect); // affichage correct sans bug
    	//pDC->Rectangle(&m_rect2);
    }
    mais le bug se produit aussi si je trace m_rect2 tout seul :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void trace_rect_rect2(CDC* pDC) {
    	m_rect2.CopyRect(m_rect);
    	m_rect2.InflateRect(1, 1);
    	//pDC->Rectangle(&m_rect);
    	pDC->Rectangle(&m_rect2); // le bug se produit
    }
    C'est comme si m_rect était modifié par le reste du code pendant que la fonction trace_rect_rect2(CDC* pDC) était executée

    Le bug est aussi présent si je déclare la fonction inline, même en ne traçant que m_rect2 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    inline void trace_rect_rect2(CDC* pDC) {
    	m_rect2.CopyRect(m_rect);
    	m_rect2.InflateRect(1, 1);
    	//pDC->Rectangle(&m_rect);
    	pDC->Rectangle(&m_rect2);
    }
    Le bug se produit aussi avec cette variante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    inline void trace_rect_rect2(CDC* pDC) {
    	pDC->Rectangle(&m_rect);
    	pDC->Rectangle(m_rect.left-1, m_rect.top-1, m_rect.right+1, m_rect.bottom+1);
    }
    Comme mon code ne fait qu'agrandir le rectangle, le problème n'est pas lié à un rectangle de taille nulle ou négative

    A bientôt
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  2. #2
    Membre chevronné Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 041
    Par défaut
    J'ai résolut le problème de cette manière :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    inline void trace_rect_rect2(CDC* pDC, CRect rect) {
    	CPen NewPen(PS_SOLID, 2, RGB(0, 0, 0));
    	pDC->SelectObject(&NewPen);
    	pDC->Rectangle(&rect);
    	//pDC->Rectangle(rect.left-1, rect.top-1, rect.right+1, rect.bottom+1);
    }
    Ca m'embête un peu de créer un nouveau CPen à chaque appel,

    mais il n'y a aucun impact perceptible sur la rapidité,

    ni sur le reste du programme (c'est un projet open source que j'ai repris)

    Cette manière de faire permet seulement de dessiner un trait plus épais ; j'aurais voulu dessiner un rectangle épais mais avec deux couleurs, ce n'est pas possible
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  3. #3
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 972
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 972
    Par défaut
    Hello,

    Je me permets de rebondir sur votre analyse qui est tout à fait pertinente. Votre diagnostic concernant le manque d'atomicité entre l'événement MouseMove et votre fonction de dessin est parfaitement exact.

    1. Pourquoi votre problème initial se produisait-il ?
    Le phénomène des "lignes fantômes" (ou du déséquilibre lors du rendu XOR) survient car la variable membre de votre classe (m_rect) est lue plusieurs fois au sein de la fonction trace_rect_rect2. Si le système d'événements de Windows traite un nouveau MouseMove entre les différentes instructions de votre fonction de dessin, la valeur de m_rect change "en vol". Votre fonction dessine alors un rectangle basé sur d'anciennes coordonnées et un autre basé sur de nouvelles, ce qui casse l'effet d'effacement.

    2. Pourquoi votre solution fonctionne-t-elle visuellement ?
    Votre correctif, qui consiste à passer l'objet CRect par valeur (inline void trace_rect_rect2(CDC* pDC, CRect rect)), est une excellente approche pour régler le problème d'affichage. En passant le paramètre par valeur, le compilateur effectue une copie immédiate des coordonnées au moment de l'appel. La fonction de dessin travaille alors sur cet "instantané" (snapshot) local, qui est immunisé contre les modifications extérieures générées par la souris pendant l'exécution de la fonction. Le dessin reste donc cohérent du début à la fin.

    3. Le piège caché : Ce que disent les outils d'analyse
    Pour aller plus loin, j'ai reproduit la mécanique de votre code dans un environnement de test isolé et je l'ai passé au crible avec l'outil d'analyse Valgrind (spécifiquement l'outil Helgrind, qui détecte les problèmes de concurrence).

    Bien que votre solution règle l'incohérence visuelle, l'outil lève toujours des erreurs de type Data Race (conflit de données). En effet, bien que le passage par valeur crée une copie sécurisée, l'opération de copie elle-même n'est pas atomique. Si le thread gérant la file de messages modifie m_rect au moment exact où la copie est effectuée pour l'appel de fonction, vous risquez théoriquement d'obtenir un rectangle avec des coordonnées "hybrides" (par exemple, avec le left de l'ancienne position et le right de la nouvelle position).

    4. La solution robuste en C++ Moderne
    Pour garantir une véritable atomicité et vous prémunir contre tout comportement indéfini (Undefined Behavior), la bonne pratique en C++ consiste à utiliser un verrou (std::mutex) lors de la lecture et de l'écriture de cette ressource partagée.

    Voici comment sécuriser totalement votre mécanique vis-à-vis du processeur :

    Code cpp : 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
     
    #include <mutex>
     
    // Dans la déclaration de votre classe
    std::mutex m_rect_mutex;
    CRect m_rect;
     
    // ---------------------------------------------------
    // Lors de la mise à jour (ex: événement MouseMove) :
    {
        std::lock_guard<std::mutex> lock(m_rect_mutex);
        m_rect.left = ...;
        // ...
    }
     
    // ---------------------------------------------------
    // Avant d'appeler la fonction de dessin :
    CRect snapshot;
    {
        // On verrouille juste le temps de faire la copie
        std::lock_guard<std::mutex> lock(m_rect_mutex);
        snapshot = m_rect; 
    }
    // On appelle la fonction avec la copie propre
    trace_rect_rect2(pDC, snapshot);

    En procédant ainsi, vous conservez les bénéfices de votre passage par valeur tout en garantissant au compilateur qu'aucune donnée ne sera corrompue au moment de l'initialisation du paramètre.

    En espérant que ces détails techniques vous seront utiles pour la suite de votre projet. Bonne continuation !
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  4. #4
    Membre chevronné Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 041
    Par défaut
    Merci d'avoir pris le temps de me répondre

    Alors je ne passe pas par valeur

    Voici la fonction dans la version finale :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    CPen pen_rect_epais(PS_SOLID, 3, RGB(0, 0, 0));
    ...
    inline void trace_rect_epais(CDC* pDC, CRect rect) {
    	pDC->SelectObject(&pen_rect_epais);
    	pDC->Rectangle(&rect);
    }

    Et voici le code qui l'appelle

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    trace_rect_epais(pDC, &m_rect); //pDC->Rectangle(&m_rect);
    Je passe par référence et non par valeur (avec le '&') - et ça fonctionne

    Mais le code qui plantait utilisait non pas UNE mais DEUX fonctions graphiques successives

    Donc c'est plus lent et ça laisserait le temps à un autre appel de fonction MouseMove de modifier m_rect entre les deux

    D'après vous, la solution serait donc de passer m_rect par valeur et non pas par référence

    J'ai essayé le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    inline void trace_rect_epais(CDC* pDC, CRect rect) {
    	pDC->Rectangle(&rect);
    	pDC->Rectangle(m_rect.left - 1, m_rect.top - 1, m_rect.right + 1, m_rect.bottom + 1);
    }
    Avec des appels de fonction comme ceci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    trace_rect_epais(pDC, m_rect); //pDC->Rectangle(&m_rect);
    Mais le bug est toujours là - c'est bizarre

    En revanche, ce code-là fonctionne, peut importe que m_rect() soit passé par valeur ou par référence :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    CPen pen_rect_epais(PS_SOLID, 3, RGB(0, 0, 0));
    ...
    inline void trace_rect_epais(CDC* pDC, CRect rect) {
    	pDC->SelectObject(&pen_rect_epais);
    	pDC->Rectangle(&rect);
    }
    Je pourrais optimiser le code en évitant d'appeler à chaque fois SelectObject, mais cela impose des modifications à de nombreux endroits du code pour ajouter les SelectObject aux bons endroits.


    Concernant la "vraie" solution, c'est à dire le mutex, comme vous dites c'est du C++ "moderne"

    Et justement, le programme sur lequel je travaille est un vieux projet open source C++ WIN32 obsolète que j'ai repris, je ne sais pas si le mutex sera accepté,
    et si ça marche j'ai peur de créer d'autres bugs ailleurs que je ne verais pas tout de suite

    Cela me rappelle de mauvais souvenir avec Visual Basic.
    En Visual Basic on arrivait à gérer ces problèmes de façon plus ou moins sale avec DoEvents, et aussi en verrouillant "manuellement" les fonctions avec une variable globale "autorisation_paint" gérée de la manière suivante :
    - au debut de chaque fonction, un test pour voir si autorisation_paint est VRAI, sinon on quitte la fonction
    - juste après, une instruction met autorisation_paint à FALSE
    - à la fin de la fonction, la dernière instruction remet autorisation_paint à TRUE
    Ce n'était pas facile, selon les possibilités d'édition à la souris du programme, il fallait plusieurs variables "autorisation_xxx" et la fonction MouseMove n'était pas traité de la même manière que MouseDown et MouseUp, car "rater" un MouseMove n'était pas grave (et même souhaitable) en revanche il ne fallait pas rater un appel de MouseDown ou MouseUp.

    Ces variables "autorisation_xxx" permettaient aussi d'éviter les ralentissements du à une succession d'appel de fonction d'affichages quand une action unique de l'utilisateur sur l'interface engendre plusieurs évenements (typiquement, le redimenssionnement de la fenêtre qui ajuste le mini, le maxi et la valeur des barres de défilement)

    Je n'ai jamais compris pourquoi WINDOWS et/ou les langages IDE Visual Basic / Visual C++ :
    - n'empêchaient pas de nouveaux appels de MouveMove tant que les précédents ne sont pas terminés
    - ne mettaient pas en attente l'appel de MouseDown ou MouseUp tant qu'un appel précédent de MouseMove n'était pas terminé

    A cause de la manière dont le système d'exploitation gère les évenements de l'interface graphique, on se retrouve à devoir gérer des problèmes de Thread dans un programme qui ne les utilise pas à l'origine
    Ces bugs sont très emmerdants car ils n'apparaissent pas tout de suite.
    Quand le programme est simple (donc rapide) et que l'utilisateur est lent tout fonctionne correctement.1
    Mais quand le programme s'enrichi en fonctionnalités et que le code dans les fonctions devient plus gros et plus lent, et qu'en même temps l'utilisateur maitrise le logiciel et va plus vite, les soucis apparaissent...


    Au risque de choquer les gens, la programmation "à l'ancienne" sous MS-DOS (ou sur un microcontrôleur), où il fallait gérer manuellement une souris, une manette de jeux ou un clavier avec une boucle, était presque plus simple.
    Une interruption mettait à jours les coordonnées souris ou actions de l'utilisateur. On pouvait même faire une pile pour enregistrer plusieurs frappes rapides au clavier successives.
    La boucle principale du programme scrutait si les valeurs avaient changés, et si oui, les traitait.
    Pas de problème de recouvrement.


    La solution que j'ai trouvée, qui dessine un seul rectangle épais via un CPen fonctionne, je vais m'en contenter.
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  5. #5
    Membre chevronné Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 041
    Par défaut
    Bonjour,

    Voici une remarque :

    Avec la technique NOT XOR PEN, si on dessine avec une couleur noire, il sera tracé avec un négatif de l'image originale

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CPen pen_rect_epais(PS_SOLID, 3, RGB(0, 0, 0));
    La visibilité est maximale si les composantes RGB de l'image originale sont proches de 0 ou 255 (ce qui est le cas des images correspondant à des plans, des schémas ou du texte)

    Mais si c'est proche du gris (128), la visibilité est très faible voire nulle. En effet, le négatif du gris... c'est le gris

    Or les photos contiennent beaucoup de tons intermédiaires, c'est à dire assez proche du gris, notamment avant qu'on les retravaille pour améliorer le contraste et la dynamique.

    En utilisant comme couleur RGB(127, 127, 127), le dessin sera tracé en inversant uniquement le bit de poids fort de chaque composante RGB de l'image originale.

    Autrement dit, chaque pixel sera tracé avec un "décalage" positif ou négatif d'une amplitude constante de 128.

    La visibilité est donc constante, quelque soit les couleurs de l'image originale :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CPen pen_rect_epais(PS_SOLID, 3, RGB(127, 127, 127));
    A bientôt
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  6. #6
    Invité de passage
    Homme Profil pro
         ​​​  
    Inscrit en
    Décembre 2025
    Messages
    93
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité :      ​​​  

    Informations forums :
    Inscription : Décembre 2025
    Messages : 93
    Par défaut
    Bonsoi,

    J'ai testé ton algo basé sur le dessin deux rectangles, je n'ai pas C++ mais en Delphi, l'algo fonctionne sans problème, pour eviter les rebonds de la souris et les événements aléatoires j'ai placé les trois événements Mouse Down Move Up dans une seule fonction avec boucle..
    Ma remarque perso et que je n'ai pas différence notable entre cette méthode et celle d'utilisation d un Pen plus large, j'ai tenté deux couleurs et la valeur préconisée RGB(127,127,127) mais la différence est marginale:




    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
    var
      FMovePt: TPoint;
      FDown: boolean;
     
    procedure TForm1.DrawRect2(X1, Y1, X2, Y2: integer);
    var
     Rc: TRect;
    begin
       with image1 do
       begin
          if (abs(X1 - X2) < 3) or (abs(Y1 - Y2) <3) then
             Exit;
          Rc := Rect(X1, Y1, X2, Y2);
          Canvas.Rectangle(Rc);
          Rc.Inflate(1,1);
          Canvas.Rectangle(Rc);
       end;
    end;
     
    procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    var
       PrvPt, Dwn: TPoint;
    begin
       if FDown then exit;
       FDown:= true;
       Dwn := Point(X,Y);
       FMovePt  := Dwn;
       PrvPt := Dwn;
       with image1 do
       begin
           Canvas.Brush.Style := bsClear;
           Canvas.Pen.Width := 1;
           Canvas.Pen.Color := rgb(127,127,127);
           Canvas.Pen.Mode  := pmNotXor;
           while GetAsyncKeyState(VK_LBUTTON) < 0 do
           begin
              if FMovePt <> PrvPt then
              begin
                 DrawRect2(Dwn.X, Dwn.Y, PrvPt.x, PrvPt.y);
                 DrawRect2(Dwn.X, Dwn.Y, FMovePt.x, FMovePt.y);
                 PrvPt := FMovePt;
              end;
              Application.HandleMessage;
           end;
           DrawRect2(Dwn.X, Dwn.Y, PrvPt.x, PrvPt.y);
       end;
       FDown:= False;
     
    end;
     
    procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    begin
      FMovePt := Point(X,Y);
    end;

  7. #7
    Membre chevronné Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 041
    Par défaut
    Citation Envoyé par Informt2025 Voir le message
    Bonsoi,
    J'ai testé ton algo basé sur le dessin deux rectangles, je n'ai pas C++ mais en Delphi, l'algo fonctionne sans problème, pour eviter les rebonds de la souris et les événements aléatoires j'ai placé les trois événements Mouse Down Move Up dans une seule fonction avec boucle..
    Comme je l'ai précisé le programme original n'est pas de moi.

    Le code source est assez lourd, je ne peux même pas publier le code du fichier .cpp de la fenêtre sur le forum car il dépasse la limite de caractères imposée par le forum

    Il y a, dans ce programme, DEUX zones d'affichages qui dessine un rectangle de sélection avec NOT XOR PEN

    Une des zones est un code que j'ai ajouté moi même ensuite, et celui-là fonctionne sans bug.

    Mais le code original, qui dessine un rectangle de sélection persistant pour recadrer l'image, présente le fameux bug.
    Ce code est beaucoup plus complexe, notamment parceque l'objet 'm_rect' est utilisé un peu partout.
    En fait le programme comporte une fonction de recadrage automatique que l'on peut "shunter" en dessinant un rectangle de sélection manuel si on désire recadrer autrement.
    Le code n'est pas documenté, et beaucoup de noms de fonctions et de variables sont en allemand que je ne parle pas, ce qui rend la compréhension et les modifications fastidieuses...
    Et bien sûr, le code est optimisé (ce qui est normal pour un logiciel de traitement photo) ce qui rend les modifications encore plus ardues.

    J'ai surtout peur, en faisant trop de modifications pour résoudre ce bug, de créer d'autres bugs dans des fonctions dont je ne connais pas l'utilité.

    C'est toute la difficulté du reverse engineering

    Il faut passer du temps pour comprendre ce que fait le code, et ensuite modifier le code existant qu'aux endroits où on sait ce que l'on fait.

    Citation Envoyé par Informt2025 Voir le message
    Bonsoi,
    Ma remarque perso et que je n'ai pas différence notable entre cette méthode et celle d'utilisation d'un Pen plus large, j'ai tenté deux couleurs et la valeur préconisée RGB(127,127,127) mais la différence est marginale:

    Alors oui ce n'est pas flagrant car ton image a des tons et des couleurs bien constrastés.

    Si tu utilises une photo avec des tons pâles ou gris, ce sera bien plus visible.

    Les photos que je traite viennent d'un appareil photo semi-pro.
    Ce type d'appareil photo préserve la dynamique pour éviter d'avoir des zones bouchées ou cramées, pour laisser la possibilité d'agir ensuite en post-traitement sans perte de données.
    Les photos que je traite avec ma version modifiée de ShiftN sont des photos "brutes", ce traitement est le premier que je réalise.
    C'est seulement ensuite que je traite les photos avec un autre logiciel pour corriger les niveaux et réhausser la dynamique.
    Donc une bonne partie des photos que je traite sont un peu "pâles", avec pour conséquence un rectangle de sélection par endroit assez peu visible si on dessine en noir avec NOT XOR PEN.

    Les photos prises avec un smartphone sont, au contraires, optimisées au maximum par le logiciel photo du smartphone.
    Cela permet aux utilisateurs d'avoir une photo avec un bel aspect directement sans traitement.
    Mais si on essaye de retoucher une photo prise au smartphone, on n'a quasiment plus de "marge", le contraste et la saturation ayant déjà été poussées au maximum.
    C'est pareil pour la nettetée et le bruit.
    Sur les smartphones haut de gamme des algorithmes - parfois avec de l'IA - ajoutent des effets (par exemple accentuer le flou d'arrière plan).
    Les smartphones font aussi de "l'assemblage", quand les conditions de prise de vue sont difficiles, plusieurs photos sont prises et ensuite le logiciel les fusionne en choisissant dans chaque image les meilleures zones. Cela compense le manque de performance optique lié à la petite taille des objetifs et des capteurs.
    Ces traitements sont en fait destructeurs : si la photo originale a l'air très bien, on ne peut pas la "pousser" plus loin, car les traitements logiciel du smartphone, en améliorant l'image, ont en fait détruit des données.

    Un appareil photo pro ou semi pro va au contraire laisser un maximum d'information.
    Le traitement de l'image réalisé par le processeur de l'appareil photo sera limité aux corrections des déformations optiques fournies par l'objetif, et à la réduction du bruit lors des pauses longues.
    Il faut retraiter l'image ensuite...
    ... mais l'avantage c'est qu'on a le choix du traitement qu'on va faire.

    Les puristes utilisent le format RAW qui laisse les données totalement brutes, mais le travail de traitement est alors conséquent.
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  8. #8
    Invité de passage
    Homme Profil pro
         ​​​  
    Inscrit en
    Décembre 2025
    Messages
    93
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité :      ​​​  

    Informations forums :
    Inscription : Décembre 2025
    Messages : 93
    Par défaut
    C'est vrai que lorsqu’on modifie un code qu on connaît pas bien, c'est souvent le cas, il y a le risque d'introduire un bug peut être plus grave que celui qu on souhaite réparer..le problème avec la méthode de Xor qu'elle exige un stricte équilibre dans les appels pour garantir que l’opération inverse soit appliqué pour retrouver les valeurs originales des pixels, cette méthode s'interfere avec les données de l'image et le gestionnaire du dessin ce qui la rend difficile même pour un programme conçu par soi mème sans parler des contraintes liés au versions windows si le programme est tres vieux datant de l'époque le XP qui utilise moins de cache pour le rafraîchissement et appelle beaucoup de WM_PAINT.

    En théorie le frame de la sélection est un objet distinct qui doit être géré dans une couche séparée qui superpose l'image, on peut envisager par exemple l’utilisation d'un contrôle transparent pour remplacer l'opération du dessin nXor..

    Il existe une vieille technique plus que pratique pour manipuler les sélections sans interférer dans le gestionnaire de dessin c'est d utiliser une fenetre interne en guise de frame de sélection, placer cette fenetre à l'interieure de la fenetre du travail ajuster ses dimensions bordures via createregion et SetWindowRgn.. on peut meme envisager la creation d'un frame animé.



  9. #9
    Membre chevronné Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 041
    Par défaut
    Citation Envoyé par Informt2025 Voir le message
    C'est vrai que lorsqu’on modifie un code qu on connaît pas bien, c'est souvent le cas, il y a le risque d'introduire un bug peut être plus grave que celui qu on souhaite réparer..le problème avec la méthode de Xor qu'elle exige un stricte équilibre dans les appels pour garantir que l’opération inverse soit appliqué pour retrouver les valeurs originales des pixels, cette méthode s'interfere avec les données de l'image et le gestionnaire du dessin ce qui la rend difficile même pour un programme conçu par soi mème sans parler des contraintes liés au versions windows si le programme est tres vieux datant de l'époque le XP qui utilise moins de cache pour le rafraîchissement et appelle beaucoup de WM_PAINT.

    En théorie le frame de la sélection est un objet distinct qui doit être géré dans une couche séparée qui superpose l'image, on peut envisager par exemple l’utilisation d'un contrôle transparent pour remplacer l'opération du dessin nXor..

    Il existe une vieille technique plus que pratique pour manipuler les sélections sans interférer dans le gestionnaire de dessin c'est d utiliser une fenetre interne en guise de frame de sélection, placer cette fenetre à l'interieure de la fenetre du travail ajuster ses dimensions bordures via createregion et SetWindowRgn.. on peut meme envisager la creation d'un frame animé.
    C'est intéressant, mais, difficulté supplémentaire : je modifie ce projet obsolète avec une version beaucoup plus récente de l'IDE : Visual Studio 2015

    Pour modifier l'interface graphique, c'est la galère, il faut bidouiller les fichiers de ressource, puis recompiler des DLL pour que ça soit pris en compte dans la version Release (voir mon autre post sur ce problème là)

    Autre aspect du problème : le programme fonctionne encore très bien sous Windows 11, mais j'ai peur qu'il ne fonctionne plus avec les futures mises à jour.


    Je continue à maintenir un logiciel que j'avais terminé en... 2003, créé avec Visual Basic 5, il s'appelle CiDess

    http://cidess.free.fr/index-fr.html

    Pour qu'il tourne encore sous Windows 10 et Windows 11, j'ai dû le modifier pour ne plus utiliser des contrôles OCX


    Donc pour ShiftN, il faut que je reste avec des fonctions de base de GDI32.

    Si j'utilise des astuces trop poussées, ça risque de ne plus fonctionner du tout.


    Je devrait être tranquille, car étant donné le nombre d'anciens logiciels encore utilisés dans beaucoup d'entreprises, Microsoft ne devrait pas prendre le risque de supprimer la rétrocompatibilité avec les programmes WIN32

    Il faut arrêter avec la "mise-à-jourite aigue", il existe des tas de logiciels anciens qui font parfaitement le job et qui n'ont pas besoin d'être améliorés.

    Il y a un gros sujet dans l'industrie avec les logiciels qui pilotent des machines automatiques ou des machines outils à commande numérique.
    Des machines des années 2000, 1990 ou même plus anciennes encore sont en parfait état de marche mais ont des systèmes informatiques obsolètes.
    Il serait absurde d'un point de vue économique et écologique de les remplacer uniquement à cause de l'obsolescence du système informatique.
    Et un rétrofit est une tâche très ardue...

    De plus, la performance des ordinateurs stagne depuis un certain temps...

    Aujourd'hui un PC qui a plus de 10 ans est encore utilisable (sauf sous Windows 11 à cause de TPM 2.0), chose totalement inimaginable à l'époque...

    En 1989 c'était l'arrivée du 486, dix ans plus tard, en 1999 c'était l'entrée en scène du Pentium III
    A cette époque, tous les 2 ou 3 ans la nouvelle génération d'ordinateurs apportait de nouveaux usages (MP3, vidéo, 3D, ...)

    Le passage de MS-DOS à Windows 3.11, puis à Windows 95, puis à Windows XP, ont été des évolutions majeures.

    Rien à voir avec la décennie écoulée
    Windows 10 puis Windows 11 n'ont RIEN apporté de plus par rapport à Windows 7.
    L'expérience utilisateur et la fiabilité ont même été dégradées...
    Par exemple, avec le Pack Office, le fameux ruban, quelle idée à la con
    Avec Office 1997, dans Word, j'avais plein de barres d'outils que j'avais positionné sur les côtés, en vertical, pour exploiter au mieux la hauteur de mon écran 16/9 pour éditer des documents au format A4.
    La perte d'ergonomie a été énorme, quand on a besoin de faire des dessins dans Word ou de travailler avec des images bonjour les TMS avec la souris...

    Ce qui m'énerve le plus, c'est qu'avec la puissance des ordinateurs actuels, les devellopeurs n'optimisent plus rien, et utilisent de plus en plus des langages avec des performances médiocres.
    J'ai des vieux logiciels programmés en C++ d'il y 10, 15 ou 20 ans qui font la même chose que des logiciels actuels en étant plus rapides.

    Et surtout : le fait que les logiciels ne sont achetable définitivement, mais qu'il faille payer un loyer, avec un serveur de licence, qui lorsqu'il ferme, rend le logiciel inutilisable.
    Ce genre de truc devrait être illégal


    Ca va faire hurler certaines personnes, mais Microsoft devrait arrêter de sortir de nouvelles versions de Windows.

    On a besoin de mises à jour de sécurité, d'une meilleur stabilité, d'optimisations, éventuellement d'options d'ergonomies supplémentaires, mais rien d'autre.

    Il n'y a plus grand chose à inventer en matière de système d'exploitation multitâche avec interface graphique depuis longtemps.

    D'ailleurs depuis Windows XP, je désactive toutes les évolutions kikoolol pour revenir à quelque chose de sobre à la Windows 95

    Merci à TweakUI et ExplorerPatcher
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  10. #10
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 652
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 652
    Par défaut
    C'est comme si m_rect était modifié par le reste du code pendant que la fonction trace_rect_rect2(CDC* pDC) était executée
    Pour moi, c'est très très improbable car les applications MFC sont, par défaut, mono-threadé et ne supportent pas plusieurs threads dans les composants graphiques.

    MFC utilise une pompe à message pour la gestion des évènements. Pendant la gestion d'un évènement, aucun autre évènement n'est traité.

    Je ne vois pas dans le nommage des variables un attention particulière faite aux coordonnées lors du précédent affichage.

    Pour que le XOR fonctionne, vous devez appeler 2 fois l'affichage :
    - une première fois, sur les anciennes coordonnées, pour effacer le précédent rectangle
    - une seconde fois, sur les "nouvelles" coordonnées pour afficher le rectangle aux nouvelles coordonnées.

    Utilisez les primitives de trace des MFC 'TRACEx" pour voir les valeurs des coordonnées du vieux rectangle et du nouveau rectangle.
    S'ils ne s'affichent pas par paire identiques (les nouvelles coordonnées deviennent les anciennes, etc...), c'est qu'il y a un problème dans votre code.

    Je suis très circonspect sur la réponse de @fred1599. J'ai l'impression qu'il n'a pas pris en compte les spécificités des MFC et en particulier son modèle de threading.

    Je passe par référence et non par valeur (avec le '&') - et ça fonctionne
    Absolument pas. Quand vous utilisez un "&" (esperluette) lors d'un appel, vous ne faite pas un appel par référence mais vous passez un pointeur sur l'objet.
    Comme la fonction Rectangle prend aussi bien un LPCRECT (https://learn.microsoft.com/en-us/cp...-170#rectangle) qu'un quadruplé de int et que la classe CRect doit avoir un opérateur de cast de CRect* vers LPCRECT, ça passe (à moins que des warnings s'allument sur ces lignes un peu dégueu).
    Mais c'est pas un passage par référence ni pas valeur, mais par "pointeur nus".

    D'après vous, la solution serait donc de passer m_rect par valeur et non pas par référence
    Cela pourrait corriger un cas d'erreur que je trouve très très improbable.
    Pour moi, le cas le plus probable, c'est que les appels d'affichage et d'effacement ne sont pas correctement "apparaillés". cf.urilisation de TRACEx ci-avant.

    Concernant la "vraie" solution, c'est à dire le mutex, comme vous dites c'est du C++ "moderne"

    Et justement, le programme sur lequel je travaille est un vieux projet open source C++ WIN32 obsolète que j'ai repris, je ne sais pas si le mutex sera accepté,
    et si ça marche j'ai peur de créer d'autres bugs ailleurs que je ne verais pas tout de suite
    Le framework des MFC fait que vous n'avez pas besoin de ces "nouvelles" fonctionnalités.

    Cela me rappelle de mauvais souvenir avec Visual Basic.
    En Visual Basic on arrivait à gérer ces problèmes de façon plus ou moins sale avec DoEvents, et aussi en verrouillant "manuellement" les fonctions avec une variable globale "autorisation_paint" gérée de la manière suivante :
    - au debut de chaque fonction, un test pour voir si autorisation_paint est VRAI, sinon on quitte la fonction
    - juste après, une instruction met autorisation_paint à FALSE
    - à la fin de la fonction, la dernière instruction remet autorisation_paint à TRUE
    Ce n'était pas facile, selon les possibilités d'édition à la souris du programme, il fallait plusieurs variables "autorisation_xxx" et la fonction MouseMove n'était pas traité de la même manière que MouseDown et MouseUp, car "rater" un MouseMove n'était pas grave (et même souhaitable) en revanche il ne fallait pas rater un appel de MouseDown ou MouseUp.
    De quel "Visual Basic" on parle ?
    De VB6 ?
    VB6, c'est comme les MFC, c'est mono-thread de base, plus précisément STA (Single Thread Appartment) donc avec des protections contre les autres threads.
    Votre histoire de "autorisation_paint", ça semble une bonne vieille rustine pourrie pour appeler la fonction DoEvents n'importe comment et esquiver les appels récursifs qu'implique l'appel sauvage de DoEvents.
    Il y a des appels de fonction dans des contrôles standard pour désactiver le calcul d'affichage tant qu'on n'a pas fini le chargement de données dedans, mais c'est juste pour faire des optimisations, pas pour autoriser des DoEvents de barbares.
    Je ne vois pas comment vous pouviez "looper" des MouseDown etc..., c'est l'OS qui s'en occupe et VB a le même type de pompe à message que MFC ou le SDL Win32.

    Ces variables "autorisation_xxx" permettaient aussi d'éviter les ralentissements du à une succession d'appel de fonction d'affichages quand une action unique de l'utilisateur sur l'interface engendre plusieurs évenements (typiquement, le redimenssionnement de la fenêtre qui ajuste le mini, le maxi et la valeur des barres de défilement)
    cf. "Il y a des appels de fonction dans des contrôles standard pour désactiver le calcul d'affichage ..." ci-avant.

    Je n'ai jamais compris pourquoi WINDOWS et/ou les langages IDE Visual Basic / Visual C++ :
    - n'empêchaient pas de nouveaux appels de MouveMove tant que les précédents ne sont pas terminés
    - ne mettaient pas en attente l'appel de MouseDown ou MouseUp tant qu'un appel précédent de MouseMove n'était pas terminé
    Bin, tous les framework courants sous Windows, à base de pompe à messages, n'ont aucuns des inconvénients que vous mentionnez.
    Ils sérialisent tout, messages après messages.

    A cause de la manière dont le système d'exploitation gère les évenements de l'interface graphique, on se retrouve à devoir gérer des problèmes de Thread dans un programme qui ne les utilise pas à l'origine
    Ces bugs sont très emmerdants car ils n'apparaissent pas tout de suite.
    Quand le programme est simple (donc rapide) et que l'utilisateur est lent tout fonctionne correctement.1
    Mais quand le programme s'enrichi en fonctionnalités et que le code dans les fonctions devient plus gros et plus lent, et qu'en même temps l'utilisateur maitrise le logiciel et va plus vite, les soucis apparaissent...
    Ne serait-ce pas plutôt des bugs latents que la vitesse d'exécution révèle ?
    Il n'y a pas de problèmes de thread quand on utilise "simplement" les Framework de base de Windows.
    Vous mentionnez des Thread dans un programme "simple". Pourquoi avez-vous besoin de thread dans des cas simples, sachant que les Framework s'arrangent pour n'utiliser que le thread créateur de la première fenêtre.

    Au risque de choquer les gens, la programmation "à l'ancienne" sous MS-DOS (ou sur un microcontrôleur), où il fallait gérer manuellement une souris, une manette de jeux ou un clavier avec une boucle, était presque plus simple.
    Une interruption mettait à jours les coordonnées souris ou actions de l'utilisateur. On pouvait même faire une pile pour enregistrer plusieurs frappes rapides au clavier successives.
    La boucle principale du programme scrutait si les valeurs avaient changés, et si oui, les traitait.
    Pas de problème de recouvrement.
    C'est encore plus simple en Windows car vous n'avez pas à gérer des interruptions. Vous n'avez pas à gérer les différents périphériques car les évènements postés dans la pompe à message colportent l'ensemble des informations nécessaires (états de boutons du clavier, de la souris, etc...) et chaque changement d'état fait potentiellement l'objet d'un post dans la file de message de la fenêtre qui va bien.

    Franchement, je ne vois pas en quoi la programmation MS-DOS, avec ces terribles programmes résidents TSR qui foutaient la grouille en moins de 2 était plus simple.

    Dans le code de @Informt2025, on voit bien que les coordonnés nouvelles (FMovePt) ne sont pas mélangées avec les coordonnées anciennes (PrvPt) et que l'appel de DrawRect2 avec les anciennes cordonnées précède toujours celles avec les nouvelles.

    Le code source est assez lourd, je ne peux même pas publier le code du fichier .cpp de la fenêtre sur le forum car il dépasse la limite de caractères imposée par le forum
    GitHub ou GitLab sont nos amis.

    Ce code est beaucoup plus complexe, notamment parceque l'objet 'm_rect' est utilisé un peu partout.
    Je crois que c'est le nœud du problème.

    Je pense que tenter un passage d'IA pour traduire le code en anglais et ajouter des commentaires, ça se tente, pour améliorer drastiquement la maintenabilité du bidule.

    Si "m_rect" est mal utilisé, vous êtes bon pour le corriger. Mais je vois pas trop le problème pour le corriger.

    Pour compléter la réponse très pertinente de @Informt2025 le "18/07/2026, 00h03", il existe des classes de "haut niveau" pour gérer ce type de fonctionnalité, comme la classe CRectTracker :
    https://learn.microsoft.com/en-us/cp...?view=msvc-170

    @electroremy, si tu as du mal à "couper dans le vif", prépare un jeu de test de non-régression et tu seras bien plus "relaxe".

    C'est intéressant, mais, difficulté supplémentaire : je modifie ce projet obsolète avec une version beaucoup plus récente de l'IDE : Visual Studio 2015
    Pourquoi rester en VS2015 quand il existe pléthore de versions plus récentes ?
    Vous avez pris un risque pour le passer en VS2015, pourquoi ne pas le prendre pour avoir une version plus actuelle ?
    cf. Test de non-régression

    Pour modifier l'interface graphique, c'est la galère, il faut bidouiller les fichiers de ressource, puis recompiler des DLL pour que ça soit pris en compte dans la version Release (voir mon autre post sur ce problème là)
    Déjà répondu, c'est un projet MFC, vous devez disposer d'un Designer Graphique, sauf si vos modifications l'ont cassé. (Peut-être que l'ancien mainteneur l'avait déjà "cassé")

    Autre aspect du problème : le programme fonctionne encore très bien sous Windows 11, mais j'ai peur qu'il ne fonctionne plus avec les futures mises à jour.
    Pour le coup, c'est plutôt les MFC qui font craindre un problème d'obsolescence car c'est plus une bibliothèque très soutenue pas M$.
    Vous deviez tenter une migration vers des bibliothèques plus récentes. Mais l'architecture du projet est peut-être mal fichue pour résister à ce type de migration.
    GDI32 est bien plus pérenne que les MFC.

    Vous engrangez de la dette technique, et, un jour, faut passer à la caisse.

    N'engrangez pas cette dette en utilisant toujours les outils à jours. Quand des composants deviennent obsolètes, migrez avant qu'il soit trop tard et que vous soyez au pied du mur.

    Je continue à maintenir un logiciel que j'avais terminé en... 2003, créé avec Visual Basic 5, il s'appelle CiDess

    http://cidess.free.fr/index-fr.html

    Pour qu'il tourne encore sous Windows 10 et Windows 11, j'ai dû le modifier pour ne plus utiliser des contrôles OCX
    OCX est encore "maintenu", c'est plutôt VB5 qui est "mort".
    Pourquoi ne pas faire sa migration vers du VB.NET ou autres ?

    Les IA comme Claude Code font des miracles au niveau des migrations, même depuis des antiquités.

    Donc pour ShiftN, il faut que je reste avec des fonctions de base de GDI32.
    Vous n'êtes pas en GDI32 "de base", vous êtes en MFC, et c'est plus problématique.

    Si j'utilise des astuces trop poussées, ça risque de ne plus fonctionner du tout.
    Git et les tests de non-régressions sont nos amis, les IA aussi.

    Je devrait être tranquille, car étant donné le nombre d'anciens logiciels encore utilisés dans beaucoup d'entreprises, Microsoft ne devrait pas prendre le risque de supprimer la rétrocompatibilité avec les programmes WIN32
    Il faut que M$ y trouve son compte, et votre programme est MFC, pas WIN32.
    MFC, ça fait des décennies qu'ils indiquent qu'elle va crever, ils vous auront pas pris en traitre .

    Il faut arrêter avec la "mise-à-jourite aigue", il existe des tas de logiciels anciens qui font parfaitement le job et qui n'ont pas besoin d'être améliorés.
    Sauf qu'eux, ils ont des trous de sécurité et des problèmes de compatibilité à patch et qu'ils ne peuvent pas avoir de dette technique abyssale.

    Il y a un gros sujet dans l'industrie avec les logiciels qui pilotent des machines automatiques ou des machines outils à commande numérique.
    Des machines des années 2000, 1990 ou même plus anciennes encore sont en parfait état de marche mais ont des systèmes informatiques obsolètes.
    Il serait absurde d'un point de vue économique et écologique de les remplacer uniquement à cause de l'obsolescence du système informatique.
    Et un rétrofit est une tâche très ardue...
    Toi, t'as pas entendu parler de Stuxnet.

    Et surtout : le fait que les logiciels ne sont achetable définitivement, mais qu'il faille payer un loyer, avec un serveur de licence, qui lorsqu'il ferme, rend le logiciel inutilisable.
    Ce genre de truc devrait être illégal
    T'as signé la pétition européenne sur le sujet ?

    Il n'y a plus grand chose à inventer en matière de système d'exploitation multitâche avec interface graphique depuis longtemps.
    On se demande pourquoi MacOS et Linux prennent des parts de marché.

  11. #11
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 652
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 652
    Par défaut
    @Informt2025
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Application.HandleMessage
    Ca fait quoi ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while GetAsyncKeyState(VK_LBUTTON) < 0 do
    Pourquoi cette boucle ???

  12. #12
    Invité de passage
    Homme Profil pro
         ​​​  
    Inscrit en
    Décembre 2025
    Messages
    93
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité :      ​​​  

    Informations forums :
    Inscription : Décembre 2025
    Messages : 93
    Par défaut
    Bonjour,

    La boucle while GetAsyncKeyState(VK_LBUTTON) < 0 do sert à vérifier que le bouton gauche de la souris est encore enfoncé, en effet le code est bloquant et il n'est plus possible de quitter MouseDown avant que la souris ne soit relâchée .

    On peut distinguer trois parties dans ce code: avant la boucle constitue l'évenement MouseDown, la boucle qui simule le MouseMove et après la boucle c'est le MouseUp, cette séquence au sein de la même procédure garantit l'enchaînement des trois évènements stricts pour equlibrer les operation XOR et pour faciliter l'implémentation de l'algo mieux que de le disperser entre 3 fonctions séparées..on peut l’optimiser avec un try/finally pour s'assurer que Xor finale soit appliqué ainsi la restauration de FDown pour indiquer que MouseDown est libre.

    Application.HandleMessage est considéré comme DoEvents en VB6 pour traiter les messages actuellement présents dans la file d'attente avec la particularité de mettre en pause le thread si aucun message n'est disponible pour éviter l'emballement du CPU.

  13. #13
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 825
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 825
    Par défaut
    Bonjour,

    Plutôt que de modifier l'image elle-même pour afficher box et autres informations temporaires, il est possible de les tracer sur un Paint placé au-dessus de l'image. C'est juste une surface d'affichage (un canvas, un hdc) qui ne stocke pas l'information. Il faut, à chaque rafraichissement, redessiner l'ensemble des informations à superposer, sinon elles disparaissent. Cet inconvénient est ici un avantage. L'actualisation se limite à demander un rafraichissement (aka repaint).

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  14. #14
    Membre chevronné Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 041
    Par défaut
    Citation Envoyé par bacelar Voir le message
    Pour que le XOR fonctionne, vous devez appeler 2 fois l'affichage :
    - une première fois, sur les anciennes coordonnées, pour effacer le précédent rectangle
    - une seconde fois, sur les "nouvelles" coordonnées pour afficher le rectangle aux nouvelles coordonnées.
    C'est ce que le code original fait, j'ai "seulement" essayé de modifié le tracé

    Citation Envoyé par bacelar Voir le message
    MFC utilise une pompe à message pour la gestion des évènements. Pendant la gestion d'un évènement, aucun autre évènement n'est traité.

    De quel "Visual Basic" on parle ?
    De VB6 ?
    De VB5

    Citation Envoyé par bacelar Voir le message
    Votre histoire de "autorisation_paint", ça semble une bonne vieille rustine pourrie pour appeler la fonction DoEvents n'importe comment et esquiver les appels récursifs qu'implique l'appel sauvage de DoEvents.
    Il y a des appels de fonction dans des contrôles standard pour désactiver le calcul d'affichage tant qu'on n'a pas fini le chargement de données dedans, mais c'est juste pour faire des optimisations, pas pour autoriser des DoEvents de barbares.
    Je ne vois pas comment vous pouviez "looper" des MouseDown etc..., c'est l'OS qui s'en occupe et VB a le même type de pompe à message que MFC ou le SDL Win32.
    As-tu déjà dévellopé un logiciel de CAO complet ?

    J'avais aussi un problème de fluidité d'affichage, résolus grâce à DoEvents et à ces rustines.

    Citation Envoyé par bacelar Voir le message
    Toi, t'as pas entendu parler de Stuxnet.
    Si justement Je trouve que c'est aberrant de relier des machines ou des machines-outils à internet.

    C'est la mode de tout connecter à Internet, sans se poser les questions suivantes :
    - est-ce vraiement utile ?
    - quels sont les risques ?

    Dans le cas où on a seulement besoin de surveiller ou d'avoir un retour d'information via Internet, on peut très bien installer une interface de sortie électronique elle-même reliée à un boitier indépendant relié à Internet, de telle sorte via Internet on aura un accès en "lecture seule" mais tout sabotage à distance sera impossible.

    Même réflexion pour la vidéo surveillance... pas besoin de tout filmer, et si c'est juste pour détecter une anomalie pas besoin d'avoir une haute définition qui dévoile des choses sensibles.

    Que ce soit en matière de données ou de connectivité, il est prudent de se contenter du strict minimum nécessaire.
    Une donnée qui n'est pas sur un serveur ne sera pas volée lors d'un piratage


    Citation Envoyé par bacelar Voir le message
    On se demande pourquoi MacOS et Linux prennent des parts de marché.
    Ce n'est pas aussi simple...
    Beaucoup de personnes et d'entreprises utilisent des outils informatiques métiers spécifiques un peu anciens et ne fonctionnant que sous Windows...
    Refaire ces outils avec un IDE moderne demande beaucoup de temps et implique aussi de refaire tous les tests.
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

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

Discussions similaires

  1. Evaluation de la fonction quote
    Par Toitoine dans le forum Lisp
    Réponses: 2
    Dernier message: 05/05/2007, 19h13
  2. [Fonction] Quote et guillemet dans un textarea
    Par ddelec24 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 11/03/2007, 15h51
  3. Fonction Quoted printable qui ne fonctionne pas.
    Par leCcsympas dans le forum C
    Réponses: 3
    Dernier message: 13/01/2007, 18h54
  4. Inverse de la fonction QUOTE() ?
    Par __fabrice dans le forum SQL Procédural
    Réponses: 2
    Dernier message: 13/07/2006, 10h39

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