2013-11-01 7 views
5

Ist es möglich, eine verwaltete Ausnahme und den verwalteten Code gefangen geworfen haben aber wo es dazwischen nativen Rahmen auf den Call-Stack?Fangen eine verwaltete Ausnahme über nativen Rahmen

Ich habe Probleme damit. Die App ist 32-Bit-nativen Code und hostet die MSCLR 2.0 (aber der meiste Code ist .NET 3.5.)

Die Anwendung läuft gut, es sei denn, dieser Wurf ist fertig, und was genau passiert, wenn es wirft, hängt von der System, auf dem es läuft.

Die eigentliche Anwendung ist ziemlich komplex, so dass ich zunächst nur ein paar einfache konzeptionelle Code nur zur Veranschaulichung post. Das native Programm (wir rufen Native.exe) führt ein einzelnes verwaltetes Programm, das wir Managed.exe aufrufen. Irgendwo innerhalb Managed.exe, in C# geschrieben, ist die folgende:

class MyException : Exception {} 

... 

void OuterManaged() 
{ 
    MyObject.MyEvent += (s, a) => 
    { 
     Console.WriteLine("Throwing..."); 
     throw new MyException(); 
    } 

    try 
    { 
     MyKernel.DoSomething(); 
     Console.WriteLine("Finished"); 
    } catch(MyException) 
    { 
     Console.WriteLine("Caught"); 
    } 
} 

MyKernel ist eine verwaltete Klasse in einem gemischten C definiert ++/CLI Baugruppe, die wir Glue.dll nennen wollen. MyObject ist eine Instanz einer anderen Klasse in Glue.dll. Die Methode dort sieht ungefähr so ​​aus:

void DoSomething(void) 
{ 
    _pMyNativeKernel->DoSomething(); 
} 

DoSomething ist eine C++ Funktion in Native.exe die praktisch genannt wird. Um es kurz zu machen, es endet schließlich mit dem Aufruf einer verwalteten Methode in Glue.dll, die MyEvent auslöst.

Wenn MyEvent angehoben wird und das Programm läuft auf einem 32-Bit-Windows-XP-System, verhält es sich wie beabsichtigt und die Konsole zeigt:

Throwing... 
Caught 

auf einem Windows 7 64-Bit-System I statt erhalten Sie diese:

Grundsätzlich verschwindet die Ausnahme einfach in Luft; das Ganze läuft weiter, als wäre es nie passiert. (. Die Ausnahme entspricht in einem Fenster auf die Schaltfläche Schließen zu schlagen, so wirkt es so, als ob die Schaltfläche nicht geklickt wurde)

auf einem Windows Server 2012-System über Remote-Desktop, bekomme ich diese:

Throwing... 

und dann die gesamte Anwendung stürzt mit einem Dialog sagen „Native.exe hat aufgehört zu arbeiten“, und dies:

Description: 
    Stopped working 

Problem signature: 
    Problem Event Name: CLR20r3 
    Problem Signature 01: Native.exe 
    Problem Signature 02: 0.0.0.0 
    Problem Signature 03: 5267c484 
    Problem Signature 04: 0 
    Problem Signature 05: 1.0.0.0 
    Problem Signature 06: 5272e299 
    Problem Signature 07: 208 
    Problem Signature 08: f 
    Problem Signature 09: MyException 
    OS Version: 6.2.9200.2.0.0.144.8 
    Locale ID: 1033 

Dies ist, was würde ich nicht gehabt haben, erwartet hatte ich die try/catch.

Wenn ich es in dieser Umgebung unter dem Debugger VS2008SP ausführen, fängt der Debugger die Ausnahme der ersten Chance, und wenn ich es fortsetze, fängt es dann als unbehandelte Ausnahme.

soll ich beachten Sie, dass die native DoSomething schließlich die Win32 GetMessage Aufruf endet und dann DispatchMessage, und der native-to-Managed Rückruf in Code tritt aus einem Fenster Prozedur aufgerufen. Dieses Fenster wird mit Direct3D gezeichnet.Das verwaltete Programm verwendet den "Kernel" Native.exe für alle Fenster- und Zeichenoperationen und greift nie allein auf Windows zu.

Keine der dazwischenliegenden Funktionen in Native.exe fangen irgendwelche Ausnahmen überhaupt. Ich kann nicht sagen, ob es Ausnahmehandler in den Win32-API-Funktionen gibt; Ich würde das nicht denken, aber wenn das möglich ist, könnte das möglicherweise erklären, wie das Verhalten zwischen den Systemen inkonsistent war.

Dies ist in etwa die tatsächliche Call-Stack auf Server 2012, mit repetitious Artikel ausgeschnitten:

Managed!MyGame.ReInitDisplay.AnonymousMethod(object s = {Engine.Display}, System.EventArgs a = {System.EventArgs}) C# // throw site 
Glue.dll!CDisplayBridge::OnClosePressed() C++ 
[Native to Managed Transition] 
Native.EXE!EngineKern::CGfxDisplay_a::HandleClosePress() C++ 
Native.EXE!EngineKern::CGfxDisplay::WindowProc(HWND__ * hwnd=0x000610ac, unsigned int uMsg=16, unsigned int wParam=0, long lParam=0) C++ 
user32.dll!74a477d8() 
[Frames below may be incorrect and/or missing, no symbols loaded for user32.dll]  
user32.dll!74a47c44() 
ntdll.dll!773e2f02()  
user32.dll!74a48fed() 
uxtheme.dll!7422254d() 
user32.dll!74a475e7() // DefWindowProc 
Native.EXE!EngineKern::CGfxDisplay::WindowProc(HWND__ * hwnd=0x000610ac, unsigned int uMsg=274, unsigned int wParam=61536, long lParam=4261024) C++ 
user32.dll!74a48a66() // DispatchMessage 
Native.EXE!EngineKern::CKernel::DoEvent() C++ 
[Managed to Native Transition] 
Glue.dll!Engine::Kernel::DoEvent() C++ // DoSomething in the example 
MyClassLib!MyClassLib.Game.MainLoop() C# 
MyClassLib!MyClassLib.Game.Play() C# 
Managed!MyGame.Play() C# 
Managed!Program.Main(string[] args = {string[0]}) C# 
mscorlib.dll!System.AppDomain.ExecuteAssemblyByName(string assemblyName, System.Security.Policy.Evidence assemblySecurity, string[] args) 
mscorlib.dll!System.AppDomain.ExecuteAssemblyByName(string assemblyName) 
Glue.dll!__Engine__::AppDomainManager::Main(int pEngineKern = 15760932) C++ 
[Native to Managed Transition] 
Native.EXE!EngineGlue::IManagedEntryPoint::Main(long pEngineKern=15760932) C++ // calls in by COM interop 
Native.EXE!CClrHost::Run() C++ 
Native.EXE!wWinMain(HINSTANCE__ * hInstance=0x00e40000, HINSTANCE__ * hPrevInstance=0x00000000, wchar_t * lpCmdLine=0x01462a80, int nCmdShow=5) C++ 
Native.EXE!__tmainCRTStartup() C 
Native.EXE!wWinMainCRTStartup() C 
kernel32.dll!74ca8543()  
ntdll.dll!773fac3c()  

Dieses ganze System ist für eine lange Zeit fein gearbeitet, aber ich habe nie Ausnahmen zu werfen brauchte über das verwaltete/native Übergänge vorher. Ich möchte, dass der verwaltete Anwendungscode in der Lage ist, Ausnahmen frei zu werfen und abzufangen, ohne sich Gedanken darüber machen zu müssen, ob der native Host einen nativen zu verwalteten Rückruf durchführt.

Alle Informationen, die ich on-line über das Auslösen von Ausnahmen über solche Übergänge finden, ist immer über das Abfangen einer systemeigenen Ausnahme oder umgekehrt. Dies wird verwaltet verwaltend verwaltet, aber die dazwischenliegenden nativen Frames sind komplizierter.

So in Bezug wie dies in der Regel meine Fragen zu werfen sind:

  • diese Arbeit sollte? Es funktioniert funktioniert auf Windows XP, aber ich weiß nicht, ob das wohldefinierte Verhalten war oder wenn ich nur Glück hatte.

  • Wenn es sollte arbeiten, was sind mögliche Gründe, warum es nicht auf allen Systemen funktioniert?

Wenn es nicht funktionieren soll, dann denke ich, müsste ich alle verwalteten Rückrufe erweitern auf verwaltete Ausnahmen abfangen, wickeln Sie sie mit einer nativen Ausnahme, und dass für die verwalteten Wrapper fangen die native Funktion und wirft die ursprüngliche verwaltete Ausnahme. Das klingt nach viel Haarziehen!

+1

Wenn die Ausnahme in einem nativen Thread ausgelöst wird, hängt das beschriebene Problem möglicherweise mit http://stackoverflow.com/questions/6124631/clr-hosting-exception-handling-in-a-non-clr-created- zusammen. Thread? Rq = 1. Sehen Sie, ob es hilfreich ist, sicherzustellen, dass Sie den Rückruf für einen verwalteten Thread immer ausführen. – archgl

+0

@archgl Danke für den Tipp. In meinem Fall sollte es keine _unhandled_Ausnahme sein, aber es gibt einen Hinweis in der anderen Frage. Vielleicht ist es eine SEH-Ausnahme wegen der nativen Frames und so fängt der äußere verwaltete Frame es nicht, weil es ist nur versuchen, die ursprüngliche verwaltete Ausnahme zu erfassen, nicht die SEH. Ich hatte gehofft, es wäre schlauer als das (der M-> N Thunk _should_ fangen die SEH und konvertieren zurück zu verwaltet), aber vielleicht nicht. Wenn Sie einen separaten Thread aufrufen, kann der äußere verwaltete Code die Ausnahme nicht _catch_ so lassen, wie ich es möchte. – Kevin

Antwort

0

Ich habe mit dem gleichen Problem zu tun. Ich habe ein Formular, der Code, der es aufruft (oder vielmehr der Code, der .ShowDialog() aufruft) befindet sich in einem try {} -Block mit einem entsprechenden catch {} -Block. Ab einem bestimmten Punkt verursacht ein Klick auf den Dialog eine Ausnahme, ABER der Fang wird nicht getroffen!

Also habe ich den Code bearbeitet und dann einfach die anstößige Anweisung (eine Umwandlung im OnClick-Handler) mit ihrer eigenen try/catch umgeben.

Nun, der "Fang" ist getroffen, aber innen gibt es einen einfachen "Wurf"; führt zur Ausnahme "User-Unhandled"!

Wenn ich auf den Stapel schaue, gibt es mehrere verwaltete/native/verwaltete Übergänge.

Es scheint, dass der verwaltete Stapel keinen Handler hat und dass das System den Stack nicht durch die nativen Frames zum nächsten verwalteten Frame führt, so dass es dort keinen Handler gibt.