IT

c# 및 excel 자동화 - 실행 중인 인스턴스 종료

itgroup 2023. 8. 21. 21:05
반응형

c# 및 excel 자동화 - 실행 중인 인스턴스 종료

저는 C#을 통해 엑셀 자동화를 시도하고 있습니다.저는 이 문제에 대한 Microsoft의 지침을 모두 지켰지만, Excel을 닫고 GC가 이를 수집할 수 있도록 하기 위해 Excel에 대한 최종 참조를 폐기하는 데 여전히 어려움을 겪고 있습니다.

다음은 코드 샘플입니다.다음과 유사한 행이 포함된 코드 블록을 주석 처리할 때:

Sheet.Cells[iRowCount, 1] = data["fullname"].ToString();

그러면 파일이 저장되고 Excel이 종료됩니다.그렇지 않으면 파일은 저장되지만 Excel은 프로세스로 실행됩니다.다음 번에 이 코드를 실행하면 새 인스턴스가 생성되고 해당 인스턴스가 생성됩니다.

어떤 도움이든 감사합니다.감사해요.

이것이 내 코드의 기본입니다.

        Excel.Application xl = null;
        Excel._Workbook wBook = null;
        Excel._Worksheet wSheet = null;
        Excel.Range range = null;

        object m_objOpt = System.Reflection.Missing.Value;

        try
        {
            // open the template
            xl = new Excel.Application();
            wBook = (Excel._Workbook)xl.Workbooks.Open(excelTemplatePath + _report.ExcelTemplate, false, false, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt);
            wSheet = (Excel._Worksheet)wBook.ActiveSheet;

            int iRowCount = 2;

            // enumerate and drop the values straight into the Excel file
            while (data.Read())
            {

                wSheet.Cells[iRowCount, 1] = data["fullname"].ToString();
                wSheet.Cells[iRowCount, 2] = data["brand"].ToString();
                wSheet.Cells[iRowCount, 3] = data["agency"].ToString();
                wSheet.Cells[iRowCount, 4] = data["advertiser"].ToString();
                wSheet.Cells[iRowCount, 5] = data["product"].ToString();
                wSheet.Cells[iRowCount, 6] = data["comment"].ToString();
                wSheet.Cells[iRowCount, 7] = data["brief"].ToString();
                wSheet.Cells[iRowCount, 8] = data["responseDate"].ToString();
                wSheet.Cells[iRowCount, 9] = data["share"].ToString();
                wSheet.Cells[iRowCount, 10] = data["status"].ToString();
                wSheet.Cells[iRowCount, 11] = data["startDate"].ToString();
                wSheet.Cells[iRowCount, 12] = data["value"].ToString();

                iRowCount++;
            }

            DirectoryInfo saveTo = Directory.CreateDirectory(excelTemplatePath + _report.FolderGuid.ToString() + "\\");
            _report.ReportLocation = saveTo.FullName + _report.ExcelTemplate;
            wBook.Close(true, _report.ReportLocation, m_objOpt);
            wBook = null;

        }
        catch (Exception ex)
        {
            LogException.HandleException(ex);
        }
        finally
        {
            NAR(wSheet);
            if (wBook != null)
                wBook.Close(false, m_objOpt, m_objOpt);
            NAR(wBook);
            xl.Quit();
            NAR(xl);
            GC.Collect();
        }

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

갱신하다

어떤 방법을 시도하든 '깨끗한' 방법이든 '못생긴' 방법이든(아래 답변 참조) Excel 인스턴스는 이 줄이 닿자마자 계속 작동합니다.

wSheet.Cells[iRowCount, 1] = data["fullname"].ToString();

만약 내가 그 선을 언급하면 (그리고 그 아래에 있는 다른 유사한 것들은 분명히) Excel 앱은 우아하게 종료됩니다.위의 한 줄에 대한 설명이 없는 즉시 Excel이 계속 표시됩니다.

xl 변수를 할당하기 전에 실행 중인 인스턴스가 있는지 확인하고 그 대신에 후크를 연결해야 할 것 같습니다.윈도우 서비스라는 걸 깜빡했는데, 그건 상관없겠죠?


갱신하다(2016년 11월)

나는 방금 한스 패상의 설득력 있는 주장을 읽었다.GC.Collect그게 사실 옳은 길입니다.저는 더 이상 Office와 함께 일하지 않지만(감사합니다), 만약 제가 그렇게 했다면 아마도 이것을 다시 시도하고 싶을 것입니다. 그것은 제가 "올바른" 방식으로 일을 처리하기 위해 작성한 수많은 (수천 줄의) 코드를 확실히 단순화할 것입니다.

나의 원래 대답은 후세를 위해 남겨둘 것입니다...


Mike가 답변에서 말했듯이, 이것을 다루는 쉬운 방법과 어려운 방법이 있습니다.마이크는 쉬운 방법을 사용할 것을 제안합니다. 왜냐하면...그게 더 쉽습니다.저는 개인적으로 그것이 충분한 이유라고 생각하지 않습니다. 그리고 그것이 올바른 방법이라고 생각하지 않습니다.그것은 저에게 "끄었다가 다시 켜졌다"라는 느낌이 듭니다.

저는 에서 오피스 자동화 애플리케이션을 개발한 경험이 몇 년 있습니다.NET, 그리고 이러한 COM 인터럽트 문제는 제가 처음 이 문제에 부딪혔을 때 처음 몇 주와 몇 달 동안 저를 괴롭혔는데, 특히 마이크로소프트가 애초에 문제가 있다는 것을 인정하는 것에 대해 매우 수줍어했기 때문입니다. 그리고 그 당시에는 웹에서 좋은 조언을 찾기가 어려웠습니다.

저는 이제 생각 없이 가상으로 사용하는 작업 방식을 가지고 있으며, 문제가 생긴 지 몇 년이 되었습니다.생성할 수 있는 모든 숨겨진 개체를 인식하는 것은 여전히 중요합니다. 그리고 예, 하나를 놓치면 훨씬 나중에야 명백해지는 누출이 발생할 수 있습니다.하지만 그것은 나쁜 옛날의 상황보다 나쁘지 않습니다.malloc/free.

저는 마지막이 아니라 가면서 뒷정리를 하는 것에 대해 할 말이 있다고 생각합니다.Excel을 시작하여 몇 개의 셀만 채우는 경우에는 문제가 되지 않을 수도 있습니다. 하지만 무거운 물건을 들어올리려면 다른 문제입니다.

▁thatlements▁class▁imp▁wrapper▁anyway▁a▁i것다를 구현하는 래퍼 클래스를 사용하는 것입니다.IDisposable그리고 그 안에 있는 것.Dispose 호출 메드호출ReleaseComObject내가 사용할 수 있는 방법using개체가 삭제되고 COM 개체가 해제되었는지 확인하는 문장입니다.

결정적으로, 제 기능이 일찍 돌아오거나 예외가 발생하는 등의 경우에도 폐기/해제될 것입니다.또한, 애초에 실제로 생성된 경우에만 폐기/해제될 입니다. 페던트라고 부르지만 실제로 생성되지 않았을 수 있는 객체를 릴리스하려는 제안된 코드는 엉성한 코드로 보입니다.FinalReleaseComObject를 사용하는 것에 대해서도 비슷한 반대 의견이 있습니다. COM 참조를 생성한 횟수를 알고 있으므로 동일한 횟수만큼 릴리스할 수 있어야 합니다.

일반적인 코드 조각은 다음과 같이 보일 수 있습니다(또는 C# v2를 사용하고 제네릭을 사용할 수 있다면:-).

using (ComWrapper<Excel.Application> application = new ComWrapper<Excel.Application>(new Excel.Application()))
{
  try
  {
    using (ComWrapper<Excel.Workbooks> workbooks = new ComWrapper<Excel.Workbooks>(application.ComObject.Workbooks))
    {
      using (ComWrapper<Excel.Workbook> workbook = new ComWrapper<Excel.Workbook>(workbooks.ComObject.Open(...)))
      {
        using (ComWrapper<Excel.Worksheet> worksheet = new ComWrapper<Excel.Worksheet>(workbook.ComObject.ActiveSheet))
        {
          FillTheWorksheet(worksheet);
        }
        // Close the workbook here (see edit 2 below)
      }
    }
  }
  finally
  {
    application.ComObject.Quit();
  }
}

이제, 저는 그것이 말이 아닌 척하지 않을 것입니다. 그리고 만약 여러분이 그것들을 더 작은 방법으로 나누지 않는다면, 객체 생성으로 인한 들여쓰기는 통제할 수 없을 것입니다.이 예는 최악의 경우입니다. 우리가 하는 일은 객체를 만드는 것뿐이기 때문입니다.일반적으로 교정기 사이에는 훨씬 더 많은 일이 일어나고 오버헤드는 훨씬 적습니다.

저는 '메소드 이며, 개체가 아니며으로 위예에따랩르면, , 할며대로거벌는벗은달이의것책호객폐것아로).using물체를 , 는 그것을입니다.마찬가지로, 저는 항상 벌거벗은 물체가 아닌 포장된 물체를 반환할 것이며, 다시 한번 그것을 해제하는 것은 발신자의 책임일 것입니다.다른 프로토콜을 사용할 수도 있지만, 메모리 관리를 직접 해야 했던 것처럼 명확한 규칙을 갖는 것이 중요합니다.

ComWrapper<T>여기서 사용되는 수업은 거의 설명이 필요하지 않기를 바랍니다. 개체에 (" "COM" 사용).ReleaseComObject그 안에서Dispose방법. 그ComObjectmethod는 입력된 참조를 래핑된 COM 개체로 반환합니다.

이것이 도움이 되길 바랍니다!

편집: 저는 이제 다른 질문에 대한 마이크의 답변에 대한 링크를 따라갔고, 위에서 제안한 것처럼 그 질문에 대한 또 다른 대답이 래퍼 클래스에 대한 링크를 가지고 있다는 것을 알게 되었습니다.

에 대한 는 " 사용해요, GC.Collectㅠㅠ . 가 없을 것처럼 .하지만, 저는 주로 잘못된 전제에서 그것에 끌렸습니다. 언뜻 보기에는 COM 참조에 대해 전혀 걱정할 필요가 없을 것처럼 보였습니다.그러나 Mike가 말했듯이 모든 범위 내 변수와 관련된 COM 개체를 여전히 명시적으로 릴리스해야 합니다. 따라서 COM 개체 관리의 필요성을 제거하는 대신 COM 개체 관리의 필요성을 줄이는 것이 전부입니다.개인적으로, 저는 차라리 전력을 다하겠습니다.

코드 쓰기에 대한 이 메서드의 합니다. 큰는저 또 모 것 마 코 한 답 메 공 블 서 개 에 경 되 는 주 향 록 을 합 목 니 다 막 큰 지 에 에 변 서 의 은 드 드 를 많 작 든 서 성 위 한 하 이 기 ▁where ▁i ▁code ▁of ▁note , ▁block ▁a ▁in ▁a ▁to 저 ▁atReleaseComObject호출. 모든 것이 계획대로 작동한다면 그것은 매우 좋지만, 저는 심각한 코드를 쓰는 사람이라면 예외가 던져지거나 메소드에 여러 개의 종료 지점(코드가 실행되지 않아 COM 개체가 해제되지 않음)이 있을 경우 어떤 일이 발생할지 고려해 볼 것을 촉구합니다.이 제가 "와 "랩퍼"를입니다.using말이 많지만 방탄 코드를 만들긴 합니다.

EDIT2: 변경 내용을 저장하거나 저장하지 않고 워크북을 닫을 위치를 나타내기 위해 위의 코드를 업데이트했습니다.변경 사항을 저장하는 코드는 다음과 같습니다.

object saveChanges = Excel.XlSaveAction.xlSaveChanges;

workbook.ComObject.Close(saveChanges, Type.Missing, Type.Missing);

...변경사항을 저장하지 않으려면 변경하기만 하면 됩니다.xlSaveChangesxlDoNotSaveChanges.

현재 진행 중인 통화 내용은 다음과 같습니다.

Sheet.Cells[iRowCount, 1] = data["fullname"].ToString();

기본적으로 다음과 같습니다.

Excel.Range cell = Sheet.Cells[iRowCount, 1];
cell.Value = data["fullname"].ToString();

이런 식으로 하면, 당신은 당신이 다음을 만들고 있다는 것을 알 수 있습니다.Excel.Range개체에 값을 할당합니다.이방은또우우게범변위수리, 즉에 합니다.cell우리가 원한다면 직접 풀어줄 수 있는 변수.따라서 다음 두 가지 방법 중 하나로 개체를 정리할 수 있습니다.

어렵고 추악한 방법:

while (data.Read())
{
    Excel.Range cell = Sheet.Cells[iRowCount, 1];
    cell.Value = data["fullname"].ToString();
    Marshal.FinalReleaseComObject(cell);

    cell = Sheet.Cells[iRowCount, 2];
    cell.Value = data["brand"].ToString();
    Marshal.FinalReleaseComObject(cell);

    cell = Sheet.Cells[iRowCount, 3];
    cell.Value = data["agency"].ToString();
    Marshal.FinalReleaseComObject(cell);

    // etc...
}

위에서 우리는 각 범위 객체를 다음과 같은 통화를 통해 해제합니다.Marshal.FinalReleaseComObject(cell)우리가 계속해서

쉽고 깨끗한 방법:

현재 코드를 그대로 유지하고 마지막에 다음과 같이 정리할 수 있습니다.

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

if (wSheet != null)
{
    Marshal.FinalReleaseComObject(wSheet)
}
if (wBook != null)
{
    wBook.Close(false, m_objOpt, m_objOpt);
    Marshal.FinalReleaseComObject(wBook);
}
xl.Quit();
Marshal.FinalReleaseComObject(xl);

간단히 말해서, 당신의 기존 코드는 매우 가깝습니다.GC에 통화만 추가하면 됩니다.() 및 GC를 수집합니다.WaitForPendingFinalizers()는 당신의 'NAR' 호출 전에 당신에게 효과가 있어야 한다고 생각합니다. (간단히 말해서, 제이미의 코드와 아흐마드의 코드는 모두 맞습니다.)제이미의 코드가 더 깨끗하지만, GC에 통화를 추가하기만 하면 되기 때문에 아마드의 코드가 더 쉬운 "빠른 수정"입니다.() 및 GC를 수집합니다.기존 코드에서 Finalizers()를 대기합니다.

Jamie와 Amhad는 또한 에 대한 링크를 나열했습니다.가 참여하는 NET Automation Forum (여러분 감사합니다!)다음은 StackOverflow에 대한 몇 가지 관련 게시물입니다.

C#에서 Excel interop 객체를 올바르게 정리하는 방법

C# PowerPoint Excel 자동화 -- PowerPoint가 종료되지 않음

이게 도움이 되길 바래, 션...

마이크

xl에 전화하기 전에 다음 사항을 추가합니다.종료():

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

사용할 수도 있습니다.Marshal.FinalReleaseComObject()NAR 메서드에서 ReleaseComObject 대신 사용할 수 있습니다.ReleaseComObject는 참조 카운트를 1씩 줄이는 반면 FinalReleaseComObject는 모든 참조를 릴리스하므로 카운트는 0입니다.

마지막 블록은 다음과 같습니다.

finally
{
    GC.Collect(); 
    GC.WaitForPendingFinalizers(); 

    NAR(wSheet);
    if (wBook != null)
        wBook.Close(false, m_objOpt, m_objOpt);
    NAR(wBook);
    xl.Quit();
    NAR(xl);
}

업데이트된 NAR 방법:

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

저는 얼마 전에 이것을 조사했고, 예를 들어 보통 앱을 닫은 후 GC 관련 통화가 끝에 있다는 것을 발견했습니다.하지만 초반에 불러야 한다고 언급하는 MVP(마이크 로젠블럼)가 있습니다.저는 두 가지 방법을 모두 시도했고 그들은 효과가 있었습니다.Wait For Pending Finalizers를 사용하지 않고 시도해 봤는데 아무 것도 다치지 않을 텐데도 효과가 있었습니다.YMMV.

다음은 제가 언급한 MVP의 관련 링크입니다(VB에 있지만 크게 다르지 않습니다).

다른 사람들이 이미 InterOp를 다루었기 때문에 XLSX 확장자가 있는 Excel 파일을 다루려면 EPLUS를 사용해야 한다고 제안합니다. 이는 Excel의 악몽이 사라질 것입니다.

저는 방금 이 질문에 답했습니다.

메인 창 hWnd에 의한 엑셀 프로세스 죽이기

이 글이 올라온 지 4년이 넘었지만, 저는 같은 문제를 발견하고 해결할 수 있었습니다.Cells 배열에 액세스하는 것만으로도 COM 개체가 생성됩니다.그래서 만약 당신이 한다면,

    wSheet = (Excel._Worksheet)wBook.ActiveSheet;
    Microsoft.Office.Interop.Excel.Range cells = wSheet.Cells;

    int iRowCount = 2;

    // enumerate and drop the values straight into the Excel file
    while (data.Read())
    {
        Microsoft.Office.Interop.Excel.Range cell = cells[iRowCount, 1];
        cell  = data["fullname"].ToString();
        Marshal.FinalReleaseComObject(cell);
    }
    Marshal.FinalReleaseComObject(cells);

그리고 나머지 청소를 하면 문제가 해결될 것입니다.

비슷한 문제를 해결하기 위해 제가 하게 된 것은 프로세스 ID를 얻어 최후의 수단으로 그것을 죽이는 것이었습니다.

[DllImport("user32.dll", SetLastError = true)]
   static extern IntPtr GetWindowThreadProcessId(int hWnd, out IntPtr lpdwProcessId);

...

objApp = new Excel.Application();

IntPtr processID;
GetWindowThreadProcessId(objApp.Hwnd, out processID);
excel = Process.GetProcessById(processID.ToInt32());

...

objApp.Application.Quit();
Marshal.FinalReleaseComObject(objApp);
_excel.Kill();

엑셀 자동화를 정리하기 위해 아직 실패하지 않은 제 블록의 내용입니다.내 애플리케이션은 엑셀을 열어놔서 종료 호출이 없습니다.댓글에 있는 언급은 저의 출처였습니다.

finally
{
    // Cleanup -- See http://www.xtremevbtalk.com/showthread.php?t=160433
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    GC.WaitForPendingFinalizers();
    // Calls are needed to avoid memory leak
    Marshal.FinalReleaseComObject(sheet);
    Marshal.FinalReleaseComObject(book);
    Marshal.FinalReleaseComObject(excel);
}

순수한 것을 사용하는 것을 고려해 보셨습니까?SpreadsheetGear for 와 같은 NET 솔루션.NET? 다음은 SpreadsheetGear를 사용하여 코드가 원하는 것입니다.

// open the template            
using (IWorkbookSet workbookSet = SpreadsheetGear.Factory.GetWorkbookSet())
{
    IWorkbook wBook = workbookSet.Workbooks.Open(excelTemplatePath + _report.ExcelTemplate);
    IWorksheet wSheet = wBook.ActiveWorksheet;
    int iRowCount = 2;
    // enumerate and drop the values straight into the Excel file            
    while (data.Read())
    {
        wSheet.Cells[iRowCount, 1].Value = data["fullname"].ToString();
        wSheet.Cells[iRowCount, 2].Value = data["brand"].ToString();
        wSheet.Cells[iRowCount, 3].Value = data["agency"].ToString();
        wSheet.Cells[iRowCount, 4].Value = data["advertiser"].ToString();
        wSheet.Cells[iRowCount, 5].Value = data["product"].ToString();
        wSheet.Cells[iRowCount, 6].Value = data["comment"].ToString();
        wSheet.Cells[iRowCount, 7].Value = data["brief"].ToString();
        wSheet.Cells[iRowCount, 8].Value = data["responseDate"].ToString();
        wSheet.Cells[iRowCount, 9].Value = data["share"].ToString();
        wSheet.Cells[iRowCount, 10].Value = data["status"].ToString();
        wSheet.Cells[iRowCount, 11].Value = data["startDate"].ToString();
        wSheet.Cells[iRowCount, 12].Value = data["value"].ToString();
        iRowCount++;
    }
    DirectoryInfo saveTo = Directory.CreateDirectory(excelTemplatePath + _report.FolderGuid.ToString() + "\\");
    _report.ReportLocation = saveTo.FullName + _report.ExcelTemplate;
    wBook.SaveAs(_report.ReportLocation, FileFormat.OpenXMLWorkbook);
}

행이 몇 개 이상인 경우 얼마나 빨리 실행되는지에 대해 충격을 받을 수 있습니다.그리고 당신은 엑셀의 교수형 사례에 대해 걱정할 필요가 없을 것입니다.

무료 체험판은 여기에서 다운로드하여 직접 체험해 보실 수 있습니다.

고지 사항:스프레드시트Gear LLC 소유

코드를 붙여넣는 가장 쉬운 방법은 질문을 통해 붙여넣는 것입니다. 이것은 제가 (불행히도) 제 질문에 답했다는 것을 의미하지 않습니다.저를 도우려는 사람들에게 사과드립니다 - 저는 지금까지 이것으로 돌아갈 수 없었습니다.아직도 절 당황하게 만들고 있어요나는 엑셀 코드를 아래와 같이 하나의 기능으로 완전히 분리했습니다.

private bool GenerateDailyProposalsReport(ScheduledReport report)
{
    // start of test

    Excel.Application xl = null;
    Excel._Workbook wBook = null;
    Excel._Worksheet wSheet = null;
    Excel.Range xlrange = null;
    object m_objOpt = System.Reflection.Missing.Value;

    xl = new Excel.Application();
    wBook = (Excel._Workbook)xl.Workbooks.Open(@"E:\Development\Romain\APN\SalesLinkReportManager\ExcelTemplates\DailyProposalReport.xls", false, false, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt);
    wSheet = (Excel._Worksheet)wBook.ActiveSheet;
    xlrange = wSheet.Cells[2, 1] as Excel.Range;

    // PROBLEM LINE ************
    xlrange.Value2 = "fullname";
    //**************************

    wBook.Close(true, @"c:\temp\DailyProposalReport.xls", m_objOpt);
    xl.Quit();

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

    Marshal.FinalReleaseComObject(xlrange);
    Marshal.FinalReleaseComObject(wSheet);
    Marshal.FinalReleaseComObject(wBook);
    Marshal.FinalReleaseComObject(xl);

    xlrange = null;
    wSheet = null;
    wBook = null;
    xl = null;

    // end of test
    return true;

}

위의 문제 라인을 코멘트하면 엑셀 인스턴스가 메모리에서 해제됩니다.현재 상태로는 그렇지 않습니다.시간이 촉박하고 마감일이 다가오고 있기 때문에 (모두 그렇지 않나요?) 이에 대해 더 많은 도움을 주시면 감사하겠습니다.

더 필요한 정보가 있으면 물어보세요.기대해 주셔서 감사합니다.

부록

이것에 대해 더 많은 정보를 제공할 수도 있고 그렇지 않을 수도 있습니다.저는 일정 시간 경과 후(엑셀이 프로세스를 완료할 수 있는 시간을 5-10초) 프로세스를 중지하는 방법에 의존했습니다.두 가지 보고서가 예약되어 있습니다. 첫 번째 보고서가 생성되어 디스크에 저장되고 Excel 프로세스가 종료된 후 이메일로 전송됩니다.두 번째가 생성되어 디스크에 저장되고 프로세스가 중지되지만 전자 메일을 시도할 때 갑자기 오류가 발생합니다.오류:프로세스에서 '....' 등의 파일에 액세스할 수 없습니다.

따라서 Excel 앱이 제거되었을 때도 실제 Excel 파일은 여전히 Windows 서비스에 의해 유지됩니다.파일을 삭제하려면 서비스를 종료해야 합니다.

션, 아이디어가 다 떨어졌네요. :-(

게리는 어떤 생각을 할 수도 있지만, 비록 그의 포장지 접근법이 매우 확고하지만, 당신이 이미 모든 것을 거의 정확하게 하고 있기 때문에 이 경우에는 실제로 도움이 되지 않을 것입니다.

여기에 몇 가지 생각을 나열하겠습니다.당신의 미스터리 라인 때문에 그들 중 누구도 실제로 어떻게 작동할지 모르겠어요.

xlrange.Value2 = "fullname";

이러한 아이디어에 영향을 받지 않는 것처럼 보이지만, 다음과 같습니다.

_워크북 및 _워크시트 인터페이스를 사용하지 마십시오.대신 워크북과 워크시트를 사용합니다. (자세한 내용은 Excel interop: _워크시트 또는 워크시트?를 참조하십시오.)

Excel 개체에 액세스할 때 동일한 줄에 두 개의 점(".")이 있을 때마다 두 줄로 나누어 각 개체를 명명된 변수에 할당합니다.그런 다음 코드의 정리 섹션에서 마샬을 사용하여 각 변수를 명시적으로 해제합니다.FinalReleaseComObject()입니다.

예를 들어, 코드는 다음과 같습니다.

 wBook = (Excel._Workbook)xl.Workbooks.Open(@"E:\Development\Romain\APN\SalesLinkReportManager\ExcelTemplates\DailyProposalReport.xls", false, false, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt, m_objOpt);

다음으로 나눌 수 있습니다.

Excel.Workbooks wBooks = xl.Workbooks;
wBook = wBooks.Open("@"E:\Development\...\DailyProposalReport.xls", etc...);

나중에 정리 섹션에서 다음을 수행할 수 있습니다.

Marshal.FinalReleaseComObject(xlrange);
Marshal.FinalReleaseComObject(wSheet);
Marshal.FinalReleaseComObject(wBook);
Marshal.FinalReleaseComObject(wBooks); // <-- Added
Marshal.FinalReleaseComObject(xl);

당신의 프로세스에 무슨 일이 일어나고 있는지 잘 모르겠습니다.킬 어프로치.wBook에 전화하시면.닫기()를 누른 다음 xl.프로세스를 호출하기 전에()를 종료합니다.킬(), 당신은 문제가 없을 것입니다.워크북.닫기()는 워크북과 Excel을 닫을 때까지 실행을 반환하지 않습니다.종료()는 Excel 종료가 완료될 때까지 실행을 반환하지 않습니다(아직 중단 중일 수 있음).

프로세스를 호출한 후.Kill(), 프로세스를 확인할 수 있습니다.루프에 Exit 속성이 있거나 프로세스를 호출합니다.WaitForExit() 메서드는 종료될 때까지 일시 중지됩니다.나는 이것이 발생하는 데 일반적으로 1초도 걸리지 않을 것이라고 추측합니다.5-10초를 기다려 추측만 하는 것보다 더 적은 시간을 기다리고 확실하게 하는 것이 좋습니다.

위에 나열한 정리 아이디어를 사용해 보십시오. 하지만 추가 기능 또는 안티바이러스 프로그램과 같은 Excel에서 작동할 수 있는 다른 프로세스에 문제가 있을 수 있다는 의심이 들기 시작했습니다.이러한 추가 기능은 올바르게 수행되지 않으면 Excel이 중단될 수 있습니다.이 경우 Excel을 출시하기가 매우 어렵거나 불가능할 수 있습니다.문제가 되는 프로그램을 파악한 다음 사용하지 않도록 설정해야 합니다.또 다른 가능성은 Windows 서비스로 작동하는 것이 문제가 될 수도 있습니다.왜 그런지는 모르겠지만, 윈도우 서비스를 통해 엑셀을 자동화한 경험이 없어서 말할 수 없습니다.문제가 이와 관련된 경우 프로세스를 사용합니다.살인이 유일한 수단이 될 겁니다

이게 바로 내가 생각할 수 있는 전부야, 션.이것이 도움이 되길 바랍니다.어떻게 진행되는지 알려주세요...

마이크

숀.

제 변경사항(아래)과 함께 다시 코드를 게시합니다.코드 변경을 너무 피해서 예외 처리 등을 추가하지 않았습니다.이 코드는 견고하지 않습니다.

private bool GenerateDailyProposalsReport(ScheduledReport report)
{
    Excel.Application xl = null;
    Excel.Workbooks wBooks = null;
    Excel.Workbook wBook = null;
    Excel.Worksheet wSheet = null;
    Excel.Range xlrange = null;
    Excel.Range xlcell = null;

    xl = new Excel.Application();

    wBooks = xl.Workbooks;

    wBook = wBooks.Open(@"DailyProposalReport.xls", false, false, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

    wSheet = wBook.ActiveSheet;

    xlrange = wSheet.Cells;

    xlcell = xlrange[2, 1] as Excel.Range;

    xlcell.Value2 = "fullname";

    Marshal.ReleaseComObject(xlcell);
    Marshal.ReleaseComObject(xlrange);
    Marshal.ReleaseComObject(wSheet);

    wBook.Close(true, @"c:\temp\DailyProposalReport.xls", Type.Missing);

    Marshal.ReleaseComObject(wBook);
    Marshal.ReleaseComObject(wBooks);

    xl.Quit();

    Marshal.ReleaseComObject(xl);

    return true;
}

주의 사항:

  1. WorkbooksApplication클래스가 생성합니다.Workbooks개체에 이므로 해당. "COM"을 했습니다.wBooks 그고그에전화는하응에 .ReleaseComObject.

  2. 가지로찬마,로,CellsWorksheet는 object를 합니다.Range다른 COM 참조가 있는 개체이므로 우리도 정리해야 합니다.따라서 두 개의 분리된 장치가 필요합니다.Rangevariables

  3. 는 COM (COM 사용했습니다.ReleaseComObject더, 더 이상 필요하지 않은 경우, 엄격하게 필요하지 않더라도 좋은 관행이라고 생각합니다.또한 (그리고 이것은 미신일 수도 있습니다) 워크북을 닫기 전에 워크북이 소유한 모든 개체를 공개하고 Excel을 닫기 전에 워크북을 공개했습니다.

  4. 안 할GC.Collect필요하지 않아야 하기 때문에 등등.정말!

  5. FinalReleaseComObject보다는 ReleaseComObject를 사용하고 있습니다. 왜냐하면 완벽하게 충분할 것이기 때문입니다.

  6. 저는 사용 후 변수를 무효화하지 않습니다. 다시 한번 말하지만, 그것은 가치 있는 일을 하지 않습니다.

  7. 여기서는 관련이 없지만, 저는 사용하고 있습니다.Type.MissingSystem.Reflection.Missing.Value 변수를 C#롤!컴파일러가 선택적 매개 변수를 지원하는 C#v4에서 롤!

나는 이 코드를 컴파일하거나 실행할 수 없었지만, 그것이 작동할 것이라고 꽤 확신합니다.행운을 빌어요!

C#의 Excel com 객체를 사용할 필요가 없습니다.OleDb를 사용하여 시트를 수정할 수 있습니다.

http://www.codeproject.com/KB/office/excel_using_oledb.aspx

저도 비슷한 문제를 겪고 있었습니다.제거했습니다._worksheet그리고._workbook그리고 모든 것이 잘 되었습니다.

언급URL : https://stackoverflow.com/questions/1041266/c-sharp-and-excel-automation-ending-the-running-instance

반응형