Когда мне нужно вызвать Marshal.ReleaseComObject на интерфейсе, запрашиваемом через COM в C # - PullRequest
11 голосов
/ 23 февраля 2011

Я работал с некоторыми интерфейсами DirectShow для воспроизведения цифрового телевидения (DVB-T) с использованием C # и DirectShow.Net . Я недавно столкнулся с ошибкой во время выполнения COM object that has been separated from its underlying RCW cannot be used.

Эта ошибка произошла в следующей строке:

_guideData = _transportInformationFilter as IGuideData;

_transportInformationFilter имеет тип IBaseFilter, COM-объект, ранее назначенный с помощью служебной функции DirectShow.Net.

Я предположил, что ошибка произошла из-за преждевременного освобождения _transportInformationFilter, и я проследил ее до следующего метода (обработка ошибок удалена):

private void AttachGuideDataEvent()
{
    IConnectionPoint connPoint = null;
    IConnectionPointContainer connPointContainer = null;
    try
    {
        connPointContainer = _transportInformationFilter as IConnectionPointContainer;
        if (connPointContainer == null) /* error */

        var guideDataEventGuid = typeof (IGuideDataEvent).GUID;
        connPointContainer.FindConnectionPoint(ref guideDataEventGuid, out connPoint);
        if (connPoint == null) /* error */

        int cookie;
        connPoint.Advise(this, out cookie);
        if (cookie == 0) /* error */    
        _persistIGuideDataEventCookie = cookie;
    }
    finally
    {
        if (connPointContainer != null)
            Marshal.ReleaseComObject(connPointContainer);
        if (connPoint != null)
            Marshal.ReleaseComObject(connPoint);
    }
}

Как я понял, connPointContainer = _transportInformationFilter as IConnectionPointContainer должен был привести к вызову QueryInterface для _transportInformationFilter COM-объекта и, следовательно, должен был бы быть освобожден отдельно. Тем не менее, вызов Marshal.ReleaseComObject(connPointContainer) был виновником того, что _transportInformationFilter был отделен от своего RCW; удаление этого вызова решило проблему.

Учитывая это, в каких ситуациях мне необходимо явно освобождать COM-объекты (используя Marshal.ReleaseComObject) в C #, чтобы избежать утечки ресурсов?

Ответы [ 2 ]

11 голосов
/ 23 февраля 2011

Почти никогда.ReleaseComObject управляет счетчиком ссылок RCW, а не базового объекта и не является прямым аналогом IUnknown.Release.Вы должны позволить CLR управлять его QueryInterface 'ing и Release' ing.

RCW имеет счетчик ссылок, который увеличивается каждый раз, когда указатель COM-интерфейса сопоставляется с ним.Метод ReleaseComObject уменьшает счетчик ссылок RCW.Когда счетчик ссылок достигает нуля, среда выполнения освобождает все свои ссылки на неуправляемом COM-объекте и выдает исключение System.NullReferenceException, если вы пытаетесь использовать объект в дальнейшем.Если один и тот же интерфейс COM передается из неуправляемого кода в управляемый более одного раза, счетчик ссылок в оболочке увеличивается каждый раз, а вызов ReleaseComObject возвращает количество оставшихся ссылок.

...

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

С http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.releasecomobject.aspx

К вашему сведению, прямой вызов IUnknown.ReleaseMarshal.Release, а не ReleaseComObject.

6 голосов
/ 07 мая 2012

Я думаю, что нашел действительно законное обстоятельство для использования Marshal.ReleaseComObject. При написании надстроек Excel на C # с использованием ExcelDNA я склоняюсь к использованию COM-взаимодействия из рабочих потоков и доступа к объектам автоматизации Excel, таким как «Приложение», «Рабочая книга» и т. Д.

Если бы я ждал, пока сборщик мусора завершит эти объекты, у меня будет невидимый экземпляр "зомби" excel, остающийся в диспетчере задач после того, как пользователь выйдет из excel. Это потому, что эти RCW поддерживают Excel и могут работать еще довольно долго.

...