简体   繁体   English

C#运行后关闭Microsoft Interop Excel进程

[英]C# Closing Microsoft Interop Excel Process after running

I am uploading an excel file, opening it, reading the contents, closing it and removing it. 我正在上传一个excel文件,打开它,阅读内容,关闭它并删除它。

All works well, however I have noticed the process 'Microsoft Excel' still runs in the background in task manager. 一切正常,但是我注意到任务管理器中的“ Microsoft Excel”进程仍在后台运行。

Excel流程

I have tried searching around and have tried different answers but none of them work for me. 我已经尝试过搜索并且尝试了不同的答案,但是没有一个对我有用。 Does anyone have any ideas? 有人有什么想法吗?

I am trying different ways of closing the app, releasing the com but having no luck. 我正在尝试关闭应用程序,发布com的各种方式,但是没有运气。

The code I am using: 我正在使用的代码:

    public ActionResult UploadUpdateOOBList()
    {
        CheckPermissions("UpdateOOBList");

        string[] typesallowed = new string[] { ".xls", ".xlsx" };

        HttpPostedFileBase file = Request.Files[0];
        var fname = file.FileName;

        if (!typesallowed.Any(fname.Contains))
        {
            return Json("NotAllowed");
        }

        file.SaveAs(Server.MapPath("~/Uploads/OOB List/") + fname);

        //Create COM Objects. Create a COM object for everything that is referenced
        Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
        Microsoft.Office.Interop.Excel.Workbooks xlWorkbooks = xlApp.Workbooks;
        Microsoft.Office.Interop.Excel.Workbook xlWorkbook = xlWorkbooks.Open(Server.MapPath("~/Uploads/OOB List/") + fname);
        Microsoft.Office.Interop.Excel._Worksheet xlWorksheet = xlWorkbook.Sheets[2];
        Microsoft.Office.Interop.Excel.Range xlRange = xlWorksheet.UsedRange;

        //Create empty OOB data list
        List<OOBList.OOBDetails> oob_data = new List<OOBList.OOBDetails>();

        int rowcount = xlRange.Rows.Count;

        for (int down = 4; down <= rowcount; down++)
        {

            //Make sure first column isn't null
            if( xlRange.Cells[down, 1] != null && xlRange.Cells[down, 1].Value2 != null )
            {
                string siteno = xlRange.Cells[down, 1].Value2.ToString();
                string sitename = xlRange.Cells[down, 2].Value2.ToString();
                string description = xlRange.Cells[down, 4].Value2.ToString();
                string cabinoob = xlRange.Cells[down, 5].Value2.ToString();
                string toweroob = xlRange.Cells[down, 6].Value2.ToString();
                string manageoob = xlRange.Cells[down, 7].Value2.ToString();
                string resolutiondate = xlRange.Cells[down, 8].Value2.ToString();
                var resolutiondate_converted = DateTime.FromOADate(Convert.ToDouble(resolutiondate)).ToString("dd/MM/yyyy");

                oob_data.Add(new OOBList.OOBDetails
                {
                    SiteNo = siteno,
                    SiteName = sitename,
                    Description = description,
                    CabinOOB = cabinoob,
                    TowerOOB = toweroob,
                    ManageOOB = manageoob,
                    TargetResolutionDate = resolutiondate_converted
                });

                Debug.Write("Adding SiteNo: " + siteno);
            }

        }

        //HERE IS THE PROBLEM, DOESNT SEEM TO CLOSE THE PROCESS.
        xlWorkbook.Close();
        xlApp.Quit();

        System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkbook);
        System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkbooks);
        System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorksheet);
        System.Runtime.InteropServices.Marshal.ReleaseComObject(xlRange);
        System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
        xlWorkbook = null;
        xlWorkbooks = null;
        xlWorksheet = null;
        xlRange = null;
        xlApp = null;

        GC.Collect();

        //Now delete file.
        System.IO.File.Delete(Server.MapPath("~/Uploads/OOB List/") + fname);

        var nowdate = DateTime.Now.ToString("dd/MM/yyyy");
        System.IO.File.WriteAllText(Server.MapPath("~/Uploads/OOB List/lastupdated.txt"),nowdate);

        return Json("Success");

    }

found that somewhere: "Automation servers register themselves in the Running Object Table (ROT) through the RegisterActiveObject() API. 发现某处:“自动化服务器通过RegisterActiveObject()API在运行对象表(ROT)中注册自己。

NOTE: If there are multiple instances of an automation server running at the same time, the GetActiveObject() API function returns the IDispatch pointer to the instance that was first running. 注意:如果有多个自动化服务器实例同时运行,则GetActiveObject()API函数将IDispatch指针返回到第一次运行的实例。

Theoretically, you can iterate the ROT for each individual instance, but Office applications do not register themselves if another instance is already in the ROT because the moniker for itself is always the same, and cannot be distinguished. 从理论上讲,您可以为每个单独的实例迭代ROT,但是如果ROT中已经存在另一个实例,则Office应用程序不会注册自己,因为它的名称始终是相同的,并且无法区分。 This means that you cannot attach to any instance except for the first. 这意味着除了第一个实例外,您无法附加到任何实例。 However, because Office applications also register their documents in the ROT, you can successfully attach to other instances by iterating the ROT looking for a specific document, attaching to this document, and then getting the Application object from this document. 但是,由于Office应用程序也在ROT中注册其文档,因此您可以通过迭代ROT查找特定文档,附加到此文档并从该文档中获取Application对象,来成功附加到其他实例。 For a code example of iterating the ROT and looking for a document name, click the article number below to view the article in the Microsoft Knowledge Base: 190985 How To Get IDispatch of an Excel or Word Document from an OCX" 有关迭代ROT和查找文档名称的代码示例,请单击下面的文章编号,以查看Microsoft知识库中相应的文章:190985如何从OCX获取Excel或Word文档的IDispatch”

hope this is a hint - whish I had known this back than.... 希望这是一个提示-希望我早知道...

The following code solved my problem upon nabuchodonossor's comment: 以下代码根据nabuchodonossor的评论解决了我的问题:

       //Create don't kill processes
        var dontkill = new List<Process>();
        Process[] procs = Process.GetProcessesByName("EXCEL");
        foreach (Process p in procs)
        {
            dontkill.Add(p);
        }

        //EXCEL CODE HERE.

        xlWorkbook.Close();
        xlApp.Quit();

        //Now kill only the created process above.
        procs = Process.GetProcessesByName("EXCEL");
        foreach (Process p in procs)
        {
            if( !dontkill.Contains(p))
            {
                p.Kill();
            }
        }
        Marshal.FinalReleaseComObject(xlApp);

When I worked with the Excel Interop library, I opened and closed the document with the following code: 当我使用Excel Interop库时,我使用以下代码打开和关闭文档:

Application xlApp = null;
Workbook xlWorkbook = null;
_Worksheet xlWorksheet = null;
Range xlRange = null;

try
{
    xlApp = new Application();
    xlWorkbook = xlApp.Workbooks.Open(filename);
    xlWorksheet = xlWorkbook.Sheets[1];
    xlRange = xlWorksheet.UsedRange;

    // Do stuff with excel data
}
finally
{
    GC.Collect();
    GC.WaitForPendingFinalizers();

    //release com objects to fully kill excel process from running in the background
    if (xlRange != null)
    {
        Marshal.ReleaseComObject(xlRange);
    }

    if (xlWorksheet != null)
    {
        Marshal.ReleaseComObject(xlWorksheet);
    }

    //close and release
    if (xlWorkbook != null)
    {
        xlWorkbook.Close();
        Marshal.ReleaseComObject(xlWorkbook);
    }

    //quit and release
    if (xlApp != null)
    {
        xlApp.Quit();
        Marshal.ReleaseComObject(xlApp);
    }
}

Just another note to you guys, I decided to use ClosedXML. 再次提醒大家,我决定使用ClosedXML。

It took around 30 seconds for Interop Excel to read 750 rows. Interop Excel花费了大约30秒钟来读取750行。

Then it took ClosedXML 3 seconds to do the same thing with the following code which also does not leave any nasty processes behind: 然后,ClosedXML用了3秒的时间对以下代码执行相同的操作,该代码也不会留下任何讨厌的进程:

//Create empty OOB data list
        List<OOBList.OOBDetails> oob_data = new List<OOBList.OOBDetails>();

        string fileName = Server.MapPath("~/Uploads/OOB List/") + fname;
        using (var excelWorkbook = new XLWorkbook(fileName))
        {
            var nonEmptyDataRows = excelWorkbook.Worksheet(2).RowsUsed();

            foreach (var dataRow in nonEmptyDataRows)
            {
                //for row number check
                if (dataRow.RowNumber() >= 4 )
                {

                    string siteno = dataRow.Cell(1).GetValue<string>();
                    string sitename = dataRow.Cell(2).GetValue<string>();
                    string description = dataRow.Cell(4).GetValue<string>();
                    string cabinoob = dataRow.Cell(5).GetValue<string>();
                    string toweroob = dataRow.Cell(6).GetValue<string>();
                    string manageoob = dataRow.Cell(7).GetValue<string>();
                    string resolutiondate = dataRow.Cell(8).GetValue<string>();
                    string resolutiondate_converted = resolutiondate.Substring(resolutiondate.Length - 9);

                    oob_data.Add(new OOBList.OOBDetails
                    {
                        SiteNo = siteno,
                        SiteName = sitename,
                        Description = description,
                        CabinOOB = cabinoob,
                        TowerOOB = toweroob,
                        ManageOOB = manageoob,
                        TargetResolutionDate = resolutiondate_converted
                    });

                    Debug.Write("Adding SiteNo: " + siteno + "\n");
                }
            }
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM