Silverlight 操作Excel 中的进程资源释放问题(续)

在前几天写到的Silverlight 操作Excel 中的进程资源释放问题 中,存在很多不完善的地方,因为在BeforeClose中处理掉Excel资源,会造成Excel无法再进行与代码的部分控制进行交互了。

于是,继续谷歌……发现一篇很不错的文章,其Demo的效果也正是我想要的,于是,Mark一下。

原文是日语的,借助翻译还是能看懂吧:(

原问题的地址是:How to release COM objects in Silverlight 4,作者地址:http://csfun.blog49.fc2.com/blog-entry-79.html (好像要用代理才能看),Demo下载地址:SilverOffice

以下是根据我个人的理解,翻译并整理的两个关键的类。

1、ComObjectWrapper,实现IDisposable接口

 1  public class ComObjectWrapper : IDisposable
 2     {
 3         /// <summary>
 4         /// Com对象被释放时的事件
 5         /// </summary>
 6         internal event EventHandler ComObjectDisposed;
 7 
 8         //对象是否被释放
 9         private Boolean _disposed = false;
10 
11         /// <summary>
12         /// Com对象集合
13         /// </summary>
14         private List<ComObjectWrapper> _children = new List<ComObjectWrapper>();
15 
16         /// <summary>
17         /// Com对象是否被释放的的标记
18         /// true情况下释放出来
19         /// </summary>
20         public Boolean Disposed
21         {
22             get
23             {
24                 return _disposed;
25             }
26         }
27 
28         /// <summary>
29         /// 增加对象到集合,并为对象绑定释放事件
30         /// </summary>
31         /// <param name="child"></param>
32         protected void AddChildren(ComObjectWrapper child)
33         {
34             _children.Add(child);
35             child.ComObjectDisposed += new EventHandler(child_ComObjectDisposed);
36         }
37 
38         /// <summary>
39         /// 子对象被释放时在集合移除
40         /// </summary>
41         /// <param name="sender"></param>
42         /// <param name="e"></param>
43         private void child_ComObjectDisposed(object sender, EventArgs e)
44         {
45             _children.Remove(sender as ComObjectWrapper);
46         }
47 
48         /// <summary>
49         /// 释放Com对象(集合所有对象)
50         /// </summary>
51         private void ReleaseChildren()
52         {
53             foreach (ComObjectWrapper child in _children)
54             {
55                 child.ComObjectDisposed -= new EventHandler(child_ComObjectDisposed);
56                 child.Dispose();
57             }
58 
59             _children.Clear();
60         }
61 
62         /// <summary>
63         /// 执行释放资源(虚函数)
64         /// </summary>
65         protected virtual void DoDispose() { }
66 
67         #region IDisposable Members
68 
69         /// <summary>
70         /// 释放Excel程序资源
71         /// </summary>
72         public void Dispose()
73         {
74             try
75             {
76                 //释放对象
77                 ReleaseChildren();
78 
79                 DoDispose();
80 
81                 _disposed = true;
82 
83                 if (ComObjectDisposed != null)
84                 {
85                     ComObjectDisposed(this, EventArgs.Empty);
86                 }
87             }
88             catch { }
89         }
90 
91         #endregion
92     }

2、InstanceManager类,对所有Excel的Com对象进行管理

 1  public class InstanceManager
 2     {
 3         /// <summary>
 4         /// Excel对象实例集合
 5         /// </summary>
 6         private static List<ComObjectWrapper> _excelApplications = new List<ComObjectWrapper>();
 7 
 8         /// <summary>
 9         /// 新增一个Excel对象
10         /// </summary>
11         /// <returns></returns>
12         public static ExcelApplication CreateAppication()
13         {
14             //自动化功能是否可用
15             if (!AutomationFactory.IsAvailable) return null;
16 
17             dynamic excelObject = AutomationFactory.CreateObject("Excel.Application");
18 
19             ExcelApplication application = new ExcelApplication(excelObject);
20             _excelApplications.Add(application);
21             application.ComObjectDisposed += new System.EventHandler(application_ComObjectDisposed);
22             return application;
23         }
24 
25         /// <summary>
26         /// Com对象被释放时的事件
27         /// </summary>
28         /// <param name="sender"></param>
29         /// <param name="e"></param>
30         static void application_ComObjectDisposed(object sender, System.EventArgs e)
31         {
32             try
33             {
34                 _excelApplications.Remove(sender as ComObjectWrapper);
35             }
36             catch { }
37         }
38 
39         /// <summary>
40         /// 取得已经运行的Excel进程实例。
41         /// </summary>
42         /// <param name="create"></param>
43         /// <returns></returns>
44         public static ExcelApplication GetApplication(bool create)
45         {
46             //自动化功能是否可用
47             if (!AutomationFactory.IsAvailable) return null;
48 
49             dynamic excelObject = null;
50 
51             //在已经生成的com对象集合中取得没有被释放的实例
52             foreach (ExcelApplication excel in _excelApplications)
53             {
54                 if (!excel.Disposed)
55                 {
56                     return excel;
57                 }
58             }
59 
60             try
61             {
62                 excelObject = AutomationFactory.GetObject("Excel.Application");
63             }
64             catch
65             {
66                 if (create)
67                 {
68                     excelObject = AutomationFactory.CreateObject("Excel.Application");
69                 }
70             }
71 
72             if (excelObject != null)
73             {
74                 ExcelApplication application = new ExcelApplication(excelObject);
75                 _excelApplications.Add(application);
76                 application.ComObjectDisposed += new System.EventHandler(application_ComObjectDisposed);
77                 return application;
78             }
79             else
80             {
81                 return null;
82             }
83         }
84 
85         /// <summary>
86         /// 释放所有Excel进程
87         /// </summary>
88         public static void ReleaseAll()
89         {
90             foreach (ComObjectWrapper wrapper in _excelApplications)
91             {
92                 wrapper.ComObjectDisposed -= new EventHandler(application_ComObjectDisposed);
93                 wrapper.Dispose();
94             }
95             _excelApplications.Clear();
96         }
97     }

使用时,在ExcelApplication的封装类进行调用Exit()函数即可。

注意,封装类要进行继续1中的ComObjectWrapper类, 并重写DoDispose。封装类的代码就不上了,百度或者谷歌都有:(

public class ExcelApplication : ComObjectWrapper
{

    /// <summary>
   /// Excel程序退出 /// </summary> public void Exit() { _excel.Quit(); Dispose(); }   /// <summary> /// Com对象的释放处理 /// </summary> protected override void DoDispose() { try { Workbooks.Close(); Workbooks.Dispose(); _excel.Quit(); ((IDisposable)_excel).Dispose(); _excel = null; } catch { } }     //other code ........... }

public class ExcelWorkbook : ComObjectWrapper
{
  
protected override void DoDispose() { try { ((IDisposable)workBook).Dispose(); } catch { } } //.................other code
}

 11月27日补充:

在手动new一个Excel封装类的变量后(如:ExcelWorkSheet、ExcelRange),一定要记得把它手动释放进程,不然会直到程序关闭才自动释放!

 var currentSheet = new ExcelWorkSheet {WorkSheet = workBook.WorkBook.ActiveSheet};
// other code to do something
currentSheet.Dispose();

 

作者:Ivan
个人网站:http://www.IvanBy.com
原文地址:https://www.cnblogs.com/oneivan/p/2789302.html