버그 해결을 위한 모든 질문을 던져
0 votes
453 views
먼저 코드는 다음과 같습니다.
                Excel.Application excelApp = new Excel.Application();
                Excel.Workbooks workbooks = excelApp.Workbooks;
                Excel.Workbook wb = workbooks.Add(Type.Missing);
                Excel.Sheets sheets = wb.Worksheets;
                Excel.Worksheet ws = (Excel.Worksheet)wb.ActiveSheet;
                Excel.Range cells = (Excel.Range)ws.Cells;
                Excel.Range rng = ws.Range[cells[1, 1], cells[3 * (DataReceiveNumbers + 2) + 4, 20]];

....
                    wb.Close();
                    workbooks.Close();
                    excelApp.Quit();
                    ReleaseExcelObject(rng);
                    ReleaseExcelObject(cells);
                    ReleaseExcelObject(ws);
                    ReleaseExcelObject(sheets);
                    ReleaseExcelObject(wb);
                    ReleaseExcelObject(workbooks);
                    ReleaseExcelObject(excelApp);

 

이 부분을 제외한 나머지 코드는 주석처리 해놓았습니다. 아래와 같은 방식으로 한 줄씩 주석처리 하며 어떤 객체가 Release 되지 않았는지 확인한 결과 rng가 Release 되지 않았다는 것을 알게 되었습니다.

                Excel.Application excelApp = new Excel.Application();
                //Excel.Workbooks workbooks = excelApp.Workbooks;
                //Excel.Workbook wb = workbooks.Add(Type.Missing);
                //Excel.Sheets sheets = wb.Worksheets;
                //Excel.Worksheet ws = (Excel.Worksheet)wb.ActiveSheet;
                //Excel.Range cells = (Excel.Range)ws.Cells;
                //Excel.Range rng = ws.Range[cells[1, 1], cells[3 * (DataReceiveNumbers + 2) + 4, 20]];

                  //  wb.Close();
                  //  workbooks.Close();
                    excelApp.Quit();
                   // ReleaseExcelObject(rng);
                   // ReleaseExcelObject(cells);
                   // ReleaseExcelObject(ws);
                   // ReleaseExcelObject(sheets);
                   // ReleaseExcelObject(wb);
                   // ReleaseExcelObject(workbooks);
                    ReleaseExcelObject(excelApp);

어떻게하면 rng를 Release 시킬 수 있을까요?
asked (5 point) , 453 views
마소 엑셀을 사용 안하셔도 됩니다 좀더 가벼운 epplus 사용해보세용

3 answers

0 votes
우수 답변

ReleaseExcelObject 함수가 정확히 어떤 코드인지 알 수 없어서 제 답이 틀릴 수도 있겠지만
System.Runtime.InteropServices.Marshal.ReleaseComObject를 실행시키는 함수로 보이네요.

 

일단 질문의 코드를 다시 테스트 해 본 결과 이상없이 잘 작동합니다.

다만, 엑셀이 바로 종료되지는 않고 약간의 딜레이가 있네요.

코드 실행 후에 10초 정도 기다려보면 어떨까 싶네요

 

일단 테스트 코드는 아래와 같습니다. 질문의 코드와 거의 똑같습니다.

private void Run()
{
	Excel.Application excelApp = new Excel.Application();
	Excel.Workbooks workbooks = excelApp.Workbooks;
	Excel.Workbook wb = workbooks.Add(Type.Missing);
	Excel.Sheets sheets = wb.Worksheets;
	Excel.Worksheet ws = (Excel.Worksheet)wb.ActiveSheet;
	Excel.Range cells = ws.Cells;
	Excel.Range rng = ws.Range[cells[1, 1], cells[3 * (3 + 2) + 4, 20]];

	wb.Close();
	workbooks.Close();
	excelApp.Quit();
	Marshal.ReleaseComObject(rng);
	Marshal.ReleaseComObject(cells);
	Marshal.ReleaseComObject(ws);
	Marshal.ReleaseComObject(sheets);
	Marshal.ReleaseComObject(wb);
	Marshal.ReleaseComObject(workbooks);
	Marshal.ReleaseComObject(excelApp);
}

 

answered (143 point)
선택됨
테스트 해주셔서 감사합니다.

ReleaseExcelObject 함수는 Marshal.ReleaseComObject 함수가 맞으며 제 코드와 완전히 같습니다.

 

답변자님의 조언대로 2분 이상 기다려봤지만 Excel.exe는 종료되지 않았습니다 ㅠㅠㅠ

그래서 엑셀 파일로 저장하는 메소드가 실행되기 전에 실행되어있는 Excel.exe Process ID를 기억한 후 엑셀 파일 저장 후 기억하고 있는 Excel.exe의 Process ID를 제외한 나머지를 Kill 하는 방식을 사용했습니다. 코드는 다음과 같습니다.

            #region
            System.Diagnostics.Process[] BeforeExcelProcess;
            BeforeExcelProcess = System.Diagnostics.Process.GetProcessesByName("EXCEL");
            ArrayList arlProcessID = new ArrayList();
            for (int i = 0; i < BeforeExcelProcess.Length; i++)
            {
                arlProcessID.Add(BeforeExcelProcess[i].Id);
            }
            #endregion

 

....

 

                     System.Diagnostics.Process[] AfterExcelProcess;
                    AfterExcelProcess = System.Diagnostics.Process.GetProcessesByName("EXCEL");

                    for (int i = 0; i < AfterExcelProcess.Length; i++)
                    {
                        if (!arlProcessID.Contains(AfterExcelProcess[i].Id))
                            AfterExcelProcess[i].Kill();
                    }

이렇게 하니까 해결이 되었습니다. 강제로 프로세스를 Kill 해버리는 방식이라 어디서 문제가 생길 지는 모르겠지만요 ㅠㅠ

아무튼 귀한 시간 내주셔서 테스트해주셔서 정말 감사합니다.
어차피 공부도 되고 남는 게 시간이라 조금 더 테스트 해보았습니다.

일단 테스트 환경에서 차이가 발생한 것 같더군요

 

제 답변에서는 WPF 를 사용해서 창이 초기화 할 때 해당 함수를 실행했었습니다만
콘솔 환경에서 저 함수를 실행하고 Console.ReadLine으로 코드를 일시 정지를 걸으니 질문자님과 같은 증상이 발생하더군요.

 

추측으로는 GC와 관련되어 이러한 차이가 발생한 것으로 보입니다.

참조: https://stackoverflow.com/a/159419

위 링크의 답변을 참고하여  GC.Collect를 추가로 호출해 주니 Excel 프로세스가 종료되는 것을 확인했습니다. 물론 GC의 특성 상 결과를 보장해주지는 않으며 참조의 답변에도 확실하게 하기 위해 GC를 두번 호출했으니 참고하세요.
+2 votes

아래의 글로 정리해 봤습니다.

C# - Excel(을 비롯해 Office 제품군) COM 객체를 제어 후 Excel.exe 프로세스가 남아 있는 문제
; http://www.sysnet.pe.kr/2/0/11997

answered (185 point)
0 votes

저같은 경우는

 

static void ReleaseExcelObject(object obj)
{
    try
    {
        if (obj != null)
        {
            Marshal.ReleaseComObject(obj);
            obj = null;
        }
    }
    catch (Exception e)
    {
        obj = null;
        throw e;
    }
    finally
    {
        GC.Collect();
    }
}

 

위 함수를 사용하구요

엑셀 오브젝트 사용할때

 

try {

} catch (Exception e){

} finally {
    ReleaseExcelObject(시트);
    ReleaseExcelObject(워크북);
    ReleaseExcelObject(app);
}

 

이런식으로 사용하는데

프로그램을 강제종료 하지 않는한 ComObject들 잘 지워집니다.

테스트 해 보세용

answered (33 point)

버그 해결을 위해 도움을 구하고, 도움을 주세요. 우리는 그렇게 발전합니다.

throw bug 는 프로그래밍에 대한 전분야를 다룹니다. 질문,논의거리,팁,정보공유 모든 것이 가능합니다. 프로그래밍과 관련이 없는 내용은 환영받지 못합니다.

254 질문
388 answers
396 댓글
508 users