簡體   English   中英

我何時需要在C#中通過COM查詢的接口上調用Marshal.ReleaseComObject

[英]When am I required to call Marshal.ReleaseComObject on an interface queried through COM in C#

我一直在使用一些DirectShow接口來使用C#和DirectShow.Net播放數字電視(DVB-T)。 我最近遇到的運行時錯誤COM object that has been separated from its underlying RCW cannot be used.

此錯誤發生在以下行:

_guideData = _transportInformationFilter as IGuideData;

_transportInformationFilter的類型為IBaseFilter,這是一個先前通過DirectShow.Net實用程序函數分配的COM對象。

我認為錯誤是由於_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 IConnectionPointContainerconnPointContainer = _transportInformationFilter as IConnectionPointContainer應該導致在_transportInformationFilter COM對象上調用QueryInterface ,因此需要單獨發布。 然而,對Marshal.ReleaseComObject(connPointContainer)的調用是導致_transportInformationFilter與其RCW分離的罪魁禍首; 刪除此調用修復了該問題。

鑒於此, 在什么情況下我需要在C#中顯式釋放COM對象(使用Marshal.ReleaseComObject )以避免資源泄漏?

幾乎從不。 ReleaseComObject管理RCW的引用計數,而不是底層對象,並且不直接類似於IUnknown.Release 您應該讓CLR管理其QueryInterfaceRelease

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.Release的方法是Marshal.Release ,而不是ReleaseComObject

我想我已經找到了使用Marshal.ReleaseComObject的真正合法的情況。 當使用ExcelDNA在C#中編寫excel addins時,我傾向於使用來自工作線程的COM互操作,並訪問excel自動化對象,如“Application”,“Workbook”等。

如果我等待垃圾收集器來完成這些對象,那么在用戶退出excel之后,我將擁有一個看不見的excel“zombie”實例。 這是因為那些RCW能夠保持活力,並且可以保持運行一段時間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM