"COM-объект, который был отделен от лежащего в его основе RCW, нельзя использовать" с.NET 4.0
У меня есть класс в моем приложении.NET 3.5 C# WinForms, который имеет пять методов. Каждый метод использует различные наборы COM-интерфейсов C++. Использую Marshal.FinalReleaseCOMObject
для очистки этих объектов COM. Этот код прекрасно работает на этой платформе.NET без каких-либо проблем. Но когда я перемещаю это приложение в.NET 4.0, я начинаю получать эту ошибку в одном из этих методов в строке, где я приводил переменную из ICOMInterface1
в ICOMInterface2
т.е.
ICOMInterface1 myVar= obj as ICOMInterface2;
COM-объект, который был отделен от базового RCW, не может быть использован.
И если я уберу строку, где использую Marshal.FinalReleaseCOMObject
Я не получаю эту ошибку.
Что мне здесь не хватает? И как мне очистить эти неуправляемые COM-объекты из памяти на платформе.NET 4.0?
1 ответ
Простой ответ - никогда не использовать Marshal.FinalReleaseComObject
если вы абсолютно не должны. И если вы делаете, есть некоторые дополнительные правила, которые вы должны соблюдать.
Когда COM-объект используется в.NET, среда выполнения создает для этого объекта так называемую "вызываемую оболочку во время выполнения" или "вызываемую оболочку времени выполнения". Это RCW - просто обычный объект, который содержит ссылку COM на объекте. Когда этот объект собирается мусором, он вызовет IUnknown::Release() для COM-объекта, как и следовало ожидать. Это означает, что если ваш COM-объект не требует, чтобы последний Release () выполнялся в определенный момент времени, просто позвольте сборщику мусора позаботиться об этом. Многие COM-объекты попадают в этот случай, поэтому убедитесь, что вы должны тщательно управлять вызовом Release ().
Поэтому, когда вы вызываете FinalReleaseComObject, это по существу уменьшает ссылку, которую RCW имеет на COM-объект, пока он не достигнет нуля, а RCW затем освободит COM-объект. На данный момент этот RCW теперь зомбирован, и любое его использование даст исключение, которое вы видели. CLR (по умолчанию) создает только один RCW для любого нижележащего COM-объекта, так что это означает, что если используемый вами COM-API возвратил один и тот же объект дважды, он просто будет иметь один RCW. Вызов FinalReleaseComObject будет означать, что внезапно все виды использования этого RCW станут тостом.
Единственный способ гарантировать, что у вас есть уникальный Marshal.GetUniqueObjectForIUnknown, который предотвращает любой обмен RCW. Но, как я уже говорил ранее, в большинстве COM API это не обязательно делать в первую очередь, поэтому просто не делайте этого.
Пол Харрингтон написал хороший пост в блоге о [Final]ReleaseComObject, и это зло. Это опасное оружие, которое, если не понадобится, только навредит вам. Так как вы задаете этот вопрос, я подозреваю, что вам вообще не нужно звонить.:-)