Assimp.NET für .NET 4.0 C#

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Benutzeravatar
mOfl
Beiträge: 37
Registriert: 23.10.2010, 21:53

Assimp.NET für .NET 4.0 C#

Beitrag von mOfl »

Hallo liebe Menschen,

seit zwei Tagen versuche ich jetzt, Assimp für das .NET Framework 4.0 zum Laufen zu bringen, leider ohne Erfolg :( Hat einer bereits Erfahrung mit den C#-Bindings von Assimp? Da der Rest der Anwendung auf .NET 4.0 angewiesen ist, kann ich Assimp.NET so, wie es im offiziellen Download enthalten ist, nicht verwenden, da nur ein VS2008-Projekt enthalten ist, mit dem ich nur .NET Framework 3.5 als Zielframework auswählen kann. Die Ergebnisdateien des Projekts, Assimp.dll und Assimp.Interop.dll, kann ich in meiner Anwendung nicht korrekt einbinden - Assimp.dll wird offensichtlich nicht gefunden. Beim ersten Assimp-Aufruf, bei mir

Code: Alles auswählen

Importer importer = new Importer();
bekomme ich eine TypeInitializationException von AssimpPINVOKE bei AssimpPINVOKE.new_Importer__SWIG_0(). Dabei habe ich im VS2010-Projekt beide DLLs als Verweise eingebunden. Die gleiche Meldung erscheint, wenn ich nur Assimp.Interop.dll einbinde und Assimp.dll gar nicht existiert, d.h. letztere Bibliothek scheint einfach nicht gefunden zu werden - ich vermute, wegen den unterschiedlichen Zielframeworks für Hauptanwendung und Bibliotheken. Prinzipiell müsste alles nur für Zielplattform x86 laufen. Ich habe auch versucht, alle Buildeigenschaften anzupassen, ohne Erfolg.

Dann also Assimp.NET für 4.0 kompilieren. Dazu habe ich zuerst die Solution in eine VS2010-Solution konvertiert. Wenn man nichts weiter ändert und einfach so kompiliert, gibt es Fehler, weil das erste Projekt - assimp - nicht kompiliert (viele gleichartige Fehler):

Code: Alles auswählen

1>c:\program files (x86)\microsoft visual studio 10.0\vc\include\stdint.h(19): error C2371: 'int32_t': Neudefinition; unterschiedliche Basistypen
1>          c:\users\dani\desktop\assimp--2.0.863-sdk\code\pstdint.h(410): Siehe Deklaration von 'int32_t'
Wenn ich zwei Solutions daraus mache, eine für "assimp" und "Assimp_NET" in VS2008 und dann den .NET-Teil, also "Assimp.NET_CS" und "Assimp.NET_DEMO" in VS2010 und für das Zielframework 4.0, kriege ich beim Start der Demo (oder meiner Anwendung) eine FileLoadException:

Code: Alles auswählen

Die Assembly im gemischten Modus wurde während Version v1.1.4322 der Laufzeit erstellt und kann nicht während der 4.0-Laufzeit ohne zusätzliche Konfigurationsinformationen geladen werden.
Ich habe glaube ich schon jede mögliche Kombination aus allen Konfigurationen ausprobiert und laufe ständig in diese TypeInitializationException. Hat jemand schonmal Assimp für ein .NET 4.0-Projekt erfolgreich verwendet? Bin für jede Hilfe dankbar, insbesondere für ein Beispielprojekt :)

Gruß

mOfl
Benutzeravatar
mOfl
Beiträge: 37
Registriert: 23.10.2010, 21:53

Re: Assimp.NET für .NET 4.0 C#

Beitrag von mOfl »

Hallo,

nach vielen Stunden des Rumprobierens habe ich es tatsächlich geschafft, Assimp für mein .NET-4.0-Projekt zum Laufen zu bringen. Die Lösung ist etwas exotisch und vielleicht sind auch nicht alle der getanen Schritte notwendig, aber da es jetzt einmal bei mir läuft, möchte ich nichts mehr ändern. Für jeden, der irgendwann mal über die Suche den Thread findet und das selbst mal probieren will:

- Vom SVN-Repository Revision 1059 runterladen (ist der letzte Commit, der bei mit Out-of-the-box kompilierbar ist).
- Im Assimp-Verzeichnis nach port/Assimp.NET navigieren und Assimp.NET.sln mit Visual Studio 2008 (!) öffnen. Wenn man die Projektmappe mit VS2010 öffnet, wird sie automatisch konvertiert und die im ersten Post genannten Fehler treten auf.
- Die beiden C++-Projekte "assimp" und "Assimp_NET" in der Konfiguration "Release" für die Plattform "Win32" kompilieren, die resultierende Assimp.dll irgendwo zwischenspeichern für später.
- Alle *.cs-Dateien (und nur die) aus dem Verzeichnis port/Assimp.NET/Assimp.NET_CS in das Projekt kopieren, in dem man Assimp verwenden möchte. Ich habe dazu einen Unterordner AssimpNET in meiner Projektmappe angelegt. Das ist vermutlich ein Schritt, den man auch weglassen und weiter mit der Assimp.Interop.dll arbeiten könnte. Bei mir hat sich das ohne das zusätzliche Klassenbibliothek-Projekt entwickelt, weil ich viel im Code debuggt habe und das so angenehmer war.
- Die kopierten Dateien in VS2010 über "Hinzufügen | Vorhandenes Element..." zum Projekt hinzufügen.
- In dem Projekt, zu dem man die Dateien hinzugefügt hat, die oben erzeugte Assimp.dll hinzufügen. Damit die Datei nicht verloren geht, habe ich sie bei mir in das gleiche Verzeichnis kopiert wie die *.cs-Dateien.
- Eine der kopierten Dateien heißt "AssimpPINVOKE.cs". In der Datei finden sich viele Aufrufe nach dem Muster

Code: Alles auswählen

[DllImport("Assimp", EntryPoint = "SWIGRegisterExceptionCallbacks_Assimp")]
public static extern void SWIGRegisterExceptionCallbacks_Assimp(...)
Skurrilerweise wurde die Bibliothek Assimp.dll so nicht bei mir gefunden. Deshalb habe ich eine konstante mit dem Dateinamen angelegt und alle Verweise auf "Assimp" durch die Konstante ersetzt, also:

Code: Alles auswählen

public const string LibraryPath = "Assimp.dll";

[DllImport(AssimpPINVOKE.LibraryPath, EntryPoint = "SWIGRegisterExceptionCallbacks_Assimp")]
public static extern void SWIGRegisterExceptionCallbacks_Assimp(...)
So funktioniert es bei mir. Warum der letzte Schritt nötig ist, ist mir ein Rätsel.

Um noch auf die TypeInitializationException zu sprechen zu kommen, die mir wirklich sehr oft begegnet ist: Die Exception tritt immer auf, wenn ein statischer Member oder ein statischer Konstruktor eine Exception wirft - in diesemFall in der Klasse AssimpPINVOKE. Wer Probleme mit dem Einbinden hat, sollte sich die Zeile

Code: Alles auswählen

static SWIGExceptionHelper swigExceptionHelper = new SWIGExceptionHelper();
in Datei AssimpPINVOKE.cs ansehen. Direkt darüber steht in der Inline-Definition der Klasse auch der Konstruktor für SWIGExceptionHelper, der scheitern wird, wenn es ein Problem mit der Bibliothek gibt. Deshalb habe ich den Konstruktor mit einem Try-Catch-Block und einem Breakpoint versehen, um zu sehen, was genau schief läuft (sonst geht die eigentliche Exception verloren):

Code: Alles auswählen

static SWIGExceptionHelper() {
	try {
		SWIGRegisterExceptionCallbacks_Assimp(
			applicationDelegate,
			arithmeticDelegate,
			divideByZeroDelegate,
			indexOutOfRangeDelegate,
			invalidCastDelegate,
			invalidOperationDelegate,
			ioDelegate,
			nullReferenceDelegate,
			outOfMemoryDelegate,
			overflowDelegate,
			systemDelegate);

		SWIGRegisterExceptionCallbacksArgument_Assimp(
			argumentDelegate,
			argumentNullDelegate,
			argumentOutOfRangeDelegate);
	}
	catch (Exception e) {
		throw new ApplicationException(e.Message); // hier einen Breakpoint setzen
	}
}
Die Meldung der Exception gibt dann Auskunft darüber, warum der Aufruf in die Bibliothek gescheitert ist.

Ich hoffe, damit dem einen oder anderen ein, zwei schlaflose Nächte weniger zu bereiten :)

Gruß

mOfl
Antworten