Що таке насос для повідомлень?


104

У цій темі (опублікованій близько року тому) йде обговорення проблем, які можуть виникнути із запуском Word у неінтерактивній сесії. Дана там (досить сильна) порада цього не робити. В одному дописі зазначено, що "API API припускають, що ви працюєте з Office в інтерактивному сеансі на робочому столі, з монітором, клавіатурою та мишею і, головне, - насосом повідомлень". Я не впевнений, що це таке. (Я програмував на C # лише рік; мій інший досвід програмування в основному був із ColdFusion.)

Оновлення:

Моя програма проходить через велику кількість RTF-файлів, щоб витягти два фрагменти інформації, що використовуються для складання номера медичного звіту. Замість того, щоб спробувати і зрозуміти, як працюють інструкції щодо форматування в RTF, я вирішив просто відкрити їх у Word і витягнути текст звідти (не фактично запускаючи графічний інтерфейс). Іноді програма ігнорувала в середині обробки одного файлу і залишала відкритим потік Word, приєднаний до цього документа (я все ще мушу розібратися, як його закрити). Коли я повторно запустив програму, звичайно, мені надійшло повідомлення про те, що за допомогою цього файлу була нитка, і чи хотів я відкрити копію лише для читання? Коли я сказав «Так», графічний інтерфейс Word раптом з’явився з нізвідки і почав обробляти файли. Мені було цікаво, чому так сталося;


3
Чому це позначено як win32? - Система повідомлень була у Windows V1 (Що, як я пам’ятаю, було 8 біт.)
Хоган

Відповіді:


187

Цикл повідомлень - це невеликий фрагмент коду, який існує в будь-якій рідній програмі 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. Цикл повідомлень забезпечує виконання цього коду.


Дуже приємна і детальна відповідь. Додамо лише - є також спеціальний STA, який називається головним STA, який є першим створеним STA. Що в ідеалі має бути таким, створеним вашим потоком інтерфейсу користувача. Основна STA - це те, де компоненти з нарізною моделлю = жодна не створюються. Якщо ваша основна STA - це не та, створена вашим потоком інтерфейсу користувача - ви можете зіткнутися з цікавими проблемами, використовуючи старі елементи управління ActiveX, які не мають нитки моделей.
Кіксвер

12

"Насос повідомлень" є основною частиною будь-якої програми Windows, яка відповідає за пересилання віконних повідомлень у різні частини програми. Це ядро ​​програмування інтерфейсу Win32. Через свою всюдисущість багато програм використовують насос повідомлень для передачі повідомлень між різними модулями, через що програми Office порушуються, якщо вони запускаються без будь-якого інтерфейсу.

У Вікіпедії є основний опис .


Я вважаю, що неможливо написати додаток для Windows без циклу повідомлень, тому всі програми використовують насос для повідомлень.
Хоган

2
Ви також можете писати прості програми GUI без жодного - наприклад, ви можете спливати вікна повідомлень, не маючи у вашому додатку циклу повідомлень.

Якщо ви створюєте діалогове вікно через DialogBox або DialogBox непрямим - вам не потрібен цикл повідомлень, вам просто потрібно надати функцію (dlgproc), яка буде викликана вікнами. (а поле повідомлень - це просто простий діалог)
quixver

6

Джон розповідає про те, як система Windows (та інші системи на основі вікон - X Window , оригінальна Mac OS ....) реалізують асинхронний інтерфейс користувача, використовуючи події через систему повідомлень.

За лаштунками для кожної програми є система обміну повідомленнями, де кожне вікно може пересилати події до інших вікон або слухачів подій - це реалізується шляхом додавання повідомлення до черги повідомлень. Є головний цикл, який завжди працює, дивлячись на цю чергу повідомлень, а потім розсилає повідомлення (або події) слухачам.

Стаття Вікіпедії Цикл повідомлень у Microsoft Windows показує приклад коду основної програми Windows - і як ви бачите на самому базовому рівні, програма Windows - це лише "насос повідомлень".

Отже, зібрати все це разом. Причина, що програма Windows, призначена для підтримки інтерфейсу користувача, не може діяти як послуга, полягає в тому, що їй потрібен цикл повідомлень, який працює весь час, щоб увімкнути підтримку інтерфейсу користувача. Якщо ви реалізуєте його як послугу, як описано, вона не зможе обробити внутрішню асинхронну обробку подій.


6

У COM повідомленні насос серіалізує та де-серіалізує повідомлення, що надсилаються між квартирами. Квартира - це міні-процес, в якому можна запускати компоненти COM. Квартири оснащені режимами з однопотоковою та вільною різьбою. Однопоточні квартири - це в основному застаріла система для застосувань компонентів COM, які не підтримують багатопотоковість. Вони зазвичай використовуються для Visual BASIC (оскільки це не підтримує багатопотоковий код) та застарілих додатків.

Я здогадуюсь, що потреба в насосі для повідомлення для Word випливає або з COM-API, або з частини програми, яка не є безпечною для потоків. Майте на увазі, що моделі .NET для різьблення та вивезення сміття не грають добре із COM-кодом поза коробкою. COM має дуже спрощений механізм збору сміття та нарізання різьби, яка вимагає від вас робити речі COM. Використання стандартних службових протоколів Office все ще вимагає від вас явно закрити посилання COM-об’єктів, тому вам слід слідкувати за кожною створеною ручкою COM. PIA також створюватимуть речі за лаштунками, якщо ви не будете обережні.

Інтеграція .NET-COM - це ціла тема сама по собі, і навіть є книги, написані на цю тему. Навіть використовуючи COM-API для Office з інтерактивного настільного додатку, потрібно перестрибнути обручі та переконатися, що посилання явно випущені.

Office можна вважати небезпечним для потоків, тому вам знадобиться окремий екземпляр Word, Excel або інші програми Office для кожного потоку. Вам доведеться здійснити стартову накладну або підтримувати пул потоків. Пул потоків повинен бути ретельно перевірений, щоб переконатися, що всі посилання COM були правильно видані. Навіть запуску та вимкнення екземплярів вимагає переконатися, що всі посилання видані правильно. Якщо не поставити крапку у вашій точці та перетнути сюди, це призведе до витоку великої кількості мертвих об’єктів COM та навіть цілих запущених екземплярів Word.


1
У вашій відповіді є кілька неточностей. Існує 3 типи квартир - STA (Однопоточна), MTA (Multi-Threeded) та NTA (Neutral Threeded). Безкоштовна різьба використовується для опису компонента, який агрегує безкоштовний різьбовий механізм з різьбленням, немає такого поняття, як вільний набір різьблення. COM використовує повідомлення для спілкування з STA. Для компонентів, що живуть у MTA (або які об'єднують вільний потоковий маршалер), петлі повідомлень не потрібні. AFAIK - lpc використовується для зведення даних від виклику потоку до потоку з пулу потоків RPC, який потім фактично викликає метод.
Кіксвер


0

Я думаю, що ця дискусія 9 каналу має приємне пояснення:

Цей процес спілкування у вікні стає можливим завдяки так званому Windows Message Pump. Подумайте про Pump Message як про сутність, яка дозволяє співпрацювати між вікнами програми та робочим столом.


2
ух ... це жахлива та оманлива цитата. ("Сутність"? Помилка .. ні.)
Хоган

4
сутність - об'єкт: щось, що існує як або сприймається як окремий окремий об'єкт encarta.msn.com/dictionary_1861608661/entity.html
Матвій Віт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.