У меня есть приложение C # Windows Form, которое использует C ++ DLL. Внутри DLL я инициализирую COM:
auto hResult = CoInitialize(NULL); // Initialize COM
if (hResult != S_OK && hResult != S_FALSE) {
WSACleanup();
return 1;
}
Когда я запускаю DLL вне процесса BackgroundWorker, все работает нормально. Однако, если я это сделаю, мое приложение зависнет, когда DLL будет завершена. Итак, я пытаюсь использовать BackgroundWorker; но всякий раз, когда я запускаю DLL внутри функции DoWork, я не могу инициализировать COM.
Может кто-нибудь объяснить это, пожалуйста, и предложить какие-либо предложения о том, как запустить мою DLL в BackgroundWorker?
Спасибо.
BackgroundWorker
использует потоки пула потоков. Потоки потоков .NET автоматически инициализируются в MTA (CoInitializeEx(NULL, COINIT_MULTITHREADED)
). Ваша DLL пытается инициализировать поток в STA (CoInitialize()
), и этот звонок должен возвращаться RPC_E_CHANGED_MODE
, Это провал.
Как правило, я бы не инициализировал COM в вызывающей ветке из библиотеки. Я бы посчитал это антипаттерном. Несколько клиентских приложений могут использовать несколько библиотек, и каждая из этих библиотек может (попытаться) инициализировать COM. Лучшим вариантом было бы, чтобы владелец каждого потока инициализировал COM в этом потоке. Ваше клиентское приложение будет инициализировать COM для основного потока и любых фоновых потоков, которыми он владеет (.NET сделает все это за вас). Каждая библиотека будет указывать (в документации) требования к потокам / апартаментам для своих точек входа (например, «Эта DLL FooExport
Функция должна вызываться из потока STA. «). Потоки, принадлежащие библиотеке, будут иметь состояние квартиры, контролируемое библиотекой. Единственное реальное преимущество для вызова CoInitialize/Ex
внутри библиотеки нужно попытаться определить состояние квартиры, в которой находится ваш поток, чтобы программные требования к квартире были проверены программно, но есть некоторые сценарии (квартиры с нейтральной резьбой), в которых это становится проблематичным.
По вашему сценарию:
SetApartmentState
). Также рассмотрите возможность удаления CoInitialize
позвони в свою библиотеку.CoInitialize
позвоните из вашей DLL или используйте CoInitializeEx(NULL, COINIT_MULTITHREADED)
,Других решений пока нет …