[C#] AccessViolationException을 처리하는 방법

내 .net 응용 프로그램에서 COM 개체 (MODI)를 사용하고 있습니다. 내가 호출하는 메서드는 Visual Studio에서 가로채는 System.AccessViolationException을 발생시킵니다. 이상한 점은 AccessViolationException, COMException 및 기타 모든 것에 대한 핸들러가있는 try catch로 호출을 래핑했지만 Visual Studio (2010)가 AccessViolationException을 인터셉트하면 디버거가 메소드 호출 (doc.OCR)에서 중단됩니다. 단계별로 진행하면 catch 블록에 들어 가지 않고 다음 줄로 계속 진행합니다. 또한 Visual Studio 외부에서 이것을 실행하면 응용 프로그램이 중단됩니다. COM 개체 내에서 발생하는이 예외를 어떻게 처리 할 수 ​​있습니까?

MODI.Document doc = new MODI.Document();
try
{
    doc.Create(sFileName);
    try
    {
        doc.OCR(MODI.MiLANGUAGES.miLANG_ENGLISH, false, false);
        sText = doc.Images[0].Layout.Text;
    }
    catch (System.AccessViolationException ex)
    {
        //MODI seems to get access violations for some reason, but is still able to return the OCR text.
        sText = doc.Images[0].Layout.Text;
    }
    catch (System.Runtime.InteropServices.COMException ex)
    {
        //if no text exists, the engine throws an exception.
        sText = "";
    }
    catch
    {
        sText = "";
    }

    if (sText != null)
    {
        sText = sText.Trim();
    }
}
finally
{
    doc.Close(false);

    //Cleanup routine, this is how we are able to delete files used by MODI.
    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(doc);
    doc = null;
    GC.WaitForPendingFinalizers();
    GC.Collect();
    GC.WaitForPendingFinalizers();

}



답변

.NET 4.0에서 런타임은 Windows SEH (Structured Error Handling) 오류로 발생한 특정 예외를 손상된 상태 표시기로 처리합니다. 이러한 손상된 상태 예외 (CSE)는 표준 관리 코드에서 잡을 수 없습니다. 나는 왜 또는 어떻게 여기에 들어 가지 않을 것입니다. .NET 4.0 프레임 워크에서 CSE에 대한이 기사를 읽으십시오.

http://msdn.microsoft.com/en-us/magazine/dd419661.aspx#id0070035

그러나 희망이 있습니다. 이 문제를 해결하는 몇 가지 방법이 있습니다.

  1. .NET 3.5 어셈블리로 다시 컴파일하고 .NET 4.0에서 실행하십시오.

  2. configuration / runtime 요소 아래에서 응용 프로그램의 구성 파일 행을 추가하십시오.
    <legacyCorruptedStateExceptionsPolicy enabled="true|false"/>

  3. 이러한 예외를 포착하려는 메소드를 HandleProcessCorruptedStateExceptions속성으로 장식하십시오 . 자세한 내용은 http://msdn.microsoft.com/en-us/magazine/dd419661.aspx#id0070035 를 참조하십시오.


편집하다

이전에는 자세한 내용 은 포럼 게시물 을 참조했습니다 . 그러나 Microsoft Connect가 폐기되었으므로 다음과 같은 경우 추가 세부 정보가 있습니다.

Microsoft CLR 팀의 개발자 Gaurav Khanna

이 동작은 의도적으로 손상된 상태 예외라는 CLR 4.0의 기능으로 인해 발생합니다. 간단히 말해서 관리 코드는 손상된 프로세스 상태를 나타내는 예외를 포착하려고 시도해서는 안되며 AV는 그 중 하나입니다.

그런 다음 HandleProcessCorruptedStateExceptionsAttribute 및 위 기사 에 대한 문서를 계속 참조합니다 . 말할 것도없이, 이러한 유형의 예외를 잡는 것을 고려하고 있다면 확실히 읽을만한 가치가 있습니다.


답변

구성 파일에 다음을 추가하면 try catch 블록에 잡 힙니다. 주의 사항 … 위반이 발생했음을 의미하므로이 상황을 피하십시오.

<configuration>
   <runtime>
      <legacyCorruptedStateExceptionsPolicy enabled="true" />
   </runtime>
</configuration>


답변

위의 답변에서 편집하고 나를 위해 일했으며 그것을 잡기 위해 다음 단계를 수행했습니다.

1 단계-다음 스 니펫을 구성 파일에 추가

<configuration>
   <runtime>
      <legacyCorruptedStateExceptionsPolicy enabled="true" />
   </runtime>
</configuration>

2 단계

추가-

[HandleProcessCorruptedStateExceptions]

[SecurityCritical]

기능의 상단에 당신은 예외를 잡아

출처 : http://www.gisremotesensing.com/2017/03/catch-exception-attempted-to-read-or.html


답변

마이크로 소프트 : “손상된 프로세스 상태의 예외는 프로세스의 상태가 손상되었음을 나타내는 예외입니다. 우리는하지 않는 것이 좋습니다 당신이 있다면 …..이 상태에서 응용 프로그램을 실행 확신 당신이 당신의 취급을 유지하려는 예외는 HandleProcessCorruptedStateExceptionsAttribute속성을 적용해야 합니다 “

Microsoft : “응용 프로그램 도메인을 사용하여 프로세스를 중단시킬 수있는 작업을 분리하십시오.”

아래 프로그램은 사용 HandleProcessCorruptedStateExceptions및 관련 위험없이 주 응용 프로그램 / 스레드를 복구 할 수없는 오류로부터 보호합니다.<legacyCorruptedStateExceptionsPolicy>

public class BoundaryLessExecHelper : MarshalByRefObject
{
    public void DoSomething(MethodParams parms, Action action)
    {
        if (action != null)
            action();
        parms.BeenThere = true; // example of return value
    }
}

public struct MethodParams
{
    public bool BeenThere { get; set; }
}

class Program
{
    static void InvokeCse()
    {
        IntPtr ptr = new IntPtr(123);
        System.Runtime.InteropServices.Marshal.StructureToPtr(123, ptr, true);
    }

    private static void ExecInThisDomain()
    {
        try
        {
            var o = new BoundaryLessExecHelper();
            var p = new MethodParams() { BeenThere = false };
            Console.WriteLine("Before call");

            o.DoSomething(p, CausesAccessViolation);
            Console.WriteLine("After call. param been there? : " + p.BeenThere.ToString()); //never stops here
        }
        catch (Exception exc)
        {
            Console.WriteLine($"CSE: {exc.ToString()}");
        }
        Console.ReadLine();
    }


    private static void ExecInAnotherDomain()
    {
        AppDomain dom = null;

        try
        {
            dom = AppDomain.CreateDomain("newDomain");
            var p = new MethodParams() { BeenThere = false };
            var o = (BoundaryLessExecHelper)dom.CreateInstanceAndUnwrap(typeof(BoundaryLessExecHelper).Assembly.FullName, typeof(BoundaryLessExecHelper).FullName);
            Console.WriteLine("Before call");

            o.DoSomething(p, CausesAccessViolation);
            Console.WriteLine("After call. param been there? : " + p.BeenThere.ToString()); // never gets to here
        }
        catch (Exception exc)
        {
            Console.WriteLine($"CSE: {exc.ToString()}");
        }
        finally
        {
            AppDomain.Unload(dom);
        }

        Console.ReadLine();
    }


    static void Main(string[] args)
    {
        ExecInAnotherDomain(); // this will not break app
        ExecInThisDomain();  // this will
    }
}


답변

AppDomain.UnhandledException을 사용 해보고 그것을 잡을 수 있는지 확인할 수 있습니다.

**편집하다*

다음은 유용 할 수있는 추가 정보 입니다 (오래 읽을 수 있습니다).


답변