chiname

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

关于ASP.NET中调用Excel组件不能结束进程的解决方法

        关于在asp.net中调用Excel组件不能结束进程的问题,常见的解决方法用的是下面这段代码

wb.Close(null,null,null);
app.Workbooks.Close();
app.Quit();

if(rng != null)
{
    System.Runtime.InteropServices.Marshal.ReleaseComObject(rng);
    rng 
= null;
}

if(ws != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(ws);
    ws 
= null;
}

if(wb != null)
{  System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
    wb 
= null;
}

if(app != null)
{ System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
app 
= null;
}

GC.Collect();

        虽然这段代码在配置正确的情况下能自动结束Excel进程,但是前提是在操作Excel时没有引发异常的情况下,如果有异常发生,那么Excel进程将不能结束(比如:引用了一个在Excel文件中不存在的文本框时就会出现“HRESULT 中的异常:0x800A03EC。”),这时就要借助Process类的Kill()方法来结束,下面是我写的测试代码:

using System;
using System.Diagnostics;
using excel = Microsoft.Office.Interop.Excel;

namespace ExcelTest
{
    
/// <summary>
    
/// Excel的摘要说明。
    
/// </summary>

    public class Excel
    
{
        
private DateTime beforeTime;            //Excel启动之前时间
        private DateTime afterTime;                //Excel启动之后时间

        excel.Application app;
        excel.Workbook wb;
        excel.Worksheet ws;
        excel.Range rng;
        excel.TextBox tb;

        
public Excel(string templetPath)
        
{
            
//实例化一个Excel Application对象并使其可见
            beforeTime = DateTime.Now;
            app 
= new excel.ApplicationClass();
            app.Visible 
= true;
            afterTime 
= DateTime.Now;

            wb 
= app.Workbooks.Open(templetPath,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing);
            ws 
= (excel.Worksheet)wb.Worksheets.get_Item(1);
        }


        
public void ExcelMethod()
        
{
            rng 
= ws.get_Range("B5","C7");
            rng.Merge(excel.XlAxisCrosses.xlAxisCrossesAutomatic);
            rng.Value2 
= "Excel2003";

            rng 
= ws.get_Range("D8","E11");
            rng.MergeCells 
= true;
            rng.Value2 
= "Excel2003";
            rng.HorizontalAlignment 
= excel.XlHAlign.xlHAlignCenter;
            rng.VerticalAlignment 
= excel.XlVAlign.xlVAlignCenter;

            rng 
= ws.get_Range("A1",Type.Missing);
            rng.Value2 
= 5;

            rng 
= ws.get_Range("A2",Type.Missing);
            rng.Value2 
= 7;

            
for(int i=1;i<100;i++)
            
{
                
string s = string.Concat("G",i.ToString());
                rng 
= ws.get_Range(s,Type.Missing);
                rng.Value2 
= i.ToString();
            }


            tb 
= (excel.TextBox)ws.TextBoxes("文本框 1");
            tb.Text 
= "作 者";

            tb 
= (excel.TextBox)ws.TextBoxes("文本框 2");
            tb.Text 
= "KLY.NET的Blog";

            tb 
= (excel.TextBox)ws.TextBoxes("文本框 3");
            tb.Text 
= "日 期";


            
try
            
{
                tb 
= (excel.TextBox)ws.TextBoxes("文本框 5");
                tb.Text 
= DateTime.Now.ToShortDateString();
            }

            
catch
            
{
                
//这里用Dispose()方法结束不了Excel进程,所有还是要用Process的Kill()方法配合使用
                
//                this.Dispose();
                this.KillExcelProcess();
                
throw new Exception("不存在ID为\"文本框 5\"的文本框!");
            }

            
finally
            
{
                
//如果有异常发生,Dispose()方法放在这里也结束不了Excel进程
//                this.Dispose();

                
//如果发生异常,在这里也可以结束Excel进程
//                this.KillExcelProcess();
            }

        }


        
/// <summary>
        
/// 另存为Excel文件
        
/// </summary>
        
/// <param name="savePath">保存路径</param>

        public void SaveAsExcelFile(string savePath)
        
{
            wb.SaveAs(savePath,excel.XlFileFormat.xlHtml,Type.Missing,Type.Missing,Type.Missing,Type.Missing,excel.XlSaveAsAccessMode.xlExclusive,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing);
        }


        
/// <summary>
        
/// 结束Excel进程
        
/// </summary>

        public void KillExcelProcess()
        
{
            Process[] myProcesses;
            DateTime startTime;
            myProcesses 
= Process.GetProcessesByName("Excel");

            
//得不到Excel进程ID,暂时只能判断进程启动时间
            foreach(Process myProcess in myProcesses)
            
{
                startTime 
= myProcess.StartTime;

                
if(startTime > beforeTime && startTime < afterTime)
                
{
                    myProcess.Kill();
                }

            }

        }


        
/// <summary>
        
/// 如果对Excel的操作没有引发异常的话,用这个方法可以正常结束Excel进程
        
/// 否则要用KillExcelProcess()方法来结束Excel进程
        
/// </summary>

        public void Dispose()
        
{
            wb.Close(
null,null,null);
            app.Workbooks.Close();
            app.Quit();

            
//注意:这里用到的所有Excel对象都要执行这个操作,否则结束不了Excel进程
            if(rng != null)
            
{
                System.Runtime.InteropServices.Marshal.ReleaseComObject(rng);
                rng 
= null;
            }

            
if(tb != null)
            
{
                System.Runtime.InteropServices.Marshal.ReleaseComObject(tb);
                tb 
= null;
            }

            
if(ws != null)
            
{
                System.Runtime.InteropServices.Marshal.ReleaseComObject(ws);
                ws 
= null;
            }

            
if(wb != null)
            
{
                System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
                wb 
= null;
            }

            
if(app != null)
            
{
                System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
                app 
= null;
            }


            GC.Collect();
        }

    }

}

        这段代码能很好的解决Excel进程不能正常结束的问题,如果主机操作系统不是服务器版的话,那么就要借助于ntsd -c q -p pid命令来结束。
        还有一个问题的关于Excel组件访问权限的配置,一定要在组件服务里面正确配置,否则结束不了Excel进程,具体的配置方法在我项目的doc文件夹下;在我前面的文章里面介绍了在web.config文件里面加入假扮用户的方法,但是经我测试发现这种方法虽然可以访问Excel组件,但是结束不了进程,除非用Kill方法强行结束。

点这里下载ExcelTest.rar

 

posted on 2005-11-08 21:13 lingyun_k 阅读(1727) 评论(10)  编辑 收藏 收藏至365Key 所属分类: DOTNETReportsBI

View Comments

# re: 关于ASP.NET中调用Excel组件不能结束进程的解决方法  回复   
强,服务端居然有人敢用Excel!!!

大家别学他哦。
2005-11-09 12:06 | 沐枫
# re: 关于ASP.NET中调用Excel组件不能结束进程的解决方法  回复   
在服务器端用Excel是不好,资源占用率高,以后改在客户端用了,只是Javascript不是很熟
2005-11-09 19:55 | lingyun_k
# re: 关于ASP.NET中调用Excel组件不能结束进程的解决方法  回复   
这玩意折腾我很长时间,发现这样那样的方法都不太好,资源浪费严重,安全性也不好,还有可能把别的EXCEL进程杀死,我后来用了ASPOSE控件,效果不错,在服务端也不需要装EXCEL了
2005-11-10 15:13 | 蔚然之家
# re: 关于ASP.NET中调用Excel组件不能结束进程的解决方法  回复   
aspose我也用过,但是它不能操作文本框,而客户的Excel报表很复杂,差不多所有报表有下角都有作者、版本、图号、日期这样的文本框,本来想先将数据写在Excel的一个角落的Cell中,然后把文本框的值设置为Cell的值,但是客户不接受,所有只有采用这种方法,而且是十几个模块的报表一起导出为Excel,然后打包下载,用脚本操作Excel 几乎是不可能的
2005-11-10 22:04 | lingyun_k
# re: 关于ASP.NET中调用Excel组件不能结束进程的解决方法  回复   
myProcesses = Process.GetProcessesByName("Excel");
这句话出错了。
错误是:拒绝访问。
system.componentModel.win32exception
2005-11-18 03:14 | sunjian
# re: 关于ASP.NET中调用Excel组件不能结束进程的解决方法  回复   
你装的是什么操作系统
2005-11-18 19:12 | lingyun_k
# re: 关于ASP.NET中调用Excel组件不能结束进程的解决方法  回复   
本来看到题目很兴奋,因为自己也遇见这样的问题,困扰了很久。
结果看到结尾很失望。
因为大部分Excel的程序都不能写在一个函数,
因此,给出一个打开再关闭的例子实在没有什么用处。
甚至文章连为什么会出现关闭不了的原因都没有探讨。艾。。。
关闭进程的方法则是基本没有应用价值的。
首先是安全,其次是如果有两个用户正在导出则一个用户会被强行关闭,这种情况在实际应用肯定是被否定的。

说句不中听的话,象这样每个Excel报表写一堆死代码,我觉得很累人。

另外对于在服务器端使用excel效率的问题。
1,大家有没有真正去写点代码测试一下,多少数据,什么格式下导出,花多少时间?
随便就说效率低,到底低到什么情况了?能否运用到项目上,不是凭感觉来的。
2,真的无法使用客户端完成复杂报表么?
我个人认为那是小看了vbscript了。
2006-01-08 13:56 | ASTAR Coming Now
# re: 关于ASP.NET中调用Excel组件不能结束进程的解决方法  回复   
我在Window2000上EXCEL进程关闭不掉,但是在XP上就能够关闭.
2006-02-07 18:01 | Jian
# re: 关于ASP.NET中调用Excel组件不能结束进程的解决方法  回复   
我在Window2000上生成Excel文件时,会多生成一个要生成的快捷方式方件夹,但是在XP上就不会.
谢谢.
2006-02-07 18:04 | Jian
# re: 关于ASP.NET中调用Excel组件不能结束进程的解决方法  回复   
按上面的方法应该能杀掉进程的,至于会多生成一个要生成的快捷方式方件夹就搞不明白了
2006-02-07 20:14 | lingyun_k
posted on 2006-03-15 12:10  把我的欢乐带给你  阅读(282)  评论(0)    收藏  举报