DOTNET: C-DLL in .NET einbinden

Wer sich mal so richtig eins mitgeben möchte, sollte mal versuchen, eine C-DLL in einer .NET-Applikation einzubinden. Nein, keine Windows-API-Irgendwas-Sache oder eine Pillepalle-COM-Komponente, sondern so ganz in echt die harte Tour: Eine C-DLL mit ohne vernünftiger Beschreibung, die ein paar Methoden exportiert.

Grundsätzlich ist der Import nicht schwierig: DllImport-Attribut über einer Methode setzen, die ihrerseits als static extern (in C#) bzw. einfach nur Shared (VB) gekennzeichnet ist. Selbstverständlich müssen Signatur und Methodenname stimmen, damit es funktionieren kann. Ach ja, die DLL muss natürlich auch irgendwo im Ausführungspfad sein. Dann geht es aber total einfach.

Bis es mit den EntryPointNotFoundExceptions anfängt. Jut, denkt sich da der geneigte Entwickler, hab ich ich halt Mist gebaut. Schaun wir in die rudimentäre API-Beschreibung und sehen es uns nochmal an: int initCore() steht dort. Fein, schlagen wir einfach mal nach und überprüfen die Datentypen: int aus C wird zu Int32 (also int in C# bzw. Integer in VB). Sonst noch was zu beachten? Nö, passt schon!

Passt nicht. Gibt die nächste EntryPointNotFoundException. Öko, vielleicht ist der Name falsch geschrieben. Vielleicht muss es ja InitCore() heißen. EntryPointNotFoundException. Initcore()? EntryPointNotFoundException. Vielleicht doch void statt int als Rückgabetyp – also void in C# und in VB flugs aus einer Function in eine Sub umgewandelt, das Teil. EntryPointNotFoundException.

Nun wird es Zeit für die ersten Selbstzweifel. Ein wenig rumgesurfe und die Hilfe eines guten Freundes bringen ein .NET-Kommandozeilentool (dumpbin) und einen praktischen DLL-Viewer (Dependency Walker) zum Vorschein. Beide ausprobiert. Beide zeigen an, dass die Methode existiert. Allerdings weicht die Schreibweise des Methodennamens minimal ab – statt initCore steht dort ?initCore@@YAHXZ. Das wird aber an Tools liegen – ist halt C-Mist, der ist nicht so angenehm wie .NET.

Mehrere Stunden später: EntryPointNotFoundException. Kopfschmerzen. Termindruck. Bis die Mail mit der Errettung eintrifft: Der Methodenname muss tatsächlich ?initCore@@YAHXZ heißen. Nur, wie soll man den in .NET angeben, ist doch schließlich kein gültiger Methodenname? Die Lösung heißt EntryPoint-Eigenschaft und die erlaubt es, den tatsächlichen Namen der Funktion in der externen Ressource anzugeben:
_
Public Shared Function InitCore() As Int32
End Function

[DllImport("foo.dll", EntryPoint="?initCore@@YAHXZ")]
public static extern int InitCore();

Und dann funktioniert es. Und ich beginne C-DLLs zu verabscheuen. Oder die .NET-Beispiele zu diesem Thema. Bin mir noch nicht ganz sicher, was schlimmer ist.

2 Comments so far

  1. Stefan Falz on Oktober 5th, 2007

    Hoi :) ,

    ggfs. sollte man noch anmerken, dass man die Funktion(en) auch mit ihrem Ordinalindex ansprechen kann. Also bspw.:

    _
    Public Shared Function InitCore() As Int32
    End Function

    Den Ordinalindex gibt einem übrigens der Dependency Walker (der früher mal bei VS bei war) ebenfalls zurück.

    Gruß, Stefan

  2. Sven on Oktober 5th, 2007

    Ebenfalls anmerken sollte man, dass es sich hier nicht um C-Funktionen, sondern um C++-Funktionen handelt. In C hieße die Funktion wirklich nur InitCore, bei C++ wird der Funktionsname mitsamt seinen Parametern kodiert, was dann zu diesen kryptischen Namen führt.

    Infos dazu: http://en.wikipedia.org/wiki/Name_mangling