VSTO Excel常见COM对象的观察

浏览:1103 发布日期:2023-07-02 23:36:46
public static List<RowColumnInfo> testGetCellList(excel.Application app, excel.Workbook wb)
{
    excel.Sheets wss = wb.Worksheets;
    excel.Worksheet ws = wss[1];
    excel.Range regionRng = ws.UsedRange;
    List<RowColumnInfo> list = ExcelUtils.GetCellList(regionRng);

    excel.Range r2 = ws.UsedRange;
    Console.WriteLine("释放uRng0");
    MarshalUtils.ReleaseComObject(ref regionRng); // 返回0
    MarshalUtils.ReleaseComObject(ref r2); // 返回0
    Console.WriteLine("释放ws0");
    MarshalUtils.ReleaseComObject(ref ws);
    Console.WriteLine("释放wss0");
    MarshalUtils.ReleaseComObject(ref wss); // 返回0

    return list;
}

其中MarshalUtils.ReleaseComObject 方法和Marshal.ReleaseComObject类似。似乎ws.UsedRange不需要释放,多次创建了其COM对象,但每次释放时,返回的RCW引用数都是0。

excel.Sheets对象似乎多次引用,也不会递增引用计数。

excel.Worksheet如果多次引用不释放,则会递增引用计数。

确切的说,RCW对象可被GC回收,从而释放关联的COM对象。

不过我发现,我编写的一段代码中,从Range对象获取了Application对象,并从Application对象获取了CellFormat对象,如果不释放CellFormat对象,仅释放Application对象并不能及时释放RCWCOM对象。

excel.Application app = regionRng.Application;
   excel.CellFormat findFormat = app.FindFormat;
   findFormat.Clear();
   MarshalUtils.ReleaseComObject(ref findFormat);

对于其他情况,即使我不显示释放任何RangeWorksheetSheets,仅释放Application对象,不会残留Excel进程。

由于GC的不确定性,它可能无法及时释放相关对象,会残存excel进程,如果需要实时性,可以手动释放所涉及的对象。

不过要非常小心谨慎。而且尽量不要使用链式的多个点的方式。如:

excel.CellFormat findFormat = regionRng.Application.FindFormat;
   findFormat.Clear();
   MarshalUtils.ReleaseComObject(ref findFormat);

微软并不推荐使用Marshal.ReleaseComObject,原因是,由于COM对象在不同方法中进行调用,很可能会多调用了此方法,导致其他方法无法使用。某些COM对象是单例的,这种情形会很容易导致RCW断开,发生严重错误。