Мне нужно вызвать CoInitialize, прежде чем взаимодействовать с COM в .NET?

Я знаю, что требование COM, что каждый поток вызывает CoInitialize, прежде чем взаимодействовать с системой COM.

.NET предоставляет некоторые элементы, которые внутренне работают с потоками, например:

  • ThreadPool темы
  • асихронные делегаты (которые используют потоки пула потоков)
  • BackgroundWorker class (которые используют асинхронные делегаты (которые используют потоки пула потоков))
  • сборщик мусора
  • и многое другое! (то есть, например).

Если я собираюсь взаимодействовать с COM-объектом из потока, мне нужно сначала вызвать CoInitialize?

Я прошу, потому что может быть какая-то больше магии, которая автоматически вызывает это для меня - я не знаю.


Чтение бонусов

Управляемые и неуправляемые потоки

Взаимодействие, общая среда выполнения языка создает и инициализирует квартиру при вызове COM-объекта. Управляемая нить может создавать и вводить однопоточную квартиру (STA), которая содержит только один поток или многопоточная квартира (MTA), которая содержит один или больше потоков. Когда COM-квартира и потолочная квартира совместимы, COM позволяет вызывающему потоку совершать вызовы напрямую к COM-объекту. Если квартиры несовместимы, COM создает совместимые квартиры и маршалы все звонки через прокси в новом квартира.

Время выполнения вызывает CoInitializeEx для инициализации COM-квартиры как либо MTA, либо квартира STA.

Обновить два:

Похоже, вы не должны использовать COM из любого потока, который может предоставить .NET:

Пул управляемых потоков

Существует несколько сценариев, в которых управляйте своими потоками вместо потоков потоков потоков:

  • Вам нужна передняя часть.

  • Для потока требуется определенный приоритет.

  • У вас есть задачи, которые заставляют поток блокировать длительные периоды время. Пул потоков имеет максимальное количество потоков, поэтому большой количество заблокированных потоков пула потоков может препятствовать выполнению задач из начиная.

  • Вам нужно разместить потоки в однопоточной квартире. Все Нити ThreadPool находятся в многопоточной квартире.

  • Вам нужно иметь устойчивое удостоверение, связанное с потоком, или посвятить поток заданию.

Обновить три:

Похоже, что вы можете установить модель потоков неименных потоков:

Управляемые и неуправляемые потоки в Microsoft Windows

Управляемый поток может быть помечен, чтобы указать, что он будет размещать однопоточную или многопоточную квартиру. GetApartmentState, SetApartmentState и TrySetApartmentState метода Thread возвратить класс и присвоить его состояние. Если состояние не установлено, GetApartmentState возвращает ApartmentState.Unknown.

Свойство может быть установлено только тогда, когда поток находится в состоянии ThreadState.Unstarted; он может быть установлен только один раз для потока.

Если состояние квартиры не установлено до начала потока, поток инициализируется как многопоточная квартира (MTA).

Много противоречивой информации.

Вот почему мы будем использовать то, что сказал парень из Stackoverflow как истинный ответ.

Ответ 1

Информация здесь не конфликтует - она ​​просто не обязательно супер понятна, если вы новичок в COM.

Короткий ответ:

  • .Net-потоки всегда для вас всегда соционированы - вам не нужно (и не должно!) называть это самостоятельно.
  • ThreadPool нити (и поэтому все, что использует потоки ThreadPool, такие как асинхронные делегаты и т.д.) всегда инициализируется MTA. Единственным вариантом для создания потока STA является либо добавление [STAThread] атрибут Main(), чтобы запросить, чтобы среда выполнения инициализировала основной поток как STA, или используя thread.SetApartmentState(ApartmentState.STA) по новому потоку, который вы создаете перед вызовом thread.Start() - в противном случае они являются MTA по умолчанию. В любом случае, модель нитечной квартиры не может быть изменена после запуска и запуска потока.

Более длинный ответ: есть два способа вызова CoInitialize - вы можете использовать его для инициализации потока в виде однопоточной резьбы (STA) или в виде многопоточной резьбы (MTA). В приведенном выше тексте говорится, что по умолчанию новые потоки и потоки нити-потока автоматически предварительно конитиализуются как MTA-аромат. Но с новой нитью вы можете использовать ApartmentState для указания STA-аромата, если вы это сделаете, прежде чем начинать поток. Он всегда CoInitialized так или иначе к тому времени, когда он начинался в любом случае.

Обратите внимание, что Main() в программах на основе UI отмечен атрибутом [STAThread], чтобы гарантировать, что он основан на STA; в то время как на консольном приложении отсутствие [STAThread] означает, что CoInited как MTA. Причина этого атрибута, кстати, в том, что поток, который вызывает Main(), является единственным потоком, который вы не можете указать STA vs MTA с помощью ApartmentState, потому что он уже запущен и к моменту выполнения Main(), так слишком поздно использовать это; поэтому подумайте об атрибуте как подсказке для среды выполнения, чтобы установить состояние квартиры до вызова Main().

Ключевым моментом, который следует знать, является то, что STA обычно используется с пользовательским интерфейсом и требует цикла сообщений (который предоставляет вам WinForms.Net); Код STA никогда не должен блокироваться с помощью Sleep() или аналогичного, иначе ваш пользовательский интерфейс также будет блокироваться. С другой стороны, MTA предназначен для использования работниками - например, фоновые задачи, загрузка файлов или выполнение вычислений в фоновом режиме, и, как правило, не должны владеть пользовательским интерфейсом. Вы можете использовать COM из любого из них, но это может зависеть от того, что делает объект COM или откуда вы его взяли. Если это компонент пользовательского интерфейса, вероятно, вы хотите использовать его из потока STA; с другой стороны, если это компонент для загрузки или выполнения вычислений, вы обычно используете его из потока MTA.

Обновление 1 выше в основном говорит о том, что время выполнения .Net всегда вызывает CoInitialize для вас, но позволяет выбрать STA vs MTA, при этом MTA является стандартным.

Обновление 2 выше в основном говорит о том, что поскольку потоки ThreadPool являются MTA (и вы не можете их изменить), вы должны использовать их только для выполнения фоновых операций и не использовать их для задач пользовательского интерфейса.

Обновление 3 говорит, что для новых потоков вы можете выбрать MTA vs STA - то же самое, что и обновление 1, просто более подробно описывая API.

Вся вещь MTA против STA может стать довольно сложной, предложите прочитать эту статью в качестве отправной точки. Большая картина, однако, в основном сводится к тому, что STA = одиночный поток и пользовательский интерфейс; MTA = несколько потоков, фоновые/рабочие задачи. (STA vs MTA также применяется к объектам, а не только к потокам, а COM выполняет целую кучу работы за кулисами, чтобы различные типы потоков использовали разные типы объектов. Когда это работает хорошо, вы этого не понимаете и может блаженно игнорировать его, но когда вы нажимаете ограничение или ограничение, часто бывает сложно определить, что происходит.)

Ответ 2

Чтобы ответить на ваш первый вопрос, если я правильно помню свой Дон-бокс, каждый поток ДОЛЖЕН называть CoInitialize. Нет исключений.

Что касается автоматной части, я понятия не имею.