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.