C# 互操作Excel未关闭进程

C# 互操作Excel未关闭进程,c#,asp.net,visual-studio-2010,excel,office-interop,C#,Asp.net,Visual Studio 2010,Excel,Office Interop,我已经为这个问题挣扎了几天,我已经进行了研究并应用了我在各种论坛上找到的所有建议,但我仍然无法解决它 我的问题是excel使用互操作库,我有一个excel文件用作模板,所以我打开它并用新名称保存在新位置。除了创建并关闭文件后Excel进程继续运行外,其他一切都很好 这是我的密码 protected string CreateExcel(string strProjectID, string strFileMapPath) { string strCurrentDir = HttpCont

我已经为这个问题挣扎了几天,我已经进行了研究并应用了我在各种论坛上找到的所有建议,但我仍然无法解决它

我的问题是excel使用互操作库,我有一个excel文件用作模板,所以我打开它并用新名称保存在新位置。除了创建并关闭文件后Excel进程继续运行外,其他一切都很好

这是我的密码

protected string CreateExcel(string strProjectID, string strFileMapPath)
{
    string strCurrentDir = HttpContext.Current.Server.MapPath("~/Reports/Templates/");
    string strFile = "Not_Created";

    Application oXL;
    Workbook oWB;        

    oXL = new Application();
    oXL.Visible = false;

    Workbooks wbks = oXL.Workbooks;
    //opening template file
    oWB = wbks.Open(strFileMapPath);        

    oXL.Visible = false;
    oXL.UserControl = false;
    strFile = strProjectID + "_" + DateTime.Now.Ticks.ToString() + ".xlsx";
    //Saving file with new name
   oWB.SaveAs(strCurrentDir + strFile, XlFileFormat.xlWorkbookDefault, null, null,    false, false, XlSaveAsAccessMode.xlExclusive, false, false, null, null);

    oWB.Close(false, strCurrentDir + strFile, Type.Missing);

    wbks.Close();

    oXL.Quit();


    System.Runtime.InteropServices.Marshal.ReleaseComObject(oXL);
    System.Runtime.InteropServices.Marshal.ReleaseComObject(wbks);
    System.Runtime.InteropServices.Marshal.ReleaseComObject(oWB);


    oWB = null;
    oXL = null;
    wbks = null;
    GC.Collect();

    return strFile;
}
如您所见,我正在关闭并释放所有对象,但应用程序没有退出

我正在使用IIS7在32位的Windows Server 2008(生产版)和Windows 7(开发版)中进行测试。

尝试使用创建excel文档,而不是使用互操作程序集。根据我的经验,它运行速度快得多,而且更易于使用。

试试看

oWB.Close(false, strCurrentDir + strFile, Type.Missing);
oWB.Dispose();
wbks.Close();
wbks.Dispose();
oXL.Quit();
oXL.Dispose();


System.Runtime.InteropServices.Marshal.ReleaseComObject(oXL);
System.Runtime.InteropServices.Marshal.ReleaseComObject(wbks);
System.Runtime.InteropServices.Marshal.ReleaseComObject(oWB);
Process excelProcess = Process.GetProcessesByName("EXCEL")[0];
if (!excelProcess.CloseMainWindow())
{
 excelProcess.Kill();
}

我就是这样绕过这个问题的:

// Store the Excel processes before opening.
Process[] processesBefore = Process.GetProcessesByName("excel");

// Open the file in Excel.
Application excelApplication = new Application();
Workbook excelWorkbook = excelApplication.Workbooks.Open(Filename);

// Get Excel processes after opening the file.
Process[] processesAfter = Process.GetProcessesByName("excel");

// Now find the process id that was created, and store it.
int processID = 0;
foreach (Process process in processesAfter)
{
    if (!processesBefore.Select(p => p.Id).Contains(process.Id))
    {
        processID = process.Id;
    }
}

// Do the Excel stuff

// Now close the file with the COM object.
excelWorkbook.Close();
excelApplication.Workbooks.Close();
excelApplication.Quit();

// And now kill the process.
if (processID != 0)
{
    Process process = Process.GetProcessById(processID);
    process.Kill();
}
这是VB版本--我有一个大型项目使用它,没有时间转换成更好的系统,所以这里是相同的答案。。。在vb.NET中

使用此选项获取流程ID(在打开excel工作表之前)

完成工作表后:

xlWorkBook.Close(SaveChanges:=False)
xlApp.Workbooks.Close()
xlApp.Quit()
'Kill the process
If Not excelProcess(0).CloseMainWindow() Then
    excelProcess(0).Kill()
End If

我为它创建了这个方法,在我的测试中它是有效的

private void ClearMemory(Application excelApp) {
    excelApp.DisplayAlerts = false;
    excelApp.ActiveWorkbook.Close(0);
    excelApp.Quit();
    Marshal.ReleaseComObject(excelApp);
}
请看这里:

您可以通过
GetWindowThreadProcessId
API跟踪您的ProcessID,然后杀死与您的Excel应用程序对象实例特别匹配的进程

[DllImport("user32.dll")]
static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);

Process GetExcelProcess(Microsoft.Office.Interop.Excel.Application excelApp)
{
     int id;
     GetWindowThreadProcessId(excelApp.Hwnd, out id);
     return Process.GetProcessById(id);
}

void TerminateExcelProcess(Microsoft.Office.Interop.Excel.Application excelApp)
{
     var process = GetExcelProcess(excelApp);
     if (process != null)
     {
          process.Kill();
     }
}

简单规则:避免使用双点调用表达式,例如:

var workbook = excel.Workbooks.Open(/*params*/)

()

您不能从ASP.NET或其他服务器技术使用Office互操作。看看@JohnSaunders可能的欺骗:你可以,这只是一个非常非常糟糕的主意;-)@StingyJack:不,这不是由于asp.net造成的。@roma8716:正如John指出的,从asp.net使用互操作(根本不是一个好主意)。我建议您要么使用适合此任务的组件(例如),要么编写一个windows服务来接受排队请求以处理Excel文件。如上述问题注释中所述。这不建议从ASP.NET.NET转换为VB.NET Dim EXCELPROSS(0),因为Process EXCELPROSS=Process.GetProcessesByName(“excel”)这不适合ASP.NET(服务器)场景。您将杀死在开始处理您的请求后出现的实例以及当前正在处理其他请求的实例。这应该可以工作,但如果您/(您的客户)打开了另一个excel工作表,可以关闭它而不是此应用程序,这是最好的,因为它首先检查现有实例。这对ASP.NET(服务器)不好脚本您将杀死在您开始处理请求后出现的实例以及当前正在处理其他请求的实例。这对ASP.NET(服务器)方案不好。您将杀死在开始处理您的请求后出现的实例以及当前正在处理其他请求的实例。谢谢@ZverevEugene-您是否为我指明了编写此代码的更好方法?事实上,是的。看一看:我不想导入dll。有没有其他方法可以做到这一点。@UmerFarooq您可以迭代所有
进程
实例,并对照
excelApp.Hwnd
检查
进程.MainWindowHandle
。所有
Process
实例都可以通过
Process.getprocesss
var workbook = excel.Workbooks.Open(/*params*/)