2013-12-16 11 views
5

Ich verwende eine nicht verwaltete DLL mit einer Funktion, die std::exception löst.Catch unmanaged dll Ausnahme in .NET

Ich benutze einen .NET DLL-Wrapper, so dass es zur Verwendung in .NET-Programmen verteilt werden kann.

Ich möchte in der Lage Fang sein, die Nachricht von der nativen Ausnahme, sondern alles, was ich habe, ist immer System.Runtime.InteropServices.SEHException("External component has thrown an exception.")

Gibt es eine Möglichkeit die Ausnahme Details zu propagieren? Vielleicht sollte ich eine benutzerdefinierte Ausnahme von der nativen DLL exportieren? Wie würde ich das tun?

Dank

nativen DLL:

__declspec(dllexport) void __stdcall W32DLLFunc(int param) { 
    if (param < 0) { 
    throw new exception("Error: param must be > 0"); 
    } 
    ... 
} 

.net DLL:

[DllImport("nw32.dll", CharSet = CharSet::Auto)] 
static void W32DLLFunc(int param); 

vb.net Programm:

Try 
    W32DLLFunc(-1) 
Catch ex As Exception 
    MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error) 
End Try 

Antwort

2

native C++ Ausnahmen sind native Ausnahmen ++ C. Sie arbeiten nicht mit Dingen, die nicht C++ sind. Sie funktionieren sogar nicht zwischen verschiedenen Versionen von C++.

Native C++ - Ausnahmen sind nicht gut für die Interoperabilität.

Der Standardmechanismus zum Zurückgeben von Fehlerinformationen aus DLLs besteht darin, einen Wert zurückzugeben, der Erfolg oder Fehler angibt, und SetLastError und GetLastError zu verwenden, um einen Fehlercode zu melden, wenn die Funktion fehlgeschlagen ist.

Wenn Sie einen Standardmechanismus wünschen, der mehr Informationen als einen Fehlercode zurückgibt, müssen Sie sich COM ansehen, der hat.

Aber es wäre einfacher, nur einige Fehlercodes zu definieren.

Wenn möglich, würde ich die ursprüngliche DLL ändern, so dass es Ausnahmen überhaupt nicht verliert. Wenn dies nicht möglich ist, weil bestehende C++ - Clients vom aktuellen Entwurf abhängen, würde ich eine parallele API hinzufügen: eine neue Version jeder exportierten Funktion, die das Original aufruft, Ausnahmen abfängt und Fehlercodes zurückgibt. Dies ist alles Textbaustein, der in Makros versteckt werden kann. Wenn Sie die DLL nicht berühren können, würde ich einen nativen Wrapper hinzufügen, um die Ausnahmen zu übersetzen.

aktualisieren

Wie IInspectable vorgeschlagen, ist eine weitere Möglichkeit, eine Mixed-Mode-Assembly zu erstellen.

Fügen Sie Ihrer vorhandenen C++ - Bibliothek eine .NET-Klasse hinzu. Dies sollte einen Wrapper für jede API-Funktion bereitstellen, die die ursprüngliche API aufruft, jede Ausnahme abfängt, die Details in eine .Net-Ausnahme kopiert und die .Net-Ausnahme auslöst.

Indem alle native Ausnahmebehandlung in der DLL beibehalten wird, vermeidet dies die Probleme mit C++ - Ausnahmen, die DLL-Grenzen überschreiten. Die umbrochenen Ausnahmen können in jeder .Net-Sprache verwendet werden, ohne dass Deklarationen für die exportierten Funktionen erstellt werden müssen. Der einzige Nachteil besteht darin, dass Sie eine zusätzliche API für die Interoperabilität mit anderem systemeigenen Code benötigen.

+0

Das stimmt, die berühmte 'E msc'-Ausnahme. Ich werde meine Kommentare im Austausch für eine Upvote löschen.Sie könnten immer noch eine Notiz hinzufügen über das Schreiben eines C++/CLI-Wrappers, um C++ - Ausnahmen in .NET-Ausnahmen zu übersetzen, was die sauberste Lösung zu sein scheint. Die Assembly im gemischten Modus kann sogar von nativem und verwaltetem Code verwendet werden. – IInspectable

+0

Prost. Ein C++/CLI-Wrapper ist mir aufgefallen, aber ich wusste nicht, wie native Exceptions mit C++/CLR interagieren. [Dieser Artikel] (http://msdn.microsoft.com/en-us/library/df24ysb6.aspx) bedeutet fast, dass es funktionieren würde, also gab ich es und es tut. Ich habe meine Antwort aktualisiert. – arx