Безопасно ли использовать COM Callable Wrapper, чтобы избежать проблем при передаче GCHandles через домены приложений?
В.NET существует относительно хорошо известная проблема хранения управляемых объектов в неуправляемом коде как gcroot<ManagedObject>
обеспечить обратные вызовы из неуправляемого кода: неуправляемый код не знает, какой AppDomain использовать при обращении к управляемому коду, и иногда он выбирает неправильный код, что приводит к ошибкам "Невозможно передать GCHandle через AppDomains".
Стандартное решение проблемы - использование указателя на функцию для делегата, поскольку делегат можно использовать для "запоминания" правильного домена приложения: см. http://lambert.geek.nz/2007/05/29/unmanaged-appdomain-callback/ для полного объяснения.
Однако это решение немного сложнее и требует тщательного управления временем жизни Delgate.
Кажется, что использование COM Callable Wrapper для управляемого объекта работает так же хорошо: вместо сохранения gcroot<ManagedObject>
сохранить указатель как IUnknown *
с помощью GetIUnknownForObject
:
m_value =
static_cast<IUnknown*> (Marshal::GetIUnknownForObject(value).ToPointer());
Тогда мы можем сделать обратный перевод с GetObjectForIUnknown
прежде чем сделать обратный звонок. Недостатком является потеря безопасности типа, потому что IUnknown *
теряет фактический тип объекта, и вам позже придется снизить, используя что-то вроде
IDisposable^ value =
(IDisposable^) (Marshal::GetObjectForIUnknown(IntPtr(m_value)));
где m_value
это IUnknown*
, но это кажется небольшой ценой.
Я попробовал это, и, кажется, работает нормально в моем случае использования, но есть ли какие-то ошибки с таким подходом? Кажется, что это применимо везде, где можно использовать делегатское решение, поэтому мне интересно, что я что-то упустил из этого.
1 ответ
Сейчас я использую этот подход в производстве в течение нескольких месяцев без каких-либо проблем, о которых сообщалось, поэтому, хотя он не является окончательным, я хочу сделать предварительный вывод, что этот подход является безопасным.