Partage
  • Partager sur Facebook
  • Partager sur Twitter

Explication attente interaction utilisateur

    25 janvier 2023 à 13:10:08

    Bonjour,

    J'ai une question un peu générale sur la programmation et je ne trouve pas de réponse sur internet :

    J'apprends à programmer en C#, et j'aimerais comprendre comment on fait pour "bloquer" l'exécution du programme pour attendre une action de l'utilisateur.

    Car le programme commence par la méthode Main() et se termine quand il arrive à la fin, mais si on a une Windows Form et que l'on fait Form.ShowDialog(), alors on attend que l'on ferme cette Form pour continuer. Donc j'aimerais comprendre le fonctionnement interne de ce .ShowDialog pour savoir comment il attend l'interaction de l'utilisateur pour continuer le déroulement du programme dans Main().

    J'espère avoir été clair :)

    Cordialement,

    • Partager sur Facebook
    • Partager sur Twitter
      25 janvier 2023 à 17:08:15

      Ca dépend de l'OS sur lequel tourne le programme.

      Le framework .NET fait croire que c'est partout pareil mais chaque OS fait sa tambouille dans son coin.

      Sous Windows, le programme n'ai pas bloqué, il exécute une boucle sur une "pompe à message" pour répondre aux solicitations de l'OS.

      Une "pompe à message" est une boucle où le programme attend (passivement, c'est le Kernel qui freeze le processus pendant l'attente) de recevoir un message (rafraîchir l'affichage, traiter une touche, etc...) puis traite le message et recommence son attente pour le prochain message à traiter, et ainsi de suite, jusqu'à avoir un message WM_QUIT pour sortir de la boucle.

      Comme .NET a été conçu pour Windows principalement, on peut voir des trucs comme "Form.ProcessDialogKey" qui hérite directement de comment on travaille avec l'OS Windows quand il n'y avait pas le framework .NET :

      https://learn.microsoft.com/fr-fr/dotnet/api/system.windows.forms.form.processdialogkey?view=netframework-4.8

      Quand l'OS travaille différemment que Windows, le framework fait des acrobaties pour faire "comme si".

      C'est pour cela qu'il y a des trucs disponible dans les versions Core de .NET et pas d'autres.

      Quand c'est dans la version Core, c'est qu'on a réussi à implémenter le bidule sur tous les OS supportés.

      Sous Windows, le ShowDialog est un moyen qui permet de fournir un mécanisme de routage des messages de la pompe à message "principale" vers une "routine de fenêtre" spécifique au formulaire "Dialog" (boîte de dialogue, souvent modale).

      Quasi tous les messages sont passés de la pompe à message à la "routine de fenêtre" dans ce type de routage.

      C'est pour cela que l'activité des autres fenêtres de l'application est "bloqué" : c'est une fenêtre "Modale" qui prend en charge la très grande majorité des messages. (Il y a un mécanisme pour indiquer que la "routine de fenêtre" n'a pas traité le message et de faire suivre le message aux autres modules/fenêtres/...)

      Donc, avant le "ShowDialog" le code :

      Application.Run(new Form1());

      fait en sorte de créer une pompe à message et met en place un routage des messages vers la routine de fenêtre de "Form1".

      Avec l'appel à "toto.ShowDialog", la pompe à message envoie les messages vers la routine de fenêtre "toto". (les messages non géré par toto seront renvoyé vers sa fenêtre parente, etc...)

      A la sortie de ShowDialog, l'ancien routage des messages revient en place.

      • Partager sur Facebook
      • Partager sur Twitter
      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
        27 janvier 2023 à 16:24:38

        @kontigent, j'attendais des protestations de votre part car mon explication n'est vraiment simple.

        Soit vous êtes brillant, soit je vous ai matraqué trop fort pour que vous réagissiez.

        Une explication plus simple, c'est qu'il y a une boucle dans ShowDialog qui empêche de sortir de la fonction tant que la fenêtre n'est pas fermée.

        C'est un peu faux mais dans les grandes lignes, c'est à peu près cela.

        • Partager sur Facebook
        • Partager sur Twitter
        Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
          31 janvier 2023 à 11:25:24

          Bonjour bacelar,

          Merci beaucoup d'avoir pris le temps de me répondre. On va opter pour la deuxième proposition, le coup de bâton était violent et il m'a fallu du temps pour m'en remettre. Je suis revenu lire la réponse plusieurs fois le temps de faire des recherches :) 

          Pour résumer c'est le Application.Run qui va maintenir l'application vivante, c'est bien ça ?

          Je pense avoir compris la majorité de ce qui a été dit plus haut, sauf pour l'histoire du kernel. Ca fonctionne un peu comme un Thread.Sleep dans une boucle while ?

          Et dernière question à quoi sert un Form.Show s'il n'est pas modal et disparait directement?

          • Partager sur Facebook
          • Partager sur Twitter
            31 janvier 2023 à 12:44:16

            >Pour résumer c'est le Application.Run qui va maintenir l'application vivante, c'est bien ça ?

            Application.Run fait une boucle qui attend des messages (boucle non active, l'OS permet d'attendre le prochain message sans monopoliser un CPU/Cœur).

            Le mouvement de la souris sur une fenêtre de l'application génère des messages.

            L'appui d'une touche quand l'application à le focus clavier génère des messages.

            Le changement de contrôle ayant le focus clavier génère des messages.

            etc... (les types de message se comptent par centaines)

            Donc, s'il n'y avait que cela, le processus tournerait indéfiniment jusqu'à un arrêt "violent" via l'OS.

            On n'a passé en paramètre de "Application.Run" une fenêtre.

            "Application.Run" va donc faire en sorte de quitter sa boucle quand cette fenêtre se ferme.

            (génération d'un message "WM_QUIT" qui fait sortir de la boucle)

            Quand on sort de la boucle, on sort de la méthode "Application.Run", on revient à la fonction Main et on continue le code, qui très souvent mène à la sortie de la fonction Main, donc la sortie du processus.

            Cette boucle, c'est ce que l'on nomme la "pompe à message", car elle "pompe" pour avoir le prochain message à traiter.

            >sauf pour l'histoire du kernel. Ca fonctionne un peu comme un Thread.Sleep dans une boucle while ?

            Et comment pensez-vous que fonctionne un "Thread.Sleep" ?

            Cela peut être une boucle active qui monopolise un CPU/Cœur qui sort une fois le délai écoulé (on appelle cela un SpinLock dans le jargon), c'est super précis mais ça crame un paquet de ressource (cycles CPU) pour rien.

            Cela peut aussi se faire en appelant une méthode spécifique(1) de l'OS (un appel système), qui figera le processus pendant le temps imparti (en n'allouant pas de CPU à ce processus, donc le processus est momentanément éjecté du CPU, jusqu'à ce que le scheduler de l'OS réveille le processus en lui allouant de nouveau un CPU/Cœur.

            Cela peut aussi se faire en appelant une méthode spécifique(2) de l'OS (un appel système), qui demande à l'OS d'envoyer un message WM_TIMER à une fenêtre particulière quand le délai sera expiré. Le processus n'est pas immédiatement éjecté du CPU mais va continuer de pomper les messages. Quand le processus demande le prochain message, c'est comme la méthode spécifique(1) d'avant, mais au lieu de donner un délai spécifique pour retrouver un CPU/Cœur, le processus sera "réveillé" quand il aura un message à traiter, qui peut être un WM_TIMER mais peut-être un autre type de message.

            Quand on fait un appel système dans les OS modernes, cela passe la main à un type de processus particulier : le Kernel, qui dispose de bien plus de fonctionnalités et de "pouvoir" que les autres binaires, dont la gestion de l'allocation des CPU à des processus, etc...

            Et comme dirait Uncle Ben (Spider-Man), de grands pouvoir impliquent de grandes responsabilités, donc, on ne programme pas un Kernel comme un programme "classique", dit UserMode.

            Il y a différentes classes Timer, donc différentes implémentations de la méthode Sleep, et chacune utilise vraisemblablement un des 3 mécanismes présentés plus haut, voire d'autres, en fonction de l'OS et de ses possibilités.

            >à quoi sert un Form.Show s'il n'est pas modal et disparait directement?

            Je ne suis pas sûr de comprend la question.

            La méthode "Show" d'un objet "Form", ça sert à afficher la fenêtre correspondant à l'objet sur l'écran du moniteur/bureau. Et c'est déjà pas mal. ;-°

            Bon, je taquine un peu.

            Exactement comme "ShowDialog" modifie le traitement des messages pour que quasiment tous passent de la pompe vers les routines de la fenêtre et donc impose son caractère modal ; "Show" modifie le traitement des messages MAIS pour que seul les messages qui concernent la fenêtre ou un des contrôle/sous-fenêtre qu'elle contient/possède (comme pour les events en Javascript dans un navigateur ou avec WPF, il y a une double hiérarchie des fenêtres dans l'OS Windows) sont routés vers les routines de la fenêtre, donc pas de caractère modal.

            -
            Edité par bacelar 31 janvier 2023 à 12:45:15

            • Partager sur Facebook
            • Partager sur Twitter
            Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.

            Explication attente interaction utilisateur

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown