[dot Net] 죽지 않는 엑셀 프로세스 죽이기
성은기 책임
[dot Net] 죽지 않는 엑셀 프로세스 죽이기
엑셀 내보내기를 .net에서 C#으로 처음으로 구현해봤습니다.
if (Grid.Rows.Count > 0)
{
Microsoft.Office.Interop.Excel.Application excel = null;
Workbook workbook = null;
Worksheet worksheet = null;
bool IsSuccess = false;
try
{
string SavePath = @"c:\저장경로\";
Directory.CreateDirectory(SavePath);
string PathFilename = SavePath + strFilename + @".xlsx";
excel = new Microsoft.Office.Interop.Excel.Application();
workbook = excel.Workbooks.Add(System.Reflection.Missing.Value);
worksheet = workbook.Worksheets.Item["Sheet1"];
excel.DisplayAlerts = false;
//column width
Range ModRange = worksheet.Columns[1];
ModRange.ColumnWidth = 4;
ModRange = worksheet.Columns[2];
ModRange.ColumnWidth = 4;
ModRange = worksheet.Columns[3];
ModRange.ColumnWidth = 18;
ModRange.NumberFormat = "@";
//title
ModRange = (Range)worksheet.get_Range("A1", "W1");
ModRange.Merge(true);
ModRange.Value = "Title";
ModRange.Font.Size = 16;
ModRange.Font.Bold = true;
ModRange.HorizontalAlignment = XlHAlign.xlHAlignCenter;
ModRange.BorderAround2(XlLineStyle.xlContinuous, XlBorderWeight.xlMedium, XlColorIndex.xlColorIndexAutomatic, XlColorIndex.xlColorIndexAutomatic);
//report time
ModRange = (Range)worksheet.get_Range("A2", "W2");
ModRange.Merge(true);
ModRange.Value = "Report Date: " + DateTime.Now.ToString();
ModRange.HorizontalAlignment = XlHAlign.xlHAlignRight;
//head
for (int i = 0; i < Grid.Columns.Count; i++)
{
ModRange = (Range)worksheet.Cells[3, 1 + i];
ModRange.Value = Grid.Columns[i].HeaderText;
ModRange.HorizontalAlignment = XlHAlign.xlHAlignCenter;
//data 테두리
ModRange.BorderAround2(XlLineStyle.xlContinuous, XlBorderWeight.xlThin, XlColorIndex.xlColorIndexAutomatic, XlColorIndex.xlColorIndexAutomatic);
ModRange.Borders[XlBordersIndex.xlEdgeTop].Weight = XlBorderWeight.xlMedium;
if (i == 0)
{
ModRange.Borders[XlBordersIndex.xlEdgeLeft].Weight = XlBorderWeight.xlMedium;
}
else if (i == (Grid.Columns.Count - 1))
{
ModRange.Borders[XlBordersIndex.xlEdgeRight].Weight = XlBorderWeight.xlMedium;
}
ModRange.Borders[XlBordersIndex.xlEdgeBottom].LineStyle = XlLineStyle.xlDouble;
ModRange.Borders[XlBordersIndex.xlEdgeBottom].Weight = XlBorderWeight.xlThick;
//////
}
//data
for (int i = 0; i < Grid.Rows.Count; i++)
{
for (int j = 0; j < Grid.Columns.Count; j++)
{
ModRange = (Range)worksheet.Cells[4 + i, 1 + j];
ModRange.Value = Grid[j, i].Value == null ? "" : Grid[j, i].Value.ToString();
//data 테두리
ModRange.BorderAround2(XlLineStyle.xlContinuous, XlBorderWeight.xlThin, XlColorIndex.xlColorIndexAutomatic, XlColorIndex.xlColorIndexAutomatic);
if (j == 0)
{
ModRange.Borders[XlBordersIndex.xlEdgeLeft].Weight = XlBorderWeight.xlMedium;
}
else if (j == (Grid.Columns.Count - 1))
{
ModRange.Borders[XlBordersIndex.xlEdgeRight].Weight = XlBorderWeight.xlMedium;
}
if (i == (Grid.Rows.Count - 1))
{
ModRange.Borders[XlBordersIndex.xlEdgeBottom].Weight = XlBorderWeight.xlMedium;
}
//////
}
}
workbook.SaveAs(Filename: PathFilename);
workbook.Close();
excel.Quit();
IsSuccess = true;
}
catch (Exception ex)
{
IsSuccess = false;
MessageBox.Show("저장에 실패하였습니다.", "오류", MessageBoxButtons.OK, MessageBoxIcon.Warning);
Console.WriteLine(ex.ToString());
}
if (IsSuccess)
{
MessageBox.Show("저장 완료", "정보", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
else
{
MessageBox.Show("데이터가 없습니다.\n 검색을 먼저 실행해주십시오.", "오류", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
원래 소스에서는 명칭도 다르고 메인 폼의 상태 바에서 프로그레스로 진행률 표시한다고
부분적으로 좀 다르기는 한데 엑셀 파일 내보내기 부분만 보면 위와 같습니다.
약간의 노가다(?)를 요하는 테두리 작업까지 완료되어
전체적으로 쉽게 쓸 수 있게 잘 만들어져있다고 생각했습니다.
꾸미기 부분이 반이 넘을 뿐 실제로 소스는 단순합니다.
그러나…
이대로는 내보내기 횟수 만큼 엑셀 프로세스가 증가합니다.
PC를 재부팅하니 테스트 한 수만큼의 무수히 많은 엑셀파일이 열렸습니다.
아시다시피 윈도우10은 실행중인 프로세스를 재시작 시 이어서 실행합니다.
PC가 종료 될 때 그 개수만큼 프로세스가 남아 있었던 겁니다.
프로세스를 이어서 재시작하지 않았으면 엑셀 프로세스가 죽지 않는 걸 모를 뻔했습니다!
라이브러리에서 종료하는 부분이 떡하니 들어가 있어서
릴리즈 될 것을 기대했는데 죽지 않는다니.. .net을 욕했습니다.
그래서 Excel 이름의 프로세스를 죽이자니
사용자가 엑셀을 사용하고 있을 경우를 생각해야 하여
어떻게 할지 ‘c# excel process not closing‘으로 구글링하니
역시나 여러 글들을 발견할 수 있습니다.
이렇게 죽지 않는 엑셀 프로세스를 죽이는 언데드 소탕을 시작했습니다.
FinalReleaseComObject
를 사용하라는 여러 글들이 많았는데
몇 가지 구현 방법을 따라하고 만들었으나
구현 방법의 문제인지 테스트 결과 신뢰도가 떨어져
사용자가 엑셀을 사용하고 있을 경우를 대비하여
생성할 때 만든 엑셀 프로세스의 핸들의 프로세스 아이디(PID)를 받아
만들어진 엑셀 프로세스를 소탕하였습니다.
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
workbook.SaveAs(Filename: PathFilename);
workbook.Close();
uint processId = 0;
GetWindowThreadProcessId(new IntPtr(excel.Hwnd), out processId);
excel.Quit();
if (processId != 0)
{
System.Diagnostics.Process excelProcess = System.Diagnostics.Process.GetProcessById((int)processId);
excelProcess.CloseMainWindow();
excelProcess.Refresh();
excelProcess.Kill();
}