Immer wieder taucht die Frage auf, wie Prozeduren und Parameter deklariert sein müssen, um mit einer C-DLL kommunizieren zu können.
Eines sofort: Die Kommunikation mit einer C++-DLL ist so aus .NET nicht möglich, da ein unmanaged C++-Objekt erstellt werden muss, und das ist aus .NET nicht möglich, dazu bedarf es eines Wrappers in Form einer C-DLL.
Deswegen beschränken wir uns hier ausschließlich auf C-DLLs.
Primär ist stets, wie eine Prozedur in der C-DLL deklariert wurde, danach richtet sich die Übertragung in .NET.
Zur Information:
In C wird unterschieden, ob die Parameter einer Prozedur von vorn nach hinten oder von hinten nach vorn auf dem Stack abgelegt werden. Dies wird in der Deklaration der Funktion durch PASCAL bzw. _stdcall unterschieden.
Außerdem muss jede exportierte Prozedur als solche gekennzeichnet werden.
Ich habe folgende Beispiele implementiert:
Die Übergabeparameter werden abgetestet. Bei einem falschen Aufruf (zu große Anzahl von Werten im Array) kommt eine 0 zurück, bei Erfolg einen 1 (False bzw. True).
Ihr fügt Eurem Projekt eine MFC-DLL hinzu und fügt das File DLL32.cpp diesem DLL-Projekt hinzu. Fertig.
Das VB.NET-Projekt besteht aus der Klasse Dll, darin sind die Deklarationen der DLL-Funktionen enthalten
sowie der Klasse Form1 mit beispielhaften Aufrufen dieser DLL-Funktionen.
Der mit SetValue() übergebene Wert wird aus einer TextBox ausgelesen, so kann die Funktion überprüft werden.
Ebenso werden die übergebenen ANSI- bzw. Unicode-Strings aus Textboxen ausgelesen.
Die rückgelesenen Werte werden in Labels ausgegeben.
----
Wichtig ist die richtige Verpackung der Parameter für die Übergabe an die DLL.
.NET überwacht den Speicher der angelegten Variablen, C / C++ tut dies nicht. Deswegen muss .NET den Inhalt der Variablen in einen nicht überwachten Speicher kopieren, der dann an die DLL übergeben werden kann. Dieser wird von der DLL ausgelesen bzw. befüllt, danach wird er in .NET ggf. ausgelesen und stets wieder freigegeben.
Die Daten sind dann in Variablen vom Typ IntPtr abgelegt, das rein- und rauskopieren wird in der Klasse Marshal durchgeführt.
----
Dieser Beitrag stellt keine vollständige Auflistung möglicher Parameterübergaben zwischen .NET und einer C-DLL dar, sondern er soll Anhaltspunkte geben, wie mit .NET-Parametern verfahren werden muss, um sie in eine C-DLL übergeben zu bekommen.
Vllt. noch ein paar Anmerkungen:
Der Ausführungspfad ist noch der von meinem Rechner, da müsst Ihr noch den Euren einfügen.
Im PostBuild wird die DLL und die PDB in das .NET-Debug-Verzeichnis kopiert, da müsst Ihr natürlich dann Eure Pfade eintragen.
Die Dateien PartMFC.cpp und PartMFC.h sind ein leere C++-Klasse, da kann über das Objekt theApp nach C++ verzweigt werden.
----
Bei den String-Transfer-Prozeduren im VB-Code habe ich vergessen, den nicht gemanageden Speicher aufzuräumen, da muss 4x folgende Zeile als jeweils letzte Zeile der Prozedur rein:
Eines sofort: Die Kommunikation mit einer C++-DLL ist so aus .NET nicht möglich, da ein unmanaged C++-Objekt erstellt werden muss, und das ist aus .NET nicht möglich, dazu bedarf es eines Wrappers in Form einer C-DLL.
Deswegen beschränken wir uns hier ausschließlich auf C-DLLs.
Primär ist stets, wie eine Prozedur in der C-DLL deklariert wurde, danach richtet sich die Übertragung in .NET.
Zur Information:
In C wird unterschieden, ob die Parameter einer Prozedur von vorn nach hinten oder von hinten nach vorn auf dem Stack abgelegt werden. Dies wird in der Deklaration der Funktion durch PASCAL bzw. _stdcall unterschieden.
Außerdem muss jede exportierte Prozedur als solche gekennzeichnet werden.
Ich habe folgende Beispiele implementiert:
- ein einfacher Aufruf: TestFunction(), es wird eine MessageBox ausgegeben.
- Schreiben eines Integer-Wertes in die DLL: SetValue(int value)
- Auslesen dieses Integer-Wertes aus der DLL: GetValue(int* value)
- Schreiben von n Integer-Werten in die DLL: SetValues(int* values, int anzahl)
- Auslesen dieser n Integer-Werte aus der DLL: GetValues(int* values, int anzahl)
- Schreiben eines ANSI-Strings in die DLL: SetStringAnsi(char* text)
- Auslesen dieses ANSI-Strings aus der DLL: GetStringAnsi(char** text)
- Schreiben eines Unicode-Strings in die DLL: SetStringUnicode(wchar_t* text)
- Auslesen dieses Unicode-Strings aus der DLL: GetStringUnicode(wchar_t** text)
Die Übergabeparameter werden abgetestet. Bei einem falschen Aufruf (zu große Anzahl von Werten im Array) kommt eine 0 zurück, bei Erfolg einen 1 (False bzw. True).
Ihr fügt Eurem Projekt eine MFC-DLL hinzu und fügt das File DLL32.cpp diesem DLL-Projekt hinzu. Fertig.
Das VB.NET-Projekt besteht aus der Klasse Dll, darin sind die Deklarationen der DLL-Funktionen enthalten
sowie der Klasse Form1 mit beispielhaften Aufrufen dieser DLL-Funktionen.
Der mit SetValue() übergebene Wert wird aus einer TextBox ausgelesen, so kann die Funktion überprüft werden.
Ebenso werden die übergebenen ANSI- bzw. Unicode-Strings aus Textboxen ausgelesen.
Die rückgelesenen Werte werden in Labels ausgegeben.
----
Wichtig ist die richtige Verpackung der Parameter für die Übergabe an die DLL.
.NET überwacht den Speicher der angelegten Variablen, C / C++ tut dies nicht. Deswegen muss .NET den Inhalt der Variablen in einen nicht überwachten Speicher kopieren, der dann an die DLL übergeben werden kann. Dieser wird von der DLL ausgelesen bzw. befüllt, danach wird er in .NET ggf. ausgelesen und stets wieder freigegeben.
Die Daten sind dann in Variablen vom Typ IntPtr abgelegt, das rein- und rauskopieren wird in der Klasse Marshal durchgeführt.
----
Dieser Beitrag stellt keine vollständige Auflistung möglicher Parameterübergaben zwischen .NET und einer C-DLL dar, sondern er soll Anhaltspunkte geben, wie mit .NET-Parametern verfahren werden muss, um sie in eine C-DLL übergeben zu bekommen.
Vllt. noch ein paar Anmerkungen:
Der Ausführungspfad ist noch der von meinem Rechner, da müsst Ihr noch den Euren einfügen.
Im PostBuild wird die DLL und die PDB in das .NET-Debug-Verzeichnis kopiert, da müsst Ihr natürlich dann Eure Pfade eintragen.
Die Dateien PartMFC.cpp und PartMFC.h sind ein leere C++-Klasse, da kann über das Objekt theApp nach C++ verzweigt werden.
----
Bei den String-Transfer-Prozeduren im VB-Code habe ich vergessen, den nicht gemanageden Speicher aufzuräumen, da muss 4x folgende Zeile als jeweils letzte Zeile der Prozedur rein:
Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch
Ein guter .NET-Snippetkonverter (der ist verfügbar).
Programmierfragen über PN / Konversation werden ignoriert!
Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch
Ein guter .NET-Snippetkonverter (der ist verfügbar).
Programmierfragen über PN / Konversation werden ignoriert!
Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „RodFromGermany“ () aus folgendem Grund: Anmerkungen editiert