紧急求救:在aspx网页中起用服务器段Excel.exe,却无法关闭Excel.exe问题

neumann_liu 2006-10-30 08:36:58
我在aspx网页中起用服务器段Excel.exe,却无法关闭Excel.exe问题

代码如下:
Microsoft.Office.Interop.Excel.Application oExcel;
Workbook oBook;
Worksheet oSheet;
Range oRange;
Object oMissing = System.Reflection.Missing.Value;
oExcel = new Application();

string strTargerFile=Server.MapPath(".")+"\\Excel\\excelFile.xls";

oBook = oExcel.Workbooks.Add(strTargerFile);

try
{

oBook.Saved = true;
oExcel.UserControl = false;
oExcel.ActiveWorkbook.SaveCopyAs (strTargerFile);
oExcel.Quit();
Response.Redirect (strTargerFile);
}
catch(System.Exception e1)
{
Response.Wirte(e1.Message);
}
finally
{
oExcel.Quit();
}

问题1:
我调用了oExcel的quit方法,本是想结束进程中的excel.exe进程,可是运行程序以后,察看进程中excel.exe还是存在,这样每运行一次,就会在进程中留有一个excel.exe进程,真是要命,该如何解决阿?


问题2:
另外,我如果把oExcel = new Application(); 这条语句放在try语句快中,总会出现“访问被拒绝的异常”,当如果不放在try{}中,程序也能正常运行下去,这是怎么回事啊。
...全文
501 19 打赏 收藏 举报
写回复
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
qianli918 2006-11-25
  • 打赏
  • 举报
回复
using(ExcelWrapper myExcel = new ExcelWrapper())
{
// ....
}
这个vb.net怎么写呢,请问
  • 打赏
  • 举报
回复
supertbt(软件_小菜)

那个可以实现 ,我已经用过, 不过拜托这位仁兄借用别人代码时请声明 转 !
喝醉的咖啡 2006-10-30
  • 打赏
  • 举报
回复
全部写写不动了,来一段吧:
public class ExcelWrapper: IDispose
{
private bool _IsDisposed = false;
~ExcelWrapper()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool bIsDisposing)
{
if(!_IsDisposed)
{
if(bIsDisposing)
{ // 根据需要释放托管资源 }

// 这里 try catch 并调用你的 excel 实例 Quit()
}
_IsDisposed = true;
}
}

其它你可以自己加一些方法,例如 OpenFile 什么的,设置一个类全局变量来保存 Excel 或者 WorkBook 什么的,以便其它方法共享

调用的时候:
using(ExcelWrapper myExcel = new ExcelWrapper())
{
// ....
}
或者
ExcelWrapper myExcel = new ExcelWrapper()
// ....
myExcel.Dispose();

类似的托管资源都可以通过如此包装后管理起来。
neumann_liu 2006-10-30
  • 打赏
  • 举报
回复
那麻烦你给一段具体的代码,就是关于如下解决办法的实现,拜托了:
、不要在你的代码中直接使用 Excel 等托管资源,用一个类 wrap 一下,包装起来,比如 ExcelWrapper 什么的
2、在你的 wrapper 类实现 IDispose 接口的 Dispose() 方法
3、调用你的 wrapper 类来进行相关操作,使用完毕后调用该类的 Dispose() 方法
如果担心忘记了调用 Dispose(),可以用 using(ExcelWrapper myExcel){ //具体使用代码 }这样的方式,让 .NET 自己记得去掉用 Dispose()
喝醉的咖啡 2006-10-30
  • 打赏
  • 举报
回复
关于权限:先按照其它教程教你的方法做吧,要不要累死我
只是要记得,那些方法都存在种种隐患——因为基础知识不扎实,有能力的情况下(比如项目做完了有时间了)一定要改进一下,至少把自己的知识巩固一下。

例如:为何要用 Administrator 而不能自己创建一个账户添加到 Administrators 组里?为何用 Network 甚至 LocalSystem 账户权限都不够?为何允许 ASP.NET,甚至 everyone 等账户访问 Excel 所在文件夹也不够?——因为 Excel 需要运行账户具备桌面交互权限——界面!
甚至,权限配置不当还可能造成你的服务器必须有人用某个账户登录之后才能用等等问题。

那么,其实完全可以创建一个足够权限的账户来代替 administrator(改密码怎么办?),密码可以用随机生成的复杂代码。但问题是难道整个 WebApp 都运行在如此高的权限下?岂不很危险?

而最好的方法是写一段代码局部提升权限(impersonate),而不是修改账户或者 web.config(密码泄漏) 甚至 machine.config...

这里不多说了,唉,说得越多越累,俺又没那么多时间来混个 MVP,分又多地用不完... 命苦。
喝醉的咖啡 2006-10-30
  • 打赏
  • 举报
回复
hehe,看来还真是教程写得有问题,我还真是应该继续当老师,IT行业太混乱了...误人子弟啊

我来教你正解吧

1、GC.Collect() 错误使用
执行该方法只不过是“催促”GC进行收集,而不能保证立即执行完毕——当然,有的文章会教你加入
GC.WaitForPendingFinalizers();
but,一样无效,呵呵,这是因为对 GC 的机制理解不正确造成的。

2、杀进程——舍近求远
Microsft .NET 架构设计师有这么愚蠢么?

为什么释放不了托管资源?因为资源仍然处于被引用状态,GC不会去释放它。

解决方法:
1、不要在你的代码中直接使用 Excel 等托管资源,用一个类 wrap 一下,包装起来,比如 ExcelWrapper 什么的
2、在你的 wrapper 类实现 IDispose 接口的 Dispose() 方法
3、调用你的 wrapper 类来进行相关操作,使用完毕后调用该类的 Dispose() 方法
如果担心忘记了调用 Dispose(),可以用 using(ExcelWrapper myExcel){ //具体使用代码 }这样的方式,让 .NET 自己记得去掉用 Dispose()
这样做以后,你当前的实例还能继续做其它事情,而托管资源则因为 myExcel 的释放而被释放了。
具体代码等我打开本本贴上来——累死,软件产品开发公司不允许使用U盘、移动硬盘、笔记本什么的,只好手工敲了
Knight94 2006-10-30
  • 打赏
  • 举报
回复
很奇怪,要有错误,不加try-catch也会报错。

我这儿加上try-catch也没什么问题。

以下具体说说excel的权限设置。
1、在控制面板的组件服务中修改Excel权限;
如果以上还不行,修改web.config,用impersonate模拟系统的administrator用户。

2、设置aspnet用户对文件所在的目录具有访问权限。

完成如上两部,就可以在web中访问excel文件。
woaiqingqing 2006-10-30
  • 打赏
  • 举报
回复
execl.exe文件没有转换.
supesa 2006-10-30
  • 打赏
  • 举报
回复
q2愚翁给的帖子中提到的第二种方法
supesa 2006-10-30
  • 打赏
  • 举报
回复
/// <summary>
/// 结束Excel进程
/// </summary>
private 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,并释放调用的COM资源
/// </summary>
public void Dispose()
{
workBook.Close(null,null,null);
app.Workbooks.Close();
app.Quit();

if(range != null)
{
//释放资源
Marshal.ReleaseComObject(range);
range = null;
}
if(range1 != null)
{
Marshal.ReleaseComObject(range1);
range1 = null;
}
if(range2 != null)
{
Marshal.ReleaseComObject(range2);
range2 = null;
}
if(textBox != null)
{
Marshal.ReleaseComObject(textBox);
textBox = null;
}
if(workSheet != null)
{
Marshal.ReleaseComObject(workSheet);
workSheet = null;
}
if(workBook != null)
{
Marshal.ReleaseComObject(workBook);
workBook = null;
}
if(app != null)
{
Marshal.ReleaseComObject(app);
app = null;
}

//调用垃圾回收,释放内存
GC.Collect();

this.KillExcelProcess();
}
回收excel进程
neumann_liu 2006-10-30
  • 打赏
  • 举报
回复
问题可能出在这,我把上面的代码作了如下修改:
private void Button1_Click(object sender, System.EventArgs e)
{
try
{
ApplicationClass myExcel = new ApplicationClass();
string strExcelFile = Server.MapPath( "." ) + @"\Excel\test.xls" ;
Workbook oBook = myExcel.Workbooks.Add( strExcelFile );
System.Runtime.InteropServices.Marshal.ReleaseComObject( oBook );
myExcel.Workbooks.Close();
myExcel.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject( myExcel );
GC.Collect();
}
catch(System.Exception e1)
{
Response.Write(e1.Message);
}
}

重新运行,这时候运行到ApplicationClass myExcel = new ApplicationClass();时候,就提示:访问被拒绝的错误信息。
但是我也按照“to 2web程序访问excel组件,http://community.csdn.net/Expert/topicview.asp?id=4912705”这里描述的一样进行了设置阿,为什么在没有添加异常处理的时候,不会有访问权限问题,而且也能打开excel文件,甚至我往文件里边写一些字符,也可以。但一旦把它放大try语句快,就会出现访问权限问题,而无法继续运行。

请各位帮忙分析分析什么原因,急死我了
neumann_liu 2006-10-30
  • 打赏
  • 举报
回复
我看了网上的很多文章,包括这个论坛里的很多关于excel介绍的很多文章,就是无法解决。我的环境是:vs2003, windows Xp, office XP
我就是完全拷贝Knight94(愚翁) 的那段代码,如下:
private void Button1_Click(object sender, System.EventArgs e)
{
Microsoft.Office.Interop.Excel.ApplicationClass myExcel = new Microsoft.Office.Interop.Excel.ApplicationClass();
string strExcelFile = Server.MapPath( "." ) + @"\Excel\test.xls" ;
Microsoft.Office.Interop.Excel.Workbook oBook = myExcel.Workbooks.Add( strExcelFile );
System.Runtime.InteropServices.Marshal.ReleaseComObject( oBook );
myExcel.Workbooks.Close();
myExcel.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject( myExcel );

GC.Collect();
}

但是运行程序以后,每点击一次按钮,就会在任务管理器中看到多了一个新的Excel进程,
是不是除了代码方面的问题,还需要其他方面的设置阿。
喝醉的咖啡 2006-10-30
  • 打赏
  • 举报
回复
关闭 Excel 的问题:实现 IDispose 接口,并正确实现 Dispose() 方法
另外要注意权限问题——在服务器端进程中打开 Excel,需要有桌面交互权限的账户,我一般使用局部权限提升的方法来确保安全性。

其实,有很多人写过文章了,不妨好好看看,别急着提问——效果未必好。

仔细看看 Knight94(愚翁) 提供的参考。
desert3 2006-10-30
  • 打赏
  • 举报
回复
强制垃圾回收

int generation = System.GC.GetGeneration(myExcel);
myExcel = null;
System.GC.Collect(generation);
Knight94 2006-10-30
  • 打赏
  • 举报
回复
ps:运行环境如下
vs2003, xp, office 2003
Knight94 2006-10-30
  • 打赏
  • 举报
回复
大致试了一下,只要按照我给的两篇文章去做,是没有问题的
如下是打开excel文件的代码
Excel.ApplicationClass myExcel = new Excel.ApplicationClass();
string strExcelFile = Server.MapPath( "~" ) + @"\test.xls" ;
Excel.Workbook oBook = myExcel.Workbooks.Add( strExcelFile );
System.Runtime.InteropServices.Marshal.ReleaseComObject( oBook );
myExcel.Workbooks.Close();
myExcel.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject( myExcel );

GC.Collect();
neumann_liu 2006-10-30
  • 打赏
  • 举报
回复
q1:
http://community.csdn.net/Expert/TopicView3.asp?id=4795624,我试了这里边提供的方法,还是无法解决,能不能帮我直接修改一下上面那段代码,来结束excel.exe进程。
q2:
我就是如这里http://community.csdn.net/Expert/topicview.asp?id=4912705,描述的那样设置的,这样设置以后还是出现这种状况
Knight94 2006-10-30
  • 打赏
  • 举报
回复
to 1

参看
http://community.csdn.net/Expert/TopicView3.asp?id=4795624

to 2

web程序访问excel组件,要设置相应的权限,参看
http://community.csdn.net/Expert/topicview.asp?id=4912705
rgwfeng2 2006-10-30
  • 打赏
  • 举报
回复
good
发帖
C#

10.9w+

社区成员

.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
帖子事件
创建了帖子
2006-10-30 08:36
社区公告

让您成为最强悍的C#开发者