programing

C#에서 Excel interop 개체를 안전하게 폐기하시겠습니까?

bestprogram 2023. 9. 4. 20:28

C#에서 Excel interop 개체를 안전하게 폐기하시겠습니까?

저는 winforms c# visual studio 2008 애플리케이션을 개발하고 있습니다.그 앱은 엑셀 파일과 대화하고 나는 사용하고 있습니다.Microsoft.Office.Interop.Excel;이를 위해.

오류가 발생했을 때도 물체가 확실히 해제되도록 하려면 어떻게 해야 하는지 알고 싶습니다.

내 코드는 다음과 같습니다.

private void button1_Click(object sender, EventArgs e)
{
    string myBigFile="";
    OpenFileDialog openFileDialog1 = new OpenFileDialog();
    DialogResult result = openFileDialog1.ShowDialog(); // Show the dialog.
    if (result == DialogResult.OK) // Test result.
        myBigFile=openFileDialog1.FileName;

    Excel.Application xlApp;
    Excel.Workbook xlWorkBook;
    Excel.Worksheet xlWorkSheet;
    Excel.Range range;

    string str;
    int rCnt = 0;
    int cCnt = 0;

    xlApp = new Excel.ApplicationClass();
    xlWorkBook = xlApp.Workbooks.Open(myBigFile, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", true, false, 0, true, 1, 0);
    xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);

    range = xlWorkSheet.UsedRange;

    /*
    for (rCnt = 1; rCnt <= range.Rows.Count; rCnt++)
    {
        for (cCnt = 1; cCnt <= range.Columns.Count; cCnt++)
        {
            str = (string)(range.Cells[rCnt, cCnt] as Excel.Range).Value2;
            MessageBox.Show(str);
        }
    }
     */
    xlWorkSheet..EntireRow.Delete(Excel.XLDirection.xlUp)

    xlWorkBook.SaveAs(xlWorkBook.Path + @"\XMLCopy.xls",         Excel.XlFileFormat.xlXMLSpreadsheet, Type.Missing, Type.Missing,
   false, false, Excel.XlSaveAsAccessMode.xlNoChange,
   Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

    xlWorkBook.Close(true, null, null);
    xlApp.Quit();

    releaseObject(xlWorkSheet);
    releaseObject(xlWorkBook);
    releaseObject(xlApp);
}

private void releaseObject(object obj)
{
    try
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
        obj = null;
    }
    catch (Exception ex)
    {
        obj = null;
        MessageBox.Show("Unable to release the Object " + ex.ToString());
    }
    finally
    {
        GC.Collect();
    }
}

워크북을 연 후 오류가 발생하더라도 개체를 삭제하려면 어떻게 해야 합니까?

Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
Excel.Range range;

즉, 다음 행이 필요한 경우에도 실행됩니다.

xlWorkBook.Close(true, null, null);
xlApp.Quit();

releaseObject(xlWorkSheet);
releaseObject(xlWorkBook);
releaseObject(xlApp);

저도 이것을 시도했고, 그 결과 같은 문제가 발생했다는 것을 알아두세요.

xlWorkBook.Close(false, System.Reflection.Missing.Value, System.Reflection.Missing.Value);


                xlApp.Quit();

                Marshal.ReleaseComObject(xlWorkSheet);
                Marshal.ReleaseComObject(xlWorkBook);
                Marshal.ReleaseComObject(xlApp);

                xlWorkSheet = null;
                xlWorkBook = null;
                xlApp = null;

                GC.GetTotalMemory(false);
                GC.Collect();
                GC.WaitForPendingFinalizers();
                GC.Collect();
                GC.GetTotalMemory(true);  

그리고 저는 이것도 했습니다.

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

                Marshal.FinalReleaseComObject(xlWorkSheet);

                xlWorkBook.Close(Type.Missing, Type.Missing, Type.Missing);
                Marshal.FinalReleaseComObject(xlWorkBook); 

                xlApp.Quit();
                Marshal.FinalReleaseComObject(xlApp); 

이 시점에서 저는 비주얼 스튜디오 2008에서 엑셀을 닫는 것이 가능하다고 생각하지 않습니다. 버그 같은 것이 틀림없지만, 저는 이것에 대해 상위 20개의 웹사이트를 시도했고 같은 결과를 얻었습니다: 엑셀은 어떤 이유에서인지 두 개의 인스턴스를 열고 있고 쓰레기 수집 등을 할 때입니다.하나의 인스턴스만 닫거나 닫지 않습니다.

파일을 열려고 하면 오류가 있거나 파일이 손상되었다고 표시됩니다.

내가 작업 관리자에게 가서 엑셀 프로세스를 죽이면, 파일은 문제없이 열릴 것입니다.]

비주얼 스튜디오 2008과 엑셀을 닫는 방법이 있습니까? 그렇다면 이에 대한 지침이나 해결책을 제공해 주시겠습니까?

먼저 수정된 내용을 발표하겠습니다.releaseObject그런 다음 사용할 수 있는 패턴을 제공하겠습니다.

using Marshal = System.Runtime.InteropServices.Marshal;
private void releaseObject(ref object obj) // note ref!
{
    // Do not catch an exception from this.
    // You may want to remove these guards depending on
    // what you think the semantics should be.
    if (obj != null && Marshal.IsComObject(obj)) {
        Marshal.ReleaseComObject(obj);
    }
    // Since passed "by ref" this assingment will be useful
    // (It was not useful in the original, and neither was the
    //  GC.Collect.)
    obj = null;
}

이제 사용할 패턴:

private void button1_Click(object sender, EventArgs e)
{
    // Declare. Assign a value to avoid a compiler error.
    Excel.Application xlApp = null;
    Excel.Workbook xlWorkBook = null;
    Excel.Worksheet xlWorkSheet = null;

    try {
        // Initialize
        xlApp = new Excel.ApplicationClass();
        xlWorkBook = xlApp.Workbooks.Open(myBigFile, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", true, false, 0, true, 1, 0);
        // If the cast fails this like could "leak" a COM RCW
        // Since this "should never happen" I wouldn't worry about it.
        xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
        ...
    } finally {
        // Release all COM RCWs.
        // The "releaseObject" will just "do nothing" if null is passed,
        // so no need to check to find out which need to be released.
        // The "finally" is run in all cases, even if there was an exception
        // in the "try". 
        // Note: passing "by ref" so afterwords "xlWorkSheet" will
        // evaluate to null. See "releaseObject".
        releaseObject(ref xlWorkSheet);
        releaseObject(ref xlWorkBook);
        // The Quit is done in the finally because we always
        // want to quit. It is no different than releasing RCWs.
        if (xlApp != null) {
            xlApp.Quit();
        }
        releaseObject(ref xlApp);    
    }
}

이 간단한 접근 방식은 대부분의 상황에서 확장/내포될 수 있습니다.나는 이 작업을 쉽게 하기 위해 ID를 구현하는 사용자 지정 래퍼 클래스를 사용합니다.

코드에 두 가지 문제가 있는지 확인합니다.

  • 프로그램이 닫힐 때 Excel은 실행 중인 프로세스로 남아 있습니다.
  • 당신이 엑셀 파일을 열었을 때 당신의 프로그램이 엑셀에서 파일이 손상되었다는 에러를 볼 수 있습니다.

버튼1 클릭 핸들러와 pst를 복사했습니다.releaseObject편집한 질문의 메서드를 깨끗한 VS2008, C#3.5 Winform 응용 프로그램으로 변환하고 위에 나열한 두 가지 문제를 모두 제거하기 위해 몇 가지 사소한 변경을 가했습니다.

Excel이 메모리에서 언로드되지 않도록 수정하려면 전화하십시오.releaseObject에서range생성한 개체입니다.전화를 걸기 전에 이 작업을 수행하십시오.releaseObject(xlWorkSheet);이러한 모든 참조를 기억하는 것이 COM Interop 프로그래밍을 매우 재미있게 만드는 이유입니다.

하려면 Excel 파일을 하십시오.WorkBook.SaveAs파라미터를 호출()Excel.XlFileFormat.xlXMLSpreadsheet)와 함께Type.Missing.SaveAs메서드는 기본적으로 이 문제를 올바르게 처리합니다.

질문에 게시한 코드는 현재 발생하고 있는 문제를 디버깅하는 데 도움이 되도록 단순화되어 있습니다.은 다을사합니다야를 해야 합니다.try..finally블록 pst가 시연합니다.

언급URL : https://stackoverflow.com/questions/9962157/safely-disposing-excel-interop-objects-in-c