programing

*모든* Excel interop 개체를 마샬을 사용하여 해제해야 합니까?ReleaseComObject?

instargram 2023. 5. 22. 20:18
반응형

*모든* Excel interop 개체를 마샬을 사용하여 해제해야 합니까?ReleaseComObject?

편집

자세한 내용은 Excel 인터op 개체를 올바르게 정리하는 방법을 참조하십시오.저는 최근에 이 질문을 접했는데, COM 개체를 적절하게 처리하는 방법에 대한 많은 통찰력을 제공했습니다.다른 답변은 단순한 "두 개의 점을 사용하지 않음"과 "사용"을 넘어서기 때문에 첫 번째(표시된) 답변을 반드시 확인합니다.ReleaseComObject모든 컴포트" 조언에 대해 설명합니다.

처음에 이 질문을 다시 검토한 이유는 모든 COM 개체를 등록하고 폐기하는 데 매우 철저했음에도 불구하고 Excel 인스턴스가 여전히 제대로 처리되지 않고 있다는 것을 깨달았기 때문입니다.COM 개체를 생성할 수 있는 방법은 전혀 분명하지 않습니다(즉, 점 두 개를 사용하지 않더라도 COM 개체를 놓칠 수 있음).또한 철저하더라도 프로젝트가 특정 크기 이상으로 커지면 COM 개체를 놓칠 확률이 100%에 육박합니다.그리고 그런 일이 일어났을 때 놓친 것을 찾는 것은 매우 어려울 수 있습니다.위에 링크된 질문에 대한 대답은 Excel 인스턴스가 확실히 닫히는지 확인하기 위한 몇 가지 다른 기술을 제공합니다.한편, 저는 저의 웹사이트에 작은(그러나 중요한) 업데이트를 했습니다.ComObjectManager(아래) 위에 연결된 질문에서 배운 내용을 반영합니다.

원래 질문

저는 몇 가지 예를 보았습니다.Marshal.ReleaseComObject()Excel Interop 개체(즉, 네임스페이스 Microsoft의 개체)와 함께 사용됩니다.사무실. 인터럽트.Excel), 하지만 다양한 정도로 사용하는 것을 보았습니다.

저는 제가 다음과 같은 것을 피할 수 있을지 궁금합니다.

var application = new ApplicationClass();
try
{
    // do work with application, workbooks, worksheets, cells, etc.
}
finally
{
    Marashal.ReleaseComObject(application)
}

또는 다음 방법처럼 생성된 모든 개체를 해제해야 하는 경우:

public void CreateExcelWorkbookWithSingleSheet()
{
    var application = new ApplicationClass();
    var workbook = application.Workbooks.Add(_missing);
    var worksheets = workbook.Worksheets;
    for (var worksheetIndex = 1; worksheetIndex < worksheets.Count; worksheetIndex++)
    {
        var worksheet = (WorksheetClass)worksheets[worksheetIndex];
        worksheet.Delete();
        Marshal.ReleaseComObject(worksheet);
    }
    workbook.SaveAs(
        WorkbookPath, _missing, _missing, _missing, _missing, _missing,
        XlSaveAsAccessMode.xlExclusive, _missing, _missing, _missing, _missing, _missing);
    workbook.Close(true, _missing, _missing);
    application.Quit();
    Marshal.ReleaseComObject(worksheets);
    Marshal.ReleaseComObject(workbook);
    Marshal.ReleaseComObject(application);
}

제가 이 질문을 하게 된 계기는 제가 LINQ에 헌신적인 사람이기 때문에 다음과 같은 일을 정말 하고 싶기 때문입니다.

var worksheetNames = worksheets.Cast<Worksheet>().Select(ws => ws.Name);

...하지만 각 워크시트를 릴리스하지 않으면 메모리 누수나 고스트 프로세스가 발생하지 않을까 걱정됩니다.ws) 개체입니다.

이것에 대한 어떤 식으로든 의견을 주시면 감사하겠습니다.

갱신하다

지금까지의 답변을 토대로 볼 때, 제가 만든 모든 컴포넌트를 공개해야 할 것 같습니다.나는 그 기회를 이용해서,ComObjectManager이 두통을 조금 더 쉽게 다루기 위한 수업.당신은 그것을 사용하는 것을 기억해야 합니다.Get()메서드는 새 com 개체를 인스턴스화할 때마다 사용되지만, 인스턴스화할 경우 다른 모든 작업이 처리됩니다.문제가 있으면 알려주시기 바랍니다(또는 가능하다면 편집해서 댓글을 남겨주세요).코드는 다음과 같습니다.

public class ComObjectManager : IDisposable
{
    private Stack<object> _comObjects = new Stack<object>();

    public TComObject Get<TComObject>(Func<TComObject> getter)
    {
        var comObject = getter();
        _comObjects.Push(comObject);
        return comObject;
    }

    public void Dispose()
    {
        // these two lines of code will dispose of any unreferenced COM objects
        GC.Collect();
        GC.WaitForPendingFinalizers();

        while (_comObjects.Count > 0)
            Marshal.ReleaseComObject(_comObjects.Pop());
    }
}

다음은 사용 예입니다.

public void CreateExcelWorkbookWithSingleSheet()
{
    using (var com = new ComObjectManager())
    {
        var application = com.Get<ApplicationClass>(() => new ApplicationClass());
        var workbook = com.Get<Workbook>(() => application.Workbooks.Add(_missing));
        var worksheets = com.Get<Sheets>(() => workbook.Worksheets);
        for (var worksheetIndex = 1; worksheetIndex < worksheets.Count; worksheetIndex++)
        {
            var worksheet = com.Get<WorksheetClass>(() => (WorksheetClass)worksheets[worksheetIndex]);
            worksheet.Delete();
        }
        workbook.SaveAs(
            WorkbookPath, _missing, _missing, _missing, _missing, _missing,
            XlSaveAsAccessMode.xlExclusive, _missing, _missing, _missing, _missing, _missing);
        workbook.Close(true, _missing, _missing);
        application.Quit();
    }
}

각 COM 개체에 대해 ReleaseComObject를 호출해야 할 것 같습니다.가비지 수집되지 않기 때문에 부모-자녀 계층 구조는 실제로 방정식에 포함되지 않습니다. 부모 개체를 해제하더라도 자식 개체에 대한 참조 수가 감소하지 않습니다.

보안관님께 전화해 보세요기본 응용 프로그램 개체뿐만 아니라 코드에서 사용하는 모든 COM 개체에 대한 ReleaseComObject.

아니요. COM 개체를 하나도 해제할 필요가 없습니다.다음 답변을 참조하십시오. ID가 있는 Excel Interop 개체

답을 요약하자면:프로그램이 중단되는 경우를 제외하고는 쓰레기 수집가가 원할 때 처리할 것입니다.주의해야 할 사항은 다음과 같습니다.

  1. DEBUG 모드에서 앱을 실행하면 COM 개체 정리가 지연되거나 방지될 수 있습니다.
  2. 비주얼 스튜디오 내에서 디버거를 중지하면 COM 개체가 정리되지 않습니다.마치 당신이 앱을 다운시킨 것 같습니다.
  3. 디버깅된 앱을 제대로 닫으면 모든 COM 개체가 해제되는 것을 볼 수 있습니다.또한 앱을 릴리스 모드로 실행하고 올바르게 닫으면 모든 COM 개체도 릴리스됩니다.

이제 메소드 호출이 끝난 직후에 모든 COM 개체를 해제하려면 간단히 호출할 수 있습니다.GC.Collect(); GC.WaitForPendingFinalizers();

그러나 COM 개체를 만든 메소드를 외부에서 호출해야 합니다.다시 말하지만 앱을 디버깅하는 경우에는 예상대로 작동하지 않을 수 있지만 릴리스 모드에서는 작동합니다.

언급URL : https://stackoverflow.com/questions/2926205/does-every-excel-interop-object-need-to-be-released-using-marshal-releasecomob

반응형