Цикл сообщений - это небольшой фрагмент кода, который существует в любой собственной программе Windows. Примерно это выглядит так:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Win32 API GetMessage () получает сообщение из Windows. Ваша программа обычно проводит там 99,9% времени, ожидая, пока Windows сообщит ей о том, что произошло что-то интересное. TranslateMessage () - это вспомогательная функция, которая переводит сообщения клавиатуры. DispatchMessage () гарантирует, что оконная процедура вызывается с сообщением.
Каждая программа .NET с графическим интерфейсом пользователя имеет цикл сообщений, который запускается Application.Run ().
Значение цикла сообщений для Office связано с COM. Программы Office - это программы с поддержкой COM, вот как работают классы Microsoft.Office.Interop. COM заботится о потоковой передаче от имени компонентного класса COM, он гарантирует, что вызовы, выполняемые в интерфейсе COM, всегда выполняются из правильного потока. У большинства классов COM есть раздел реестра в реестре, который объявляет их ThreadingModel, но наиболее распространенные (включая Office) используют «Apartment». Это означает, что единственный безопасный способ вызвать метод интерфейса - это сделать вызов из того же потока, который создал объект класса. Или, другими словами, большинство COM-классов не являются потокобезопасными.
Каждый поток с поддержкой COM принадлежит COM-апартаменту. Есть два типа: однопоточные (STA) и многопоточные (MTA). В потоке STA должен быть создан отдельный поток COM-класса. Вы можете увидеть это еще в программах .NET, точка входа потока пользовательского интерфейса программы Windows Forms или WPF имеет атрибут [STAThread]. Модель квартиры для других потоков задается методом Thread.SetApartmentState ().
Большие части сантехники Windows не будут работать правильно, если поток пользовательского интерфейса не является STA. В частности, Drag + Drop, буфер обмена, диалоговые окна Windows, такие как OpenFileDialog, элементы управления, такие как WebBrowser, приложения автоматизации пользовательского интерфейса, такие как программы чтения с экрана. И многие COM-серверы, такие как Office.
Жесткое требование к потоку STA состоит в том, что он никогда не должен блокироваться и должен перекачивать цикл сообщений. Цикл сообщений важен, потому что это то, что COM использует для маршалинга вызова метода интерфейса из одного потока в другой. Хотя .NET упрощает маршалинг вызовов (например, Control.BeginInvoke или Dispatcher.BeginInvoke), на самом деле это очень сложная задача. Поток, выполняющий вызов, должен находиться в хорошо известном состоянии. Вы не можете просто произвольно прервать поток и заставить его выполнить вызов метода, что могло бы вызвать ужасные проблемы с повторным входом. Поток должен быть «простаивающим», не занятым выполнением какого-либо кода, изменяющего состояние программы.
Возможно, вы видите, к чему это ведет: да, когда программа выполняет цикл сообщений, она простаивает. Фактический маршалинг происходит через скрытое окно, которое создает COM, он использует PostMessage, чтобы оконная процедура этого окна выполняла код. В ветке STA. Цикл сообщений обеспечивает выполнение этого кода.