Laden...

P/Invoke mit char*

Erstellt von Mr. Bart Simpson vor 18 Jahren Letzter Beitrag vor 18 Jahren 3.696 Views
Mr. Bart Simpson Themenstarter:in
502 Beiträge seit 2004
vor 18 Jahren
P/Invoke mit char*

Ich versuche verzweifelt eine C++ DLL via P/Invoke zu nutzen. Im Prinzip klappt das Ganze auch, aber es gibt da einige Methoden, die char* Parameter benutzen um strings zurückzugeben. Beispiel:

int get_version (int session, char * version, size_t len);

Das wird dann folgendermaßen eingebunden:

public static extern int get_version (int session, System.Text.StringBuilder version, int len);

Ich hab's schon in allen möglichen Variationen probiert z.B. ref auf den Stringbuilder, MarshallAs(...) - Resultat beim Aufruf ist immer das Gleiche: System.NullReferenceException.

Hat irgendwer 'ne Ahnung? Ich hab schon 20 Artikel in der MSDN zum Thema Marshalling von Strings gelesen. Dummerweise war natürlich kein Einziger dabei, der genau das beschreibt was ich bräuchte...

Bart Simpson

Praxis ist wenn alles funktioniert und keiner weiss warum.
Theorie ist wenn man alles weiss, aber nichts funktioniert.

Bei uns wird Theorie und Praxis vereint: Nichts funktioniert und keiner weiss warum...

X
2.051 Beiträge seit 2004
vor 18 Jahren

erstellst du den StringBuilder vor dem benutzen?
so etwa

 
len = 1024;
System.Text.StringBuilder  version = new System.Text.StringBuilder (len);

get_version (session, version, len);

4.221 Beiträge seit 2005
vor 18 Jahren

Und ist der Stringbuilder schon mit einem String gefüllt ? (damit der Platz reserviert ist für die Rückgabe)

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

S
8.746 Beiträge seit 2005
vor 18 Jahren

Vielleicht noch nen Size+1 für die Nullterminierung? Aber vermutlich ist dein Puffer schon groß genug....

Mr. Bart Simpson Themenstarter:in
502 Beiträge seit 2004
vor 18 Jahren

Hätt ich vielleicht dazu schreiben sollen: Der Stringbuilder ist natürlich erzeugt und ich geb auch genug Platz mit... Ich hab sogar schon versucht 'nen Stringbuilder mit mehr als 2*len anzulegen, falls es irgendwelche Problem mit ANSI/Unicode oder so geben sollte... Keine Wirkung.

@Programmierhans: Der Stringbuilder gefüllt? Sollte doch wohl nicht nötig sein, oder? Wenn ich das richtig verstanden hab, muss nur die Capacity vom Stringbuilder (sprich: dessen Puffer) groß genug sein. Oder bin ich da auf dem Holzweg?

Ich tippe darauf, dass es wohl am falschen Marshalling des Strings liegt... Aber wie zur Hölle krieg ich raus, welchen UnmanagedType ich denn nehmen muss?
Mittlerweile hab ich in dem (na nennen wir's mal beschönigend🙂 SDK folgendes gefunden:

Eingaben müssen im Zeichensatz ISO 8859-1 übergeben werden. Auch die Ausgaben erfolgen
in diesem Zeichensatz. Sollen in Sonderfällen andere Zeichensätze zum Einsatz kommen (z.B.
MSDOS-Zeichensatz), müssen die Zeichen umgesetzt werden.

Das heisst doch es ist irgendein Nicht-Unicode Zeichensatz, oder? Es müsste also irgenwas wie MarshallAs(UnmanagedType.LPStr) sein, denk ich...
ABER: Bei dem speziellen Beispiel geb ich natürlich nichts mit, es ist ja eine reine Ausgabefunktion - d.h. Unabhängig davon ob ich was sinnvolles krieg oder nur Müll, es müsste doch zumindest klappen und im Puffer des Stringbuilders müsste irgendwas sein. Und vor allem sollte ich nicht die Exception kriegen... verzweifel

Bart Simpson

Praxis ist wenn alles funktioniert und keiner weiss warum.
Theorie ist wenn man alles weiss, aber nichts funktioniert.

Bei uns wird Theorie und Praxis vereint: Nichts funktioniert und keiner weiss warum...

4.221 Beiträge seit 2005
vor 18 Jahren

Hau mal genügend Zeichen in den Stringbuilder rein vor dem Aufruf

.... am besten nimmste hierführ den constructor des strings welcher char und count entgegennimmt

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

Mr. Bart Simpson Themenstarter:in
502 Beiträge seit 2004
vor 18 Jahren

Also das vorherige Füllen (ich hab's mit ASCII(0) und Space propiert) bringt auch nix... langsam weiss ich echt keinen Rat mehr 😦

Irgendwer noch irgendwelche Konstruktiven Vorschläge? Mittlerweile bin ich auch für die abwegig klingenden offen...

Bart Simpson

Praxis ist wenn alles funktioniert und keiner weiss warum.
Theorie ist wenn man alles weiss, aber nichts funktioniert.

Bei uns wird Theorie und Praxis vereint: Nichts funktioniert und keiner weiss warum...

X
2.051 Beiträge seit 2004
vor 18 Jahren

was ist das für ne dll? selbstgeschriebene?

klappt es mit dieser methode aus c++ aus?

wenn ja, vielleicht mal eine wrapper-klassse im managed c++ schreiben?

Mr. Bart Simpson Themenstarter:in
502 Beiträge seit 2004
vor 18 Jahren

Die Dll entstammt einer Hardwaresteuerung von der's den Hersteller leider nicht mehr gibt... Ich muss also wohl oder übel mit dem Leben, was man mir vorgesetzt hat.

Die Idee mal mit managed C++ ran zu gehen klingt interessant - aber kann das was bringen? Ich hab noch nicht mit den managed Extensions gearbeitet, aber gibt's da dann noch char* und so'n Zeug? Ich dachte die CLR übernimmt auch für C++ so Sachen wie Zeigerarithmetik?

Bart Simpson

Praxis ist wenn alles funktioniert und keiner weiss warum.
Theorie ist wenn man alles weiss, aber nichts funktioniert.

Bei uns wird Theorie und Praxis vereint: Nichts funktioniert und keiner weiss warum...

S
8.746 Beiträge seit 2005
vor 18 Jahren

Du könntest nochmal eins versuchen:

Hole dir unmanaged Speicher und schiebe ihn per IntPtr in die Methode. Da findet nun kein Marshalling mehr statt und es sollte funzen. Natürlich musst du den Speicher dann auch explizit freigeben.

Mr. Bart Simpson Themenstarter:in
502 Beiträge seit 2004
vor 18 Jahren

Von hinten durch die Brust ins Auge 😉 Ich hab jetzt eine Managed C++ Klasse erstellt (naja, sagen wir mal sie ist da-hat aber erst eine Methode...).
Ausserhalb der Klasse, aber im gleichen Modul hab ich dann die aufzurufenden Funktionen als external deklariert. Die kann ich dann wiederrum von Klassenmethoden aus aufrufen, welche zu guter letzt aus meiner C# App aufgerufen werden....

Das klappt tatsächlich und ich kann damit Strings als Parameter übergeben und auch wieder als out-Parameter holen... Aber das kann's ja wohl nicht sein, oder? Das ist ja umständlicher als irgendwas... Und das Beste dran: Warum zur # ist das .net Framework bei Managed C++ offensichtlich "schlauer" als bei der "speziell dafür designten Sprache" C#???
Innerhalb der C++ Klasse gibt's nämlich überhaupt kein Problem mit dem Marshalling (falls man das an der Stelle so nennen kann) - Ich kann direkt System::String* übergeben bzw. zurückgeben (was dann von C#-Seite aus string entspricht) und das an die externen Funktionen als char* übergeben...

@svenson: Noch eine neue Idee - klingt aber noch komplexer. Da muss ich mich ja direkt selbst um den Speicher kümmern... Ist ja fast wie in alten Turbo Pascal Tagen 🙂
Oder sieht das Ganze mittlerweile einfacher (und vor allem "sicherer") aus? Ein kurzes Beispiel wäre nett.

Bart Simpson

Praxis ist wenn alles funktioniert und keiner weiss warum.
Theorie ist wenn man alles weiss, aber nichts funktioniert.

Bei uns wird Theorie und Praxis vereint: Nichts funktioniert und keiner weiss warum...

X
2.051 Beiträge seit 2004
vor 18 Jahren

kann man deine dll mal zum "spielen" haben?

ich würde gerne deine funktion mal testen.

Mr. Bart Simpson Themenstarter:in
502 Beiträge seit 2004
vor 18 Jahren

Original von Xqgene
kann man deine dll mal zum "spielen" haben?

ich würde gerne deine funktion mal testen.

Wird leider nicht klappen - die Dll tut ohne die zugehörige Hardware gar nichts!
Mal abgesehen von irgendwelchen Zugriffsverletzungen 😉

Und: Ich weiss nicht, ob ich das (aus rechtlichen Gründen) überhaupt dürfte...

Bart Simpson

Praxis ist wenn alles funktioniert und keiner weiss warum.
Theorie ist wenn man alles weiss, aber nichts funktioniert.

Bei uns wird Theorie und Praxis vereint: Nichts funktioniert und keiner weiss warum...

S
8.746 Beiträge seit 2005
vor 18 Jahren

Original von Mr. Bart Simpson
@svenson: Noch eine neue Idee - klingt aber noch komplexer.

Keine Frage: Aber wenn DAS auch nicht geht, dann kann man einen Fehler beim Marshalling ausschliessen. Das ganze soll nur ein Schritt zur eigentlichen Fehlerfindung sein.