关于c#:Excel进程没有关闭

Excel process not closing

本问题已经有最佳答案,请猛点这里访问。

我有一个不会关闭Excel进程的C程序。基本上,它会找到一个字符串出现在Excel范围内的实例数。我试过各种方法,但都不管用。有一个窗体正在调用此方法,但这不应改变进程未关闭的原因。我看过汉斯·帕桑特的建议,但都没用。

编辑:我试过上面提到的东西,但还是不能关闭。这是我的更新代码。edit:尝试了整个过程。kill()并且它可以工作,但是对于一些应该工作的东西来说,它看起来有点像是一个黑客。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
public class CompareHelper
{
    // Define Variables
    Excel.Application excelApp = null;
    Excel.Workbooks wkbks = null;
    Excel.Workbook wkbk = null;
    Excel.Worksheet wksht = null;
    Dictionary<String, int> map = new Dictionary<String, int>();

    // Compare columns
    public void GetCounts(string startrow, string endrow, string columnsin, System.Windows.Forms.TextBox results, string excelFile)
    {
        results.Text ="";

        try
        {
            // Create an instance of Microsoft Excel and make it invisible
            excelApp = new Excel.Application();
            excelApp.Visible = false;

            // open a Workbook and get the active Worksheet
            wkbks = excelApp.Workbooks;
            wkbk = wkbks.Open(excelFile, Type.Missing, true);
            wksht = wkbk.ActiveSheet;
            ...

        }
        catch
        {
            throw;
        }
        finally
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();

            if (wksht != null)
            {
                //wksht.Delete();
                Marshal.FinalReleaseComObject(wksht);
                wksht = null;
            }

            if (wkbks != null)
            {
                //wkbks.Close();
                Marshal.FinalReleaseComObject(wkbks);
                wkbks = null;
            }

            if (wkbk != null)
            {
                excelApp.DisplayAlerts = false;
                wkbk.Close(false, Type.Missing, Type.Missing);
                Marshal.FinalReleaseComObject(wkbk);
                wkbk = null;
            }

            if (excelApp != null)
            {
                excelApp.Quit();
                Marshal.FinalReleaseComObject(excelApp);
                excelApp = null;
            }

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            GC.WaitForPendingFinalizers();

            /*
            Process[] processes = Process.GetProcessesByName("EXCEL");
            foreach (Process p in processes)
            {
                p.Kill();
            }
            */

        }
    }
}


下面是一个有趣的知识库,内容是在.NET应用程序与Office应用程序断开连接后保持打开状态。

从Visual Studio.NET客户端自动化后,Office应用程序不会退出。

代码示例都在链接中(vb.net抱歉)。基本上,它向你展示了如何正确地设置和拆卸Office应用程序,这样当你完成它时,它就会关闭。

魔法发生的地方是System.Runtime.InteropServices.Marshal.FinalReleaseComObject

编辑:您需要为您创建的每个Excel对象调用finalReleaseComObject。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if (excelWorkSheet1 != null)
{
    Marshal.FinalReleaseComObject(excelWorkSheet1);
    excelWorkSheet1 = null;
}
if (excelWorkbook != null)
{
    Marshal.FinalReleaseComObject(excelWorkbook);
    excelWorkbook = null;
}
if (excelApp != null)
{
    Marshal.FinalReleaseComObject(excelApp);
    excelApp = null;
}


只有在释放了所有句柄之后,DOTNET才会释放COM对象。我要做的是将所有内容都注释掉,然后再添加一部分。看看它是否发布Excel。如果不遵守以下规则。当它释放时,添加更多的代码,直到它不再释放。

1)创建Excel变量时,将所有值设置为空(这样可以避免未启动的错误)。

2)在不首先释放变量的情况下,不要重复使用变量。

3)不要用双点号(a.b = z)。dotnet创建一个临时变量,它不会被释放。

2

4)释放所有Excel变量。越快越好。

5)设置为空。

将文化设置为"en-us"。有一个bug使Excel在某些文化中崩溃。这确保了它不会。

下面是您的代码应该如何构造的一个概念:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
        thisThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
        InteropExcel.Application excelApp = null;
        InteropExcel.Workbooks wkbks = null;
        InteropExcel.Workbook wkbk = null;
        try
        {
                excelApp = new InteropExcel.Application();
                wkbks = excelApp.Workbooks;
                wkbk = wkbks.Open(fileName);
...

        }
        catch (Exception ex)
        {
        }

        if (wkbk != null)
        {
            excelApp.DisplayAlerts = false;
            wkbk.Close(false);
            Marshal.FinalReleaseComObject(wkbk);
            wkbk = null;
        }

        if (wkbks != null)
        {
            wkbks.Close();
            Marshal.FinalReleaseComObject(wkbks);
            wkbks = null;
        }

        if (excelApp != null)
        {
            // Close Excel.
            excelApp.Quit();
            Marshal.FinalReleaseComObject(excelApp);
            excelApp = null;
        }

        // Change culture back from en-us to the original culture.
        thisThread.CurrentCulture = originalCulture;    
    }


我终于把它关闭了。您需要为工作簿集合添加一个变量,然后使用finalReleaseComObject,如其他答案中所述。我想您使用的所有可能的Excel COM对象都必须这样处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
try
        {
           // Create an instance of Microsoft Excel and make it invisible
           excelApp = new Excel.Application();
           excelApp.DisplayAlerts = false;
           excelApp.Visible = false;

           // open a Workbook and get the active Worksheet

           excelWorkbooks = excelApp.Workbooks;
           excelWorkbook = excelWorkbooks.Open(excelFile, Type.Missing, true);
           excelWorkSheet1 = excelWorkbook.ActiveSheet;

        }
        catch
        {
           throw;
        }
        finally
        {

           NAR( excelWorkSheet1 );
           excelWorkbook.Close(false, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
           NAR(excelWorkbook);
           NAR(excelWorkbooks);
           excelApp.Quit();
           NAR(excelApp);

        }
     }
     private void NAR(object o)
     {
        try
        {
           System.Runtime.InteropServices.Marshal.FinalReleaseComObject( o );
        }
        catch { }
        finally
        {
           o = null;
        }
     }