ApartmentState для муляжів


120

Я просто виправив помилку за допомогою цього:

_Thread.SetApartmentState(ApartmentState.STA);

Тепер я хотів би зрозуміти, що це означає, і чому це працює!


1
Ця публікація може вам допомогти
Арсен Мкртчян

Відповіді:


236

COM - це великий батько .NET. У них було досить високі цілі, одна з речей, яку робить COM, але .NET повністю пропускає, забезпечує гарантії для класу нарізки. COM-клас може публікувати, які вимоги до різьби має. І інфраструктура COM гарантує, що ці вимоги виконуються.

Це повністю відсутнє в .NET. Ви можете використовувати об’єкт Queue <>, наприклад, у декількох потоках, але якщо ви не заблокуєтесь належним чином, у вашому коді буде неприємна помилка, яку важко діагностувати.

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

Є два види, STA (одномісна квартира) та MTA. Він визначений у виклику CoInitializeEx (), функції, яку повинен викликати будь-який потік, що робить щось із COM. CLR робить цей виклик автоматично кожного разу, коли він починає потік. Для головного потоку запуску вашої програми воно отримує значення, яке передається з атрибута [STAThread] або [MTAThread] у вашому методі Main (). За замовчуванням - MTA. Для потоків, які ви створюєте самі, це визначається вашим викликом до SetApartmentState (). За замовчуванням - MTA. Нитки нитки - це завжди MTA, які неможливо змінити.

У Windows багато коду, для якого потрібен STA. Примітними прикладами, які ви використовували б самі, є буфер обміну, перетягування та випадання та діалоги оболонок (наприклад, OpenFileDialog). І багато коду, який ви не можете бачити, як програми UI Automation і гачки для спостереження за повідомленнями. Жоден із цього коду не повинен бути безпечним для потоків, його автору було б дуже важко зробити його безпечним, не знаючи, в якій програмі він використовується. Відповідно, потік UI проекту WPF або Windows Forms завжди повинен бути STA для підтримки такого коду, як і будь-який потік, який створює вікно.

Обіцяння, яке ви даєте COM, що ваша нитка є STA, однак робить вимагатиме від вас слідувати за квартиру контракту однопотокового. Вони досить жорсткі, і ви можете отримати складність діагностувати проблеми при розриві договору. Вимоги полягають у тому, що ви ніколи не блокуєте потік протягом будь-якої кількості часу і прокачуєте цикл повідомлень. Останню вимогу відповідає нитка інтерфейсу користувача WPF або Winforms, але вам потрібно буде подбати про це самостійно, якщо ви створите свій власний потік STA. Поширена діагностика розриву договору - тупик.

У CLR є вбудована підтримка, яка підтримує ці вимоги btw, допомагаючи вам уникнути проблем. Оператор блокування та методи WaitOne () накачують цикл повідомлень, коли він блокується на потоці STA. Однак це стосується лише вимоги ніколи не блокуватись, вам все одно потрібно створити власний цикл повідомлень. Application.Run () у форматі WPF та Winforms.

Раніше я надіслав відповідь, яка містить більше деталей про важливість створення циклу повідомлень для підтримання COM. Ви знайдете повідомлення тут .


4
Відмінна відповідь! Помилка, яку я вирішив, була для потоку, який я створив для тривалого конструктора звітів, який використовував елементи керування WPF для складання частин звіту, так що це має сенс, хоча я не знаю, що в цій темі є цикл повідомлень .
Benjol

4
Мені серйозно довелося прочитати пост MSDN кілька разів, щоб зрозуміти це, Ваша відповідь дуже чітка і добре написана. Дякую!
ak3nat0n
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.