Einzelnen Beitrag anzeigen

jbg

Registriert seit: 12. Jun 2002
3.483 Beiträge
 
Delphi 10.1 Berlin Professional
 
#18

Re: Frage zum Aufbau eines Strings

  Alt 16. Jan 2005, 17:16
Zitat von Muetze1:
@SirThornberry: Die Einschränkung mit String und DLL gilt nur für AnsiString, da diese mit internen Referenzen arbeiten - im Gegensatz dazu hat man mit WideStrings oder ShortStrings keine Probleme (keine Referenzen).
Diese Erklärung ist falsch. Es liegt nicht am Referenzzähler, sondern daran, dass man bei AnsiStrings "nicht mitbekommt", wenn man Speicher reserviert oder freigibt. Da Delphi einen eigenen Speichermanager mitbringt, der von Windows größere Speicherblöcke anfordert und diese dann in kleineren Blöcken an die Anwendung gibt, braucht der Delphi-Speichermanager eine Liste mit den Blöcken. Hat man nun eine zusätzliche DLL, enthält diese eine eigene Kopie des Delphi-Speichermanagers die ihre eigene Block-Liste besitzt.
Übergibt man nun einen AnsiString an eine DLL und diese verändert diesen, passiert es, dass der AnsiString an den DLL-Speichermanager zum Freigeben übergeben wird, der mit dem Speicherbereich aber gar nichts anfangen kann, weil der AnsiString ja im EXE-Speichermanager reserviert wurde. In diesem Moment kracht es dann.
Bei WideStrings läuft das ganze anders ab. Da WideString hauptsächlich wegen COM eingeführt wurden und auch nicht-Delphi-Anwendungen COM-Server und Clients sein können, war Borland gezwungen, den von Microsoft vorgegebenen WideString-Speichermanager zu benutzen. Deswegen wird bei WideString nicht AllocMem/FreeMem sondern Windows.SysAllocStringLen/SysFreeString aufgerufen.
Bei ShortStrings liegt die Sache ganz anders. ShortStrings werden nicht dynamisch reserviert, sondern werden einfach im Datensegment oder auf dem Stack erzeugt. Beim Stack wird ein "SUB ESP,256" für einen lokale Variable "s: ShortString" durchgeführt. Und dieser Speicher muss auch nicht realloziert werden, weil die 255 Zeichen Maximum sind, weswegen der EXE und DLL-Speichermanager sich nicht in die Quere kommen.
Also alles was mit AllocMem/GetMem/FreeMem arbeitet (dazu gehören AnsiString, dyn. Array, Klassen, New, Dispose, ...) können nur ohne Probleme an eine DLL übergeben werden, wenn diese nur ohne Reallozierung (ReallocMem) oder Freigeben und neu Reservieren zugreift. Bei AnsiStrings ist es aber sehr wahrscheinlich, dass man den String Realloziert ohne das man das direkt im Code geschrieben hat. Wenn man also die Compiler-Magic für AnsiStrings nicht auswendig kennt, sollte man bei AnsiString sehr vorsichtig sein.

Und nun warum das ganze kein Problem bei Packages ist, die ja auch "nur" DLLs sind. Bei Packages hat Borland das DLL-Format dahingehend erweitert, als dass der Compiler alle öffentlichen Funktionen, Methoden und einige spezielle, nur für den Compiler/RTL wichtige Funktionen exportiert. In diesen Compiler-Magic-Funktionen stecken dann so informationen wie welche Unit im Package enthalten sind, ... Diese Informationen erlauben es der RTL nun zu verhindern, dass die BPL einen eigenen Speichermanager bekommt. Somit benutzen die EXE und die BPL ein und denselben Speichermanager, und können somit AllocMem und FreeMem in beiden Modulen ungehindert aufrufen, weil beide auf dieselble Block-List zugreifen.
Die BorlandMM.dll macht nun nichts anderes, als dass sie in der EXE und in der DLL mittels der Unit ShareMem, die per SetMemoryManager den Speichermanager der EXE und der DLL auf die BorlandMM.dll setzt, den gleichen Speichermanager für beide Module anbietet und somit AllocMem und FreeMem in beiden Modulen aufgerufen werden können.
  Mit Zitat antworten Zitat