COM-объект, который был отделен от его базового RCW, не может быть использован
Я пытаюсь использовать OpcRcw.da.dll. Если я вмешиваюсь в эту DLL внутри тестового консольного проекта, все работает, но если я создам проект dll для выполнения моей интерактивной гимнастики и верну свою библиотеку в свой консольный проект, я получаю эту ошибку:
COM-объект, который был отделен от его базового RCW, не может быть использован.
Что нужно сделать для проекта класса lib, чтобы не убить RCW ref?
Ответы
Ответ 1
Несколько сложно сказать, что делает ваше фактическое приложение, но похоже, что вы можете создавать экземпляр COM-объекта, а затем пытаться получить к нему доступ из другого потока, возможно, в событие Timer.Elapsed. Если ваше приложение многопоточно, вам нужно создать экземпляр COM-объекта в каждом потоке, в котором вы его будете использовать.
Ответ 2
Это может произойти по нескольким причинам, большие из которых я знаю ниже.
Обработчики событий без сильных ссылок на делегата
Вызывающий абонент подписывается на событие на com-объекте, не сохраняя ссылки на делегат обратного вызова. Вот пример того, как это сделать правильно и как не делать этого:
Причина этого - сильная ссылка должна быть удержана делегату, если она выходит за пределы области действия, оболочка освободит счетчик ссылок для интерфейса, и произойдет что-то плохое.
public class SomeClass
{
private Interop.ComObjectWrapper comObject;
private event ComEventHandler comEventHandler;
public SomeClass()
{
comObject = new Interop.ComObjectWrapper();
// NO - BAD!
comObject.SomeEvent += new ComEventHandler(EventCallback);
// YES - GOOD!
comEventHandler = new ComEventHandler(EventCallback);
comObject.SomeEvent += comEventHandler
}
public void EventCallback()
{
// DO WORK
}
}
Вызовы к утилизированному оберточному устройству Runtime
Обертка была удалена, и вызовы выполняются после ее удаления. Обычно это может произойти, если элемент управления использует элемент управления activex или COM-объект, а элементы управления Dispose() выходят из строя.
- Форма вызывает Close().
- System.Windows.Forms.Close() вызовет Dispose()
- Будут вызываться ваши формы virtual Dispose(), которые, надеюсь, назовут base.Dispose() где-нибудь. Systems.Windows.Forms.Dispose() освободит все COM-объекты и синхронизацию событий в форме, даже с дочерних элементов управления.
- Если элемент управления, которому принадлежит com-объект, явно удаляется после base.Dispose(), и если он вызывает какие-либо методы на нем COM-объекте, они будут терпеть неудачу, и вы получите сообщение об ошибке "COM-объект, который был отделен от его базовый RCW не может быть использован".
Шаги отладки
Хорошим способом отладки этой проблемы является выполнение следующих действий:
- Напишите класс, который наследуется от класса Interop (иначе известный как оболочка, вызываемая вызовом или RCW).
- Отменить DetachEventSink
- Переопределить Dispose
- Вызов нового класса вместо прямого вызова класса interop
- Добавить точку останова для DetachEventSink и Dispose
- Посмотрите, кто нарушает порядок этих методов.
Еще одна вещь
Это не связано с этой проблемой, но пока мы находимся на этой теме, если вы не знаете иначе, всегда помните, чтобы проверить, что поток, который использует COM-объекты, отмечен STA. Вы можете сделать это, взломав отладчик и проверив возвращаемое значение:
Thread.CurrentThread.GetApartmentState();