AccessViolationException nasıl yönetilir


185

.Net uygulamamdan bir COM nesnesi (MODI) kullanıyorum. Aradığım yöntem Visual Studio tarafından kesilen bir System.AccessViolationException atar. Garip olan şey, AccessViolationException, COMException ve diğer her şey için işleyicileri olan bir denemede aramamı tamamladım, ancak Visual Studio (2010) AccessViolationException'ı engellediğinde, hata ayıklayıcı yöntem çağrısında (doc.OCR) kesiyor, ve eğer adım atarsam, catch bloğuna girmek yerine bir sonraki satıra devam eder. Ayrıca, bunu görsel stüdyo dışında çalıştırırsam, uygulama çöküyor. COM nesnesi içine atılan bu özel durumu nasıl işleyebilirim?

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();

}

ExceptionTüm istisnaları yakalamak ve istisnanın gerçekte ne olduğunu görmek için (geçici olarak!) Bir işleyici koymayı denediniz mi?
ChrisF

3
@ChrisF - evet, son yakalama işleyicisini görüyor musunuz? Bu, İstisna ve İstisna alt sınıfları dahil her şeyi yakalamalıdır. Visual Studio da istisnanın System.AccessViolationException olduğunu bildiriyor
Jeremy

Yanıtlar:


299

.NET 4.0'da, çalışma zamanı, Windows Yapısal Hata İşleme (SEH) hataları olarak ortaya çıkan bazı özel durumları Bozuk Durumun göstergeleri olarak işler. Bu Bozuk Durum İstisnalarının (ÖAM) standart yönetilen kodunuz tarafından yakalanmasına izin verilmez. Neden ya da nasıl buraya girmeyeceğim. ÖAM'ler hakkında bu makaleyi .NET 4.0 Framework'te okuyun:

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

Ama umut var. Bu sorunu aşmanın birkaç yolu vardır:

  1. .NET 3.5 derlemesi olarak yeniden derleyin ve .NET 4.0'da çalıştırın.

  2. Uygulamanızın yapılandırma dosyasına yapılandırma / çalışma zamanı öğesinin altına bir satır ekleyin: <legacyCorruptedStateExceptionsPolicy enabled="true|false"/>

  3. Bu özel durumları yakalamak istediğiniz yöntemleri HandleProcessCorruptedStateExceptionsöznitelikle süsleyin . Ayrıntılar için http://msdn.microsoft.com/tr-tr/magazine/dd419661.aspx#id0070035 adresine bakın.


DÜZENLE

Daha önce bir forum gönderisine başvurdum ek ayrıntılar için . Ancak Microsoft Connect kullanımdan kaldırıldığı için, ilgilenmeniz durumunda ek ayrıntılar aşağıda verilmiştir:

Microsoft CLR Ekibi'nden bir geliştirici olan Gaurav Khanna'dan

Bu davranış, CLR 4.0'ın Bozuk Durum İstisnaları adı verilen bir özelliğinden dolayı tasarım gereğidir. Basitçe söylemek gerekirse, yönetilen kod, bozuk işlem durumunu gösteren istisnaları yakalamaya çalışmamalıdır ve AV bunlardan biridir.

Daha sonra HandleProcessCorruptedStateExceptionsAttribute ve yukarıdaki makaledeki belgelere başvurmaya devam eder . Bu tür istisnaları yakalamayı düşünüyorsanız kesinlikle okumaya değer.


12
HandleProcessCorruptedStateExceptions.Net 4.5'te benim için çalışıyor.
deerchao

2
Teşekkürler villecoder, sen bir mücevhersin! Bu sorunla haftalardır uğraşıyorum, kök problemini çözmeye çalıştım ve sonunda semptomu tedavi etmek için kendimi istifa ettim. Çözümünüz mükemmel.
gadildafissh

19
! Dikkat edilmesi gereken: Bozuk Durum İstisnası (ÖAM) olan AccessViolationException sonrasında işlemi sonlandırmanız önemle tavsiye edilir. Aksi takdirde daha kritik hatalara yol açabilir.
Chris W

6
Teşekkürler, bu gerçekten yararlıdır, ancak ilk başta bu istisnaları yakalamak için 3 adımın hepsini yapmam gerektiği izlenimini edindim, aslında bunu ORyapmanın yollarının "mantıklı " olması. :)
Lou

@deerchao Umarım cevapta verilen ilk bağlantıyı okudunuz. ÖAM istisnalarını ele almak kötü bir fikirdir.
piksel

17

Yapılandırma dosyasına aşağıdakileri ekleyin ve try catch bloğunda yakalanacaktır. Dikkatli olun ... bu durumdan kaçınmaya çalışın, çünkü bu bir tür ihlalin gerçekleştiği anlamına gelir.

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

2
C ++ / cli dll olarak kullananlar için, kod üst .exe projesine eklenmelidir.
Felix

9

Yukarıdaki cevaplardan derlendi, benim için çalıştı, yakalamak için aşağıdaki adımları gerçekleştirdi.

Adım # 1 - Aşağıdaki snippet'i yapılandırma dosyasına ekleyin

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

Adım 2

Ekle -

[HandleProcessCorruptedStateExceptions]

[SecurityCritical]

bağladığınız işlevin üstünde istisnayı yakalayın

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


Msdn.microsoft.com/en-us/library/… 'a göre , SecurityCriticalAttribute tam güven için bir bağlantı talebine eşdeğerdir. Açıklanan sorunun tam güven talep edilmesini gerektirdiğini düşünmüyorum.
Jeremy

0

Microsoft: "Bozuk işlem durumu özel durumları, bir işlemin durumunun bozulduğunu gösteren özel durumlardır. Uygulamanızı bu durumda yürütmenizi önermiyoruz ..... Bunları işlemeyi sürdürmek istediğinizden kesinlikle eminseniz istisnalar varsa, HandleProcessCorruptedStateExceptionsAttribute"

Microsoft: "Bir işlemi azaltabilecek görevleri izole etmek için uygulama etki alanlarını kullanın."

Program aşağıda kullanımıyla ilişkili riskleri olmadan kurtarılamayan hatalarından ana uygulama / iplik koruyacak HandleProcessCorruptedStateExceptionsve<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
    }
}

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.