Цикл повідомлень - це невеликий фрагмент коду, який існує в будь-якій рідній програмі Windows. Це приблизно так:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
API GetMessage () Win32 отримує повідомлення з Windows. Ваша програма зазвичай проводить там 99,9% свого часу, чекаючи, коли Windows скаже, що трапилось щось цікаве. TranslateMessage () - це допоміжна функція, яка перекладає повідомлення клавіатури. DispatchMessage () забезпечує виклик процедури вікна із повідомленням.
Кожна програма з підтримкою GUI .NET має цикл повідомлень, її запускає Application.Run ().
Відповідність циклу повідомлень для Office пов'язана з COM. Офісні програми - це програми з підтримкою COM, саме так працюють класи Microsoft.Office.Interop. COM піклується про введення потоків від імені COM-класу, він забезпечує, щоб дзвінки, здійснені через COM-інтерфейс, завжди здійснювалися з правильної нитки. Більшість класів COM мають у реєстрі ключ реєстру, який оголошує їхню ThreadingModel, на сьогоднішній день найпоширеніші з них (включаючи Office) використовують "Квартиру". Що означає, що єдиний безпечний спосіб викликати метод інтерфейсу - це зробити виклик з тієї ж нитки, що створила об’єкт класу. Або кажучи інакше: на сьогоднішній день більшість COM-класів не є безпечними для потоків.
Кожен потік із підтримкою COM належить до квартири COM. Існує два види, одномісні квартири (STA) та багаторічна квартира (MTA). COM-клас з різьбленням COM повинен бути створений на нитці STA. Це можна побачити ще в програмах .NET, точка входу потоку інтерфейсу інтерфейсу Windows Forms або WPF має атрибут [STAThread]. Модель квартири для інших потоків встановлюється методом Thread.SetApartmentState ().
Велика частина сантехніки Windows не буде працювати належним чином, якщо потік інтерфейсу не є STA. Зокрема, перетягування та падіння, буфер обміну, діалогові вікна Windows, такі як OpenFileDialog, такі елементи управління, як WebBrowser, програми автоматичного інтерфейсу, як читачі екранів. І багато COM-серверів, таких як Office.
Важкою вимогою до потоку STA є те, що він ніколи не блокується і повинен перекачувати цикл повідомлень. Цикл повідомлень важливий, оскільки саме це COM використовує для маршалювання виклику методу інтерфейсу з одного потоку в інший. Незважаючи на те, що .NET спрощує виклики з марширування (наприклад, Control.BeginInvoke або Dispatcher.BeginInvoke), це насправді дуже складно зробити. Потік, який виконує виклик, повинен знаходитись у відомому стані. Ви не можете просто довільно перервати потік і змусити його здійснити виклик методу, що спричинить жахливі проблеми повторного вступу. Потік повинен бути "непрацюючим", не зайнятим виконанням будь-якого коду, який мутує стан програми.
Можливо, ви можете побачити, куди це веде: так, коли програма виконує цикл повідомлень, вона не працює. Фактичний розміщення відбувається через приховане вікно, яке створює COM, він використовує PostMessage для того, щоб процедура вікна цього вікна виконувала код виконання. На нитці STA. Цикл повідомлень забезпечує виконання цього коду.