![]() |
C++ Dll soll Zeichenkette manipulieren
Hallo DPler,
ich stehe grade mal wieder voll auf dem Schlauch. Und zwar möchte ich den Zeiger zu einem String an eine in C++ geschriebene DLL übergeben. Dort soll er dann verändert werden. Mit Zahlen ist das Ganze kein großes Problem, aber bei der Umsetzung mit Zeichenketten scheitert es dann komplett bei mir! Ich bin C++ Anfänger. Will mich jedoch mal der Herrausforderung stellen ein Teil in eine C++ Dll auszulagern (als Übung). Hier mal mein Code für Integer: C++ Dll:
Code:
Aufruf in Delphi:
extern "C" __declspec(dllexport) void Zahl_aendern(int * zahl);
void Zahl_aendern(int * zahl) { *zahl = 50; }
Delphi-Quellcode:
Das funktioniert perfekt, aber wie gestaltet man das Ganze mit Strings?
procedure Zahl_aendern(zahl: PInteger); cdecl; external 'meine_dll.dll';
... procedure TForm1.Button1Click(Sender: TObject); var i: integer; begin i:= 12; showmessage(inttostr(i)); //12 Zahl_aendern(@i); showmessage(inttostr(i)); //50 end; Ich hoffe Ihr könnt mir helfen :) |
Re: C++ Dll soll Zeichenkette manipulieren
In C gibt es keine Zeichenketten, die in Delphi einem String entsprächen. In C gibt es nur Charakter-Arrays. Diese entsprechen in Delphi dem Datentyp PChar. Und dann geht eigentlich alles so wie hier
![]() IN C++ gibt es noch die String Klasse, definiert in String.h, glaube ich. In wie fern diese mit den Delphi Stringtyp kompatibel sind kann ich nicht sagen. Ich vermute aber sie sind eher nicht kompatibel. |
Re: C++ Dll soll Zeichenkette manipulieren
ja so ungefähr war mir das ganze schon klar auch wenn es ziemlich komplex gemacht ist, aber mir fehlt jegliche vorstellung wie ich es in c++ umsetzen soll. :(
PChar liefert mir zwar den Zeiger auf den Char-Array, aber ich kann den Inhalt nicht verändern in C++. Das führt zu folgendem Fehler:
Code:
error C2440: '=': 'const char [6]' kann nicht in 'char' konvertiert werden
extern "C" __declspec(dllexport) void String_aendern(char * sstring);
void String_aendern(char ** sstring) { *sstring = "Hallo"; } Mir fehlt die Grundlage in C++ :( |
Re: C++ Dll soll Zeichenkette manipulieren
Hallo,
erstmal kannst du nicht einmal char* und einmal char** schreiben. char* reicht :) . Da hast du dann auch die kompatibilität mit dem Delphi PChar. Dann solltest du den neuen String mittels
Code:
einkopieren. Dann sollte es gehen. Kann sein, dass Quelle und Ziel vertauscht sind, da musst du mal in der Hilfe schauen, hab ich jetzt nicht im Kopf.
strcpy(sstring, "Hallo");
Edit: Die C++Klasse string kommt aus der STL (Standard Template Library oder Standard C++ Library, wie sie heute heißt, trotzdem sagen alle STL :) ) und ist definitiv nicht kompatibel mit einem Delphi-Stringtyp. |
Re: C++ Dll soll Zeichenkette manipulieren
Der Fehler oben im Quelltext war unbeabsichtigt. Hab ihn im Original auch nicht gehabt.
StrCpy führt immer zu einer Zugriffsverletzung in der DLL (meldet Delphi). |
Re: C++ Dll soll Zeichenkette manipulieren
Kommt die AV beim Aufruf oder direkt bei strcpy? Du könntest mal versuchen, die DLL-Funktion direkt aus C aufzurufen, ob das da auch passiert.
|
Re: C++ Dll soll Zeichenkette manipulieren
Wenn der String aka AnsiString verändert werden soll, dann geht das maximal nur dann, wenn der String nicht länger wird und die Referenzzählung auf 1 steht.
Wenn de String länger werden soll, mehr als eine Referenz existiert und bei Konstanten müßte man Speicher reservieren und dazu müßtest du auch noch die Funktionen des Speichermanagers exportieren. Bei WideString ist es einfacher, da dieser Delphiintern einen OleStr kapselt, welcher auch in C verfügbar wäre. |
Re: C++ Dll soll Zeichenkette manipulieren
Einen Delphistring in C zu verändern, das ist ja, wie mit dem Flugzeug zum Bahnhof zu fliegen um dann mit dem Zug nach Mallorca zu fahren.
Wie himitsu schon schreibt, du kannst einen Delphistring nicht in C verändern. Entweder du nimmst einen widestring, oder du präparierst den string vorher um. Dazu musst du ihn in ein array[0..x] of char kopieren (am besten mit "move"). |
Re: C++ Dll soll Zeichenkette manipulieren
Liste der Anhänge anzeigen (Anzahl: 1)
ich bin nich so gut in C ... drum hab ich's mal in Delphi gemacht, aber läßt sich bestimmt leicht konvertieren
drei Funktionen welche dann in der C-DLL drin wären 1: versucht 'nen kürzeren String einzutragen 2: versucht 'nen längeren String einzutragen 3: trägt einen String ein, incl. Speichermanagement
Delphi-Quellcode:
und die Testaufrufe:
Type PAnsiStringInfo = ^TAnsiStringInfo;
TAnsiStringInfo = packed Record RefCount: LongInt; ElementCount: LongInt; DataAddr: packed Array[0..0] of AnsiChar; End; Function _SetString1(PString: PPointer): Boolean; StdCall; Var i: Integer; S: AnsiString; P: PAnsiStringInfo; Begin SetLength(S, 5); For i := 1 to 5 do S[i] := Chr($41 + Random(26)); P := Pointer(Integer(PString^) - 8); If (PString^ <> nil) and (P.RefCount = 1) and (P.ElementCount >= Length(S)) Then Begin P.ElementCount := Length(S); MoveMemory(@P.DataAddr, PAnsiChar(S), Length(S) + 1); Result := True; End Else Result := False; End; Function _SetString2(PString: PPointer): Boolean; StdCall; Var i: Integer; S: AnsiString; P: PAnsiStringInfo; Begin SetLength(S, 10); For i := 1 to 10 do S[i] := Chr($41 + Random(26)); P := Pointer(Integer(PString^) - 8); If (PString^ <> nil) and (P.RefCount = 1) and (P.ElementCount >= Length(S)) Then Begin P.ElementCount := Length(S); MoveMemory(@P.DataAddr, PAnsiChar(S), Length(S) + 1); Result := True; End Else Result := False; End; Type TDelphiGetMemory = function(Size: Integer): Pointer; CDecl; TDelphiFreeMemory = function(P: Pointer): Integer; CDecl; Var DelphiGetMemory: TDelphiGetMemory; DelphiFreeMemory: TDelphiFreeMemory; Procedure SetString3Memory(GetMem: TDelphiGetMemory; FreeMem: TDelphiFreeMemory); StdCall; Begin DelphiGetMemory := @GetMem; DelphiFreeMemory := @FreeMem; End; Function _SetString3(PString: PPointer): Boolean; StdCall; Var i: Integer; S: AnsiString; P: PAnsiStringInfo; Begin SetLength(S, 7); For i := 1 to 7 do S[i] := Chr($41 + Random(26)); P := Pointer(Integer(PString^) - 8); If S > '' Then Begin If (PString^ = nil) or (P.RefCount = -1) Then Begin End Else If P.RefCount > 1 Then Begin Dec(P.RefCount); End Else If P.ElementCount <> Length(S) Then Begin DelphiFreeMemory(P); End; P := DelphiGetMemory(8 + Length(S) + 1); P.RefCount := 1; P.ElementCount := Length(S); MoveMemory(@P.DataAddr, PAnsiChar(S), Length(S) + 1); PString^ := Pointer(Integer(P) + 8); End Else Begin If PString^ <> nil Then If P.RefCount = -1 Then PString^ := nil Else If P.RefCount <> 0 Then Begin Dec(P.RefCount); If P.RefCount = 0 Then Begin DelphiFreeMemory(P); PString^ := nil; End; End; End; Result := True; End;
Delphi-Quellcode:
Var ZweitString: AnsiString;
Procedure TForm1.FormCreate(Sender: TObject); Const BoolStr: Array[Boolean] of String = ('False', 'True '); ConstString = '123456789'; Var S: AnsiString; B: Boolean; Begin Memo1.Lines.Add(''); Memo1.Lines.Add('Leerstring'); Memo1.Lines.Add('ConstString'); Memo1.Lines.Add('String mit Referenzzähler = 1'); Memo1.Lines.Add('String mit Referenzzähler = 2'); Memo1.Lines.Add(''); S := ''; Memo1.Lines.Add(Format('x1 - False - "%s"', [S])); S := ConstString; Memo1.Lines.Add(Format('x2 - False - "%s"', [S])); SetLength(S, 8); Memo1.Lines.Add(Format('x3 - False - "%s"', [S])); ZweitString := S; Memo1.Lines.Add(Format('x4 - False - "%s"', [S])); Memo1.Lines.Add(''); S := ''; B := SetString1(S); Memo1.Lines.Add(Format('11 - %s - "%s"', [BoolStr[B], S])); S := ConstString; B := SetString1(S); Memo1.Lines.Add(Format('12 - %s - "%s"', [BoolStr[B], S])); SetLength(S, 8); B := SetString1(S); Memo1.Lines.Add(Format('13 - %s - "%s"', [BoolStr[B], S])); ZweitString := S; B := SetString1(S); Memo1.Lines.Add(Format('14 - %s - "%s"', [BoolStr[B], S])); Memo1.Lines.Add(''); S := ''; B := SetString2(S); Memo1.Lines.Add(Format('21 - %s - "%s"', [BoolStr[B], S])); S := ConstString; B := SetString2(S); Memo1.Lines.Add(Format('22 - %s - "%s"', [BoolStr[B], S])); SetLength(S, 8); B := SetString2(S); Memo1.Lines.Add(Format('23 - %s - "%s"', [BoolStr[B], S])); ZweitString := S; B := SetString2(S); Memo1.Lines.Add(Format('24 - %s - "%s"', [BoolStr[B], S])); Memo1.Lines.Add(''); SetString3Memory(@GetMemory, @FreeMemory); S := ''; B := SetString3(S); Memo1.Lines.Add(Format('31 - %s - "%s"', [BoolStr[B], S])); S := ConstString; B := SetString3(S); Memo1.Lines.Add(Format('32 - %s - "%s"', [BoolStr[B], S])); SetLength(S, 8); B := SetString3(S); Memo1.Lines.Add(Format('33 - %s - "%s"', [BoolStr[B], S])); ZweitString := S; B := SetString3(S); Memo1.Lines.Add(Format('34 - %s - "%s"', [BoolStr[B], S])); End;
Code:
wie man sieht, geht es nur bedingt.
Leerstring
ConstString String mit Referenzzähler = 1 String mit Referenzzähler = 2 x1 - False - "" x2 - False - "123456789" x3 - False - "12345678" x4 - False - "12345678" 11 - False - "" 12 - False - "123456789" 13 - True - "CMBVB" 14 - False - "CMBVB" 21 - False - "" 22 - False - "123456789" 23 - False - "12345678" 24 - False - "12345678" 31 - True - "CUMWNOY" 32 - True - "RIASZUT" 33 - True - "FDXUPWR" 34 - True - "HCQHWEH" 11 - kein String vorhanden 12 - geht nicht, da Konstante und somit ist kein Speicher reserviert 13 - Sring ist kurz genug und Referenzzählung steht auf 1 14 - Referenzzählug > 1 21 - kein String vorhanden 22 - geht nicht, da Konstante und somit ist kein Speicher reserviert 23 - Referenzzählung steht zwar auf 1, aber einzutragender String ist zu lang 24 - Referenzzählug > 1 Im Endefekt muß man den String auf seine interne Struktur zerlegen und alles selbst verwalten ... es sei denn, einer erfindet 'ne Klasse dafür bzw. man macht auf _SetString3 eine Prozedur, welcher man zusätzlich noch 'nen C-String übergeben kann, welcher in den Delphi-String kopiert wird. einzig und allein die 23 liese sich noch ändern, indem alles was länger ist abgeaschnitten wird. |
Re: C++ Dll soll Zeichenkette manipulieren
Was mir wegen der AV grad noch eingefallen ist: Reservierst du in deinem Delphiprogramm Speicher für den String?
[OT] Zitat:
[\OT] |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:40 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz