web-dev-qa-db-fra.com

Qu'est-ce qu'une pompe à messages?

Dans ce fil (posté il y a environ un an), il y a une discussion sur les problèmes qui peuvent survenir lors de l'exécution de Word dans une session non interactive. Le conseil (assez fort) qui y est donné n'est pas de le faire. Dans un article, il est indiqué: "Les API Office supposent toutes que vous exécutez Office dans une session interactive sur un bureau, avec un moniteur, un clavier et une souris et, surtout, une pompe de messages." Je ne sais pas ce que c'est. (Je ne programme en C # que depuis environ un an; mon autre expérience de programmation a été principalement avec ColdFusion.)

Mise à jour:

Mon programme parcourt un grand nombre de fichiers RTF pour extraire deux informations utilisées pour construire un numéro de rapport médical. Plutôt que d'essayer de comprendre comment les instructions de formatage dans RTF travail, j'ai décidé de simplement les ouvrir dans Word et de retirer le texte à partir de là (sans réellement démarrer l'interface graphique). Parfois, le programme a hoqueté au milieu du traitement d'un fichier et laissé un thread Word ouvert attaché à ce document (je dois encore trouver comment l'arrêter). Lorsque j'ai relancé le programme, bien sûr, j'ai reçu une notification indiquant qu'un thread utilisait ce fichier, et est-ce que je voulais ouvrir un fichier en lecture seule Quand j'ai dit oui, l'interface graphique Word est soudainement apparue de nulle part et a commencé à traiter les fichiers. bien?

94
Matt Gutting

Une boucle de message est un petit morceau de code qui existe dans n'importe quel programme Windows natif. Cela ressemble à peu près à ceci:

MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{ 
   TranslateMessage(&msg); 
   DispatchMessage(&msg); 
} 

L'API WinMessage () Win32 récupère un message de Windows. Votre programme y passe généralement 99,9% de son temps, en attendant que Windows lui annonce que quelque chose d'intéressant s'est produit. TranslateMessage () est une fonction d'assistance qui traduit les messages du clavier. DispatchMessage () garantit que la procédure de fenêtre est appelée avec le message.

Chaque programme .NET activé par GUI a une boucle de message, elle est démarrée par Application.Run ().

La pertinence d'une boucle de messages pour Office est liée à COM. Les programmes Office sont des programmes compatibles COM, c'est ainsi que fonctionnent les classes Microsoft.Office.Interop. COM prend en charge le threading au nom d'une coclasse COM, il garantit que les appels effectués sur une interface COM sont toujours effectués à partir du thread correct. La plupart des classes COM ont une clé de registre dans le registre qui déclare que leur ThreadingModel, de loin les plus courantes (y compris Office) utilisent "Apartment". Ce qui signifie que le seul moyen sûr d'appeler une méthode d'interface consiste à effectuer l'appel à partir du même thread qui a créé l'objet classe. Ou pour le dire autrement: de loin la plupart des classes COM ne sont pas thread-safe.

Chaque thread compatible COM appartient à un appartement COM. Il existe deux types: les appartements à thread unique (STA) et les appartements à thread multiple (MTA). Une classe COM à thread cloisonné doit être créée sur un thread STA. Vous pouvez le voir dans les programmes .NET, le point d'entrée du thread d'interface utilisateur d'un programme Windows Forms ou WPF a l'attribut [STAThread]. Le modèle de cloisonnement pour les autres threads est défini par la méthode Thread.SetApartmentState ().

De grandes parties de la plomberie Windows ne fonctionneront pas correctement si le fil d'interface utilisateur n'est pas STA. Notamment Drag + Drop, le presse-papiers, les boîtes de dialogue Windows comme OpenFileDialog, les contrôles comme WebBrowser, les applications UI Automation comme les lecteurs d'écran. Et de nombreux serveurs COM, comme Office.

Une exigence difficile pour un thread STA est qu'il ne doit jamais bloquer et doit pomper une boucle de message. La boucle de message est importante car c'est ce que COM utilise pour marshaler un appel de méthode d'interface d'un thread à un autre. Bien que .NET facilite le marshaling des appels (Control.BeginInvoke ou Dispatcher.BeginInvoke par exemple), c'est en fait une chose très délicate à faire. Le thread qui exécute l'appel doit être dans un état bien connu. Vous ne pouvez pas interrompre arbitrairement un thread et le forcer à effectuer un appel de méthode, ce qui provoquerait d'horribles problèmes de ré-entrée. Un thread doit être "inactif", pas occupé à exécuter un code qui mute l'état du programme.

Peut-être pouvez-vous voir où cela mène: oui, lorsqu'un programme exécute la boucle de message, il est inactif. Le marshaling réel a lieu à travers une fenêtre cachée que COM crée, il utilise PostMessage pour que la procédure de fenêtre de cette fenêtre exécute le code. Sur le fil STA. La boucle de message garantit que ce code s'exécute.

170
Hans Passant

La "pompe à messages" est un élément central de tout programme Windows qui est responsable de l'envoi des messages de fenêtrage aux différentes parties de l'application. C'est le cœur de la programmation de l'interface utilisateur Win32. En raison de son omniprésence, de nombreuses applications utilisent la pompe à messages pour passer des messages entre différents modules, c'est pourquoi les applications Office se cassent si elles sont exécutées sans interface utilisateur.

Wikipedia a un description de base .

11
JSBձոգչ

John parle de la façon dont le système Windows (et d'autres systèmes basés sur les fenêtres - X Window , Mac OS d'origine ...) implémentent des interfaces utilisateur asynchrones en utilisant des événements via un système de messagerie.

Dans les coulisses de chaque application, il y a un système de messagerie où chaque fenêtre peut envoyer des événements à d'autres fenêtres ou écouteurs d'événements - ceci est implémenté en ajoutant un message à la file d'attente de messages. Il existe une boucle principale qui s'exécute toujours en regardant cette file d'attente de messages, puis en distribuant les messages (ou événements) aux écouteurs.

L'article Wikipedia Boucle de message dans Microsoft Windows montre un exemple de code d'un programme Windows de base - et comme vous pouvez le voir sur le le niveau le plus élémentaire d'un programme Windows n'est que la "pompe à messages".

Donc, pour tout rassembler. La raison pour laquelle un programme Windows conçu pour prendre en charge une interface utilisateur ne peut pas agir en tant que service est qu'il a besoin que la boucle de message soit exécutée en permanence pour activer la prise en charge de l'interface utilisateur. Si vous l'implémentez en tant que service comme décrit, il ne pourra pas traiter la gestion des événements asynchrones internes.

6
Hogan

Dans COM , une pompe à messages sérialise et désérialise les messages envoyés entre les appartements. Un appartement est un mini processus dans lequel les composants COM peuvent être exécutés. Les appartements sont disponibles en modes à filetage simple et à filetage libre. Les appartements à thread unique sont principalement un système hérité pour les applications de composants COM qui ne prennent pas en charge le multithread. Ils étaient généralement utilisés avec Visual BASIC (car cela ne prenait pas en charge le code multithread) et les applications héritées.

Je suppose que l'exigence de pompe de message pour Word provient de l'API COM ou de parties de l'application qui ne sont pas thread-safe. Gardez à l'esprit que les modèles de threading et de récupération de place . NET ne fonctionnent pas bien avec COM hors de la boîte. COM a un mécanisme de récupération de place et un modèle de thread très simplistes qui vous obligent à faire les choses à la manière de COM. L'utilisation de la norme Office PIA vous oblige toujours à fermer explicitement les références aux objets COM, vous devez donc suivre chaque poignée COM créée. Les PIA créeront également des éléments dans les coulisses si vous ne faites pas attention.

L'intégration .NET-COM est un sujet à part entière, et il y a même des livres écrits sur le sujet. Même en utilisant les API COM pour Office à partir d'une application de bureau interactive, vous devez parcourir les cadres et vous assurer que les références sont explicitement publiées.

On peut supposer qu'Office n'est pas sûr pour les threads, vous aurez donc besoin d'une instance distincte de Word, Excel ou d'autres applications Office pour chaque thread. Vous devrez encourir la surcharge de démarrage ou maintenir un pool de threads. Un pool de threads devra être méticuleusement testé pour s'assurer que toutes les références COM ont été correctement libérées. Même le démarrage et l'arrêt d'instances nécessitent que vous vous assuriez que toutes les références sont correctement libérées. Si vous ne faites pas de point sur vos i et ne croisez pas vos t ici, un grand nombre d'objets COM morts et même des instances en cours de Word seront divulgués.

Wikipedia suggère que cela signifie que le programme boucle d'événement principal .

2
Vince Bowdren

Je pense que cette discussion de Channel 9 a une belle explication succincte:

Ce processus de communication par fenêtre est rendu possible par ce que l'on appelle la pompe à messages Windows. Considérez la pompe à messages comme une entité qui permet la coopération entre les fenêtres d'application et le bureau.

0
Richard Everett