12.03.2010, 14:39
Beitrag #1
|
ptillmann
LVF-Neueinsteiger
Beiträge: 1
Registriert seit: Mar 2010
7.1.1
-
de
34246
Deutschland
|
LV 7.1, VC++-DLL (VC++2008), string-Übergabe
Liebe LeserInnnen,
meine Aufgabe ist es, eine Wrapper-DLL für LV 7.1 zu erstellen. Mein Problem ist die Übergabe von Strings.
Die DLL (VC++ 2008) stellt folgende Funktion bereit:
<blockquote>extern "C" CZPLSDLL_API long WINAPI get_ComponentNames (LPCSTR sCalibFile,
long nExperiment, long nComponent, LPSTR sComponent, long *nComponentSize)
{
<blockquote>[...]
char nstring[100];
[...]
size_t origsize = strlen(nstring);
origsize = min(100,origsize);
memcpy(sComponent,nstring,origsize);
memcpy(sComponent+origsize,"",1);
*nComponentSize = origsize;
return 0;
</blockquote>
}
</blockquote>
Compiler-Einstellungen:
- __stdcall
- /clr (weil gewrappte DLL in C# geschrieben ist)
- /Zp1 (Ausrichten Strukturmember: 1 Byte)
Das Problem:
Wenn ich hinter char nstring[100]; nstring wie folgt deklariere
<blockquote> char nstring[100];
strcpy(nstring,"asdh");
</blockquote>
übernimmt LabVIEW den String korrekt. Wenn ich den String aus meiner gewrappten DLL fülle z.B.
<blockquote> char nstring[100];
String ^str = prd.getString(0);
pin_ptr<const wchar_t> wch = PtrToStringChars(str);
// Convert to a char*
const size_t newsize = 100;
WideCharToMultiByte(CP_ACP, 0, wch, -1, nstring, 100, NULL, NULL);
</blockquote>
(das Ganze liest einen String aus der gemanageden C#-DLL ein, kodiert ihn auf ASCII um und schreibt ihn nach nstring), dann zeigt LabVIEW nur Müll an.
Wenn ich die Wrapper-DLL aus einen VC++-Programm aus aufrufe, kann ich in beiden Varianten der String-Deklaration die Strings korrekt auslesen.
In beiden Varianten der String-Deklaration ist die Stringlänge korrekt, d.h.
<blockquote> sprintf(nstring,"Laenge %d", strlen(nstring));
</blockquote>
liefert die korrekten Werte an LabVIEW und mein VC++-Programm.
Ich habe das Gefühl, es könnte etwas mit UNICODE und ASCII zu tun haben. Nach Lesen des DLL-Tutorials und 3 Jahren Forums-Einträgen, sowie Stunden der alternativen Deklaration (std:string, Cstr, strcpy, memcpy, ...) erlaube ich mir die Frage hier zu stellen.
Ich habe z.Z. keinen Zugriff auf den LV-Code.
Danke
Peter Tillmann
|
|
|
12.03.2010, 20:34
Beitrag #2
|
rolfk
LVF-Guru
Beiträge: 2.305
Registriert seit: Jun 2007
alle seit 6.0
1992
EN
2901GG
Niederlande
|
LV 7.1, VC++-DLL (VC++2008), string-Übergabe
Also in Deinem C code ist einiger Müll drin der wenig Sinn macht:
' schrieb:<blockquote>extern "C" CZPLSDLL_API long WINAPI get_ComponentNames (LPCSTR sCalibFile,
long nExperiment, long nComponent, LPSTR sComponent, long *nComponentSize)
{
[indent][...]
char nstring[100];
[...]
size_t origsize = strlen(nstring);
origsize = min(100,origsize);
Was soll das? nstring ist 100 bytes lang. Entweder ist der String in nstring sowieso kürzer als 100 (eigentlich 99 Bytes) oder die Funktion die da hineingeschrieben hat hat schon lange Speicher überschrieben den sie nicht hätte überschreiben sollen und dann macht diese Sicherheitsabfrage das auch nicht mehr gut.
Zudem liefert Dir die Funktion WideCharToMultiByte() die Du da ja gemäss dem späteren Code verwendest als Returnwert genau diese Zahl um eins vermindert und dann ist es dumm um da noch mal ein strlen() zu machen.
Zitat:memcpy(sComponent,nstring,origsize);
memcpy(sComponent+origsize,"",1);
Wo bitte schön ist das NULL Byte zum Abschluss des Stringes. LPZSTR ist ein Null-terminated ASCI String aber memcpy() macht keine NULL Bytes in einen String.
Zitat:Wenn ich den String aus meiner gewrappten DLL fülle z.B.
[indent] char nstring[100];
String ^str = prd.getString(0);
pin_ptr<const wchar_t> wch = PtrToStringChars(str);
// Convert to a char*
const size_t newsize = 100;
WideCharToMultiByte(CP_ACP, 0, wch, -1, nstring, 100, NULL, NULL);
</blockquote>
(das Ganze liest einen String aus der gemanageden C#-DLL ein, kodiert ihn auf ASCII um und schreibt ihn nach nstring), dann zeigt LabVIEW nur Müll an.
Wenn ich die Wrapper-DLL aus einen VC++-Programm aus aufrufe, kann ich in beiden Varianten der String-Deklaration die Strings korrekt auslesen.
In beiden Varianten der String-Deklaration ist die Stringlänge korrekt, d.h.
<blockquote> sprintf(nstring,"Laenge %d", strlen(nstring));
</blockquote>
liefert die korrekten Werte an LabVIEW und mein VC++-Programm.
Ich habe das Gefühl, es könnte etwas mit UNICODE und ASCII zu tun haben. Nach Lesen des DLL-Tutorials und 3 Jahren Forums-Einträgen, sowie Stunden der alternativen Deklaration (std:string, Cstr, strcpy, memcpy, ...) erlaube ich mir die Frage hier zu stellen.
Ich habe z.Z. keinen Zugriff auf den LV-Code.
Das ist schade, denn könnte es sein dass das LabVIEW Programm schlichtweg vergisst entsprechende Buffer für die Stringparameter anzulegen? LabVIEW macht zwar im Diagram überall automatische Memoryverwaltung und passt Buffer wann nötig an aber für die Call Library Node und C Datenpointer geht das schlichtweg nicht, da LabVIEW auf keine einzige Art zum voraus wissen kann wie gross ein Buffer sein muss, und die DLL diesen normalerweise nicht selber anlegt und wenn sie es auch täte kommt dieser Pointer nie durch die Parameterliste zum Aufrufer zurück.
|
|
|
| |