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!
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
@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