AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

PChars und Dll

Ein Thema von Billi Berserker · begonnen am 13. Aug 2006 · letzter Beitrag vom 14. Aug 2006
Antwort Antwort
Seite 1 von 2  1 2      
Billi Berserker
(Gast)

n/a Beiträge
 
#1

PChars und Dll

  Alt 13. Aug 2006, 10:43
Ich habe ein ziemliches Problem mit PChars die aus einer Dll in irgendeine Anwendung oder dll übergeben werden.
In einer dll gibt eine funktion einen String als PChar an die Anwendung zurück, die Anwendung ließt den PChar einfach auf einen String und benutzt den weiter. Funktioniert an sich relativ gut, nur ist das Problem das total zufällig und nur für manche User am Ende der PChars noch die 0 stehen bleibt.
Gibt die DLL den String 'C:\SharpE\Settings' zurück kommt bei einigen wenigen Usern 'C:\SharpE\Settings0' an. Das seltsame ist das es im normalfall ohne Probleme geht und nur ganz selten diese Strings mit der 0 am Ende ankommen. Das ganze betrifft auch nicht nur eine funktion der dll, sondern ausnahmslos alle die einen PChar zurück geben.

der Code sieht folgendermaßen aus:

Beispiel für eine function aus der dll:
Delphi-Quellcode:
function GetCurrentSkinFile : PChar;
var
  SkinDir : String;
  SkinName : String;
  stemp:String;
begin
  SkinDir := GetSkinDirectory;
  SkinName := GetSkinName;
  stemp := SkinDir +
           IncludeTrailingBackslash(SkinName) +
           'Skin.xml';
  result := PChar(stemp);
end;
Ich habe es auch bereits so probiert das stemp eine globale variable in der dll ist... hat auch keinen großen Unterschied gemacht.
in der Anwendung werden die funktionen meisten direkt benutzt oder auf Strings eingelesen.
also z.b. direkt: XML.LoadFromFile(SharpApi.GetCurrentSkinFile);

Ich geh einfach mal schwer davon aus das irgendwas mit der PChar Handhabung in der dll nicht stimmt,
die Frage ist nur was genau?
  Mit Zitat antworten Zitat
Benutzerbild von Jelly
Jelly

Registriert seit: 11. Apr 2003
Ort: Moestroff (Luxemburg)
3.741 Beiträge
 
Delphi 2007 Professional
 
#2

Re: PChars und Dll

  Alt 13. Aug 2006, 10:47
Hast Du sowohl in deiner DLL als auch in deinem Programm jeweils die Unit ShareMem eingebunden. Die Unit muss als allererste eingebunden werden.
  Mit Zitat antworten Zitat
Jürgen Thomas

Registriert seit: 13. Jul 2006
Ort: Berlin
750 Beiträge
 
#3

Re: PChars und Dll

  Alt 13. Aug 2006, 10:51
Sind GetSkinDirectory und GetSkinName Strings oder PChar?

Delphi nimmt die Umwandlung bei den Zuweisungen zwar oft automatisch vor; aber sicherer ist ggf.:
Delphi-Quellcode:
// nur gültig, wenn GetSkinDirectory und GetSkinName jeweils PChar liefern
SkinDir := StrPas(GetSkinDirectory);
SkinName := StrPas(GetSkinName);
Hoffentlich hilft's! Jürgen
#D mit C# für NET, dazu Firebird
früher: Delphi 5 Pro, Delphi 2005 Pro mit C# (also NET 1.1)
Bitte nicht sauer sein, wenn ich mich bei Delphi-Schreibweisen verhaue; ich bin inzwischen an C# gewöhnt.
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#4

Re: PChars und Dll

  Alt 13. Aug 2006, 10:52
dir fehlt glaub ich das Verständnis was PChar ist.
PChar ist nichts anderes als ein Pointer der auf eine Reihe von zeischen zeigt welche in der Regel mit #0 terminiert wird.
Mit
result := PChar(stemp); gibst du also einen Pointer auf die Zeischen von "sTemp" zurück.
Allerdings ist nach verlassen deiner Funktion sTemp gar nicht mehr verfügbar da es eine lokale Variable ist welche auf dem Stack abgelegt werden. Nach verlassen deiner Funktion ist sTemp also nicht mehr gültig. Deine Funktion funktioniert allerdings ab und zu weil zu dem Zeitpunkt vermutlich auf dem Stack noch nix neues liegt. Sobald aber was neues auf dem Stack liegt überschreibt dies den Wert der früher auf dem Stack lagt wo dein Pointer drauf zeigt.
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
Billi Berserker
(Gast)

n/a Beiträge
 
#5

Re: PChars und Dll

  Alt 13. Aug 2006, 11:02
Zitat von Jelly:
Hast Du sowohl in deiner DLL als auch in deinem Programm jeweils die Unit ShareMem eingebunden. Die Unit muss als allererste eingebunden werden.
Nein ist weder in dll noch in irgendeiner der Anwendungen angegeben.
Ich dachte eigentlich das man ShareMem nicht braucht wenn man mit PChars arbeitet.

Sollte ich jetzt ShareMem in der dll hinzufügen,
bringt das irgendwelche Nachteile mit sich und könnten auch Anwendungen die kein ShareMem eingebunden haben die dll noch nutzen?
Und was ist mit anwendungen die in anderen Programmiersprachen geschrieben sind?


Zitat von Jürgen Thomas:
Sind GetSkinDirectory und GetSkinName Strings oder PChar?

Delphi nimmt die Umwandlung bei den Zuweisungen zwar oft automatisch vor; aber sicherer ist ggf.:
Delphi-Quellcode:
// nur gültig, wenn GetSkinDirectory und GetSkinName jeweils PChar liefern
SkinDir := StrPas(GetSkinDirectory);
SkinName := StrPas(GetSkinName);
Hoffentlich hilft's! Jürgen
Alle funktionen geben PChar zurück.
Die zusätzliche 0 tritt im normalfall auch nur am Ende auf und nicht mittendrin.


Zitat von SirThornberry:
dir fehlt glaub ich das Verständnis was PChar ist.
PChar ist nichts anderes als ein Pointer der auf eine Reihe von zeischen zeigt welche in der Regel mit #0 terminiert wird.
Mit
result := PChar(stemp); gibst du also einen Pointer auf die Zeischen von "sTemp" zurück.
Allerdings ist nach verlassen deiner Funktion sTemp gar nicht mehr verfügbar da es eine lokale Variable ist welche auf dem Stack abgelegt werden. Nach verlassen deiner Funktion ist sTemp also nicht mehr gültig. Deine Funktion funktioniert allerdings ab und zu weil zu dem Zeitpunkt vermutlich auf dem Stack noch nix neues liegt. Sobald aber was neues auf dem Stack liegt überschreibt dies den Wert der früher auf dem Stack lagt wo dein Pointer drauf zeigt.
Wäre der ganze String in der Anwendung total verstümmelt und falsch würde ich dem ja zustimmen, die sache ist aber das nur am Ende eine 0 übrig bleibt und der spaß in 99,9% aller fälle funktioniert.
Was passiert denn wenn ich in der Anwendunge eine globale/lokale String variable habe und den rückgabewert darauf zuweise? Da wird sicherlich nicht nur einfach der pointer auf die dll Daten kopiert sondern der Inhalt in die neue lokale/globale String variable kopiert. Oder?
  Mit Zitat antworten Zitat
Benutzerbild von faux
faux

Registriert seit: 18. Apr 2004
Ort: Linz
2.044 Beiträge
 
Turbo Delphi für Win32
 
#6

Re: PChars und Dll

  Alt 13. Aug 2006, 11:07
Zitat von Jelly:
Hast Du sowohl in deiner DLL als auch in deinem Programm jeweils die Unit ShareMem eingebunden. Die Unit muss als allererste eingebunden werden.
Aber doch nur, wenn man Strings selbst übergibt. Er übergibt doch einen PChar und wandelt diesen intern in einen String um, um besser damit arbeiten zu können, oder irre ich?!
Faux Manuel
Wer weiß, dass er nichts weiß, weiß mehr, als der der nicht weiß, dass er nichts weiß.
GoTrillian
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#7

Re: PChars und Dll

  Alt 13. Aug 2006, 11:14
@Billi Berserker: Wenn dein String eine globale Variable ist funktioniert es ohne Probleme mit
result := PChar(GlobaleStringVariable); es muss eben nur eine Variable sein die nach verlassen der Funktion noch gültig ist.

Das mit dem Stack war ein Fehler meiner seits. Bei Strings wird auf dem Stack nur ein Pointer abglegt welcher dann auf den eigentlichen String zeigt. Durch den Cast auf PChar wird ein Pointer zurück gegeben der auf den Speicher zeigt wo die Zeischen liegen. Nach verlassen der Funktion wird der Speicher zwar freigegeben (vom Memorymanager) aber ist immer noch im Prozess gültig. In 99% der Fälle wird dieser Speicher danach nicht wieder verwendet. In einigen Fällen wird aber an der Stelle wo ursprünglich die zeischen des Strings lagen was neues hinn geschrieben und somit ist dein String nicht mehr korrekt.

Und die Unit ShareMem braucht man nur wenn man zwischen DLL und Hauptprogramm mit Strings etc. arbeiten will wie direkt im Programm. Dies hat allerdings den Nachteil das Programme anderer Programmiersprachen die Funktionen nicht nutzen können weil diese keine Delphistrings kennen. Zudem muss die sharemem.dll mit dem Programm immer mitgegeben werden.
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
Billi Berserker
(Gast)

n/a Beiträge
 
#8

Re: PChars und Dll

  Alt 13. Aug 2006, 11:20
Ich werds mal versuchen stemp dann als global in der dll zu definieren.
Hatte ich zwar soweit ich mich erinnere bereits probiert aber ich geh jetzt nochmals alle funktionen durch.
Das komische ist halt aber wirklich das der String an sich noch korrekt ist, der kann extremst lang sein und es sind keine Fehler drin. Nur sehr sehr selten ist am Ende noch eine zusätzliche '0' dran.

Was ich im ersten post vergessen habe ist das die meisten Anwendungen die die dll benutzen mit vcl und rtl runtime packages compiliert sind und die dll nicht mit den runtime packages compiliert ist.
  Mit Zitat antworten Zitat
m.wollert

Registriert seit: 18. Aug 2003
Ort: Heilbronn
92 Beiträge
 
FreePascal / Lazarus
 
#9

Re: PChars und Dll

  Alt 13. Aug 2006, 11:33
Hi,

die Frage an sich ist, wie lange "stemp" gültig ist.

Ich würde als Versuch für "stemp" explizit Speicher reservieren und in der DLL den Speicher wieder freigeben.
Michael
*Im Auftrag ewiger Jugend und Glückseligkeit*
  Mit Zitat antworten Zitat
Benutzerbild von Flocke
Flocke

Registriert seit: 9. Jun 2005
Ort: Unna
1.172 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#10

Re: PChars und Dll

  Alt 13. Aug 2006, 12:49
Einen PChar als Ergebnis einer Funktion zurückzugeben (egal ob DLL oder nicht) ist keine gute Idee. Was denkst du, warum es keine Windows-API-Funktion gibt, die so etwas tut? Funktionen, die einen String ermitteln, bekommen normalerweise zwei Parameter: einen PChar von der aufrufenden Funktion und dessen Größe (siehe z.B. MSDN-Library durchsuchenGetWindowsDirectory).

Selbst wenn du eine globale Stringvariable für den Rückgabewert benutzt, so hättest du immer noch das Problem, dass das Ergebnis nur so lange Gültigkeit besitzt, wie du diese Variable nicht änderst. Und ob der Aufrufer ein korrektes Ergebnis erhält hängt einfach nur davon ab, ob der Speicher in der Zwischenzeit schon überschrieben wurde oder nicht (worauf du normalerweise keinen Einfluss hast).

Die einzige wirklich funktionierende Lösung wäre ein festes char-Array:
Delphi-Quellcode:
// Globale Variable mit gleichbleibender Adresse
var
  ReturnValue: array [0 .. 255] of char;

function GetCurrentSkinFile : PChar;
var
  SkinDir : String;
  SkinName : String;
  stemp:String;
begin
  SkinDir := GetSkinDirectory;
  SkinName := GetSkinName;
  stemp := SkinDir +
           IncludeTrailingBackslash(SkinName) +
           'Skin.xml';
  StrCopy(@ReturnValue[0], PChar(stemp));
  result := @ReturnValue[0];
end;
Volker
Besucht meine Garage
Aktuell: RtfLabel 1.3d, PrintToFile 1.4
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:29 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz