[英]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 IConnectionPointContainer
, connPointContainer = _transportInformationFilter as IConnectionPointContainer
應該導致在_transportInformationFilter
COM對象上調用QueryInterface
,因此需要單獨發布。 然而,對Marshal.ReleaseComObject(connPointContainer)
的調用是導致_transportInformationFilter
與其RCW分離的罪魁禍首; 刪除此調用修復了該問題。
鑒於此, 在什么情況下我需要在C#中顯式釋放COM對象(使用Marshal.ReleaseComObject
)以避免資源泄漏?
幾乎從不。 ReleaseComObject管理RCW的引用計數,而不是底層對象,並且不直接類似於IUnknown.Release
。 您應該讓CLR管理其QueryInterface
和Release
。
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.