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 Win32 GetMessage () récupère un message de Windows. Votre programme y passe généralement 99,9% de son temps à attendre que Windows lui dise 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 l'interface graphique a une boucle de message, il est démarré par Application.Run ().
La pertinence d'une boucle de message 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 s'occupe du threading pour le compte 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 leur ThreadingModel, de loin les plus courants (y compris Office) utilisent "Appartement". Ce qui signifie que le seul moyen sûr d'appeler une méthode d'interface est de faire l'appel depuis le même thread qui a créé l'objet de classe. Ou pour le dire autrement: de loin, la plupart des classes COM ne sont pas thread-safe.
Chaque thread compatible COM appartient à un cloisonnement COM. Il existe deux types, les appartements à un seul filetage (STA) et un appartement à plusieurs threads (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 d'appartement 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 filetage de l'interface utilisateur n'est pas STA. Notamment Drag + Drop, le presse-papiers, les boîtes de dialogue Windows comme OpenFileDialog, des contrôles comme WebBrowser, des applications UI Automation comme des lecteurs d'écran. Et de nombreux serveurs COM, comme Office.
Une exigence absolue pour un thread STA est qu'il ne doit jamais se 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 connu. Vous ne pouvez pas simplement interrompre arbitrairement un thread et le forcer à faire un appel de méthode, ce qui causerait d'horribles problèmes de rentrée. Un thread doit être "inactif", pas occupé à exécuter un code qui modifie l'état du programme.
Vous pouvez peut-être voir où cela mène: oui, lorsqu'un programme exécute la boucle de message, il est inactif. Le marshaling réel a lieu via une fenêtre masquée créée par COM, 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.