Non sono riuscito a comprendere bene il meccanismo che hai descritto, forse perché al suo stato attuale è molto complesso, ma cerco di fare un riassunto sintetico della questione "stringhe in DLL" con cui forse puoi giungere autonomamente alla risposta.
Delphi gestisce automaticamente le stringhe, così come avviene con un'altra ristretta cerchia di tipi di dati (Variant, ad esempio).
Gestire automaticamente significa che la rappresentazione binaria della stringa è "particolare", innanzitutto; in secondo luogo, Delphi opera sulla memoria allocando spazio per le stringhe a seconda dell'uso che se ne fa: ad esempio, se dichiari una stringa e assegni il suo valore ad un'altra, Delphi effettua semplicemente l'assegnazione del puntatore, quindi l'operazione risulta estremamente rapida; non appena tenti di modificare una delle due istanze, Delphi alloca memoria per le modifiche; in sostanza, la memoria viene automaticamente amministrata per allocare lo spazio necessario ad ospitare le stringhe sottoposte a varie operazioni a seconda dell'ambito.
La memoria viene poi revocata quando le stringhe escono dallo "scope" o non sono più raggiungibili.
Tutto questo compito è svolto dal memory manager di Delphi, che opera nel contesto di un'applicazione.
Il problema nasce quando si ha a che fare con DLL, che di fatto rappresentano due istanze di applicazioni (anche se il termine è improprio), cioè due contesti in cui lavorano due memory manager distinti, a meno che non si includa la unit ShareMem, che serve appositamente a delegare il compito di gestione della memoria al "memory manager" condiviso, sfruttando un'apposita DLL esterna ("borlndmm.dll").
Se la tua DLL deve essere usata da altre applicazioni, non puoi affidarti al memory manager condiviso in quanto altri linguaggi e compilatori non hanno alcuna cognizione di esso, che è valido solo in ambiente Delphi.
Non puoi nemmeno utilizzare il tipo string in quanto, oltre ad essere particolare e non standard come formato (appositamente per consentire al MM di scrivere in memoria le informazioni necessarie a gestire dinamicamente le risorse stringa), sono sottoposte come si diceva prima ad una gestione automatica della memoria.
Significa che restituendo un puntatore ad una variabile string, quando la funzione termina, la variabile esce dal suo "scope" e quindi Delphi la dealloca; il programma che invoca la funzione si troverà quindi un puntatore non utilizzabile, anche se si tratta di un'applicazione Delphi, con l'aggiunta di non poter comprendere l'informazione in quanto, se non è Delphi, il puntatore restituisce l'indirizzo ad una struttura di memoria particolare che non può essere direttamente interpretata (a meno che tu non voglia introdurre questa interpretazione nei file sorgenti da distribuire ad altri linguaggi, ma rimarrebbe il problema della gestione della memoria).
Quindi, in conclusione, laddove sia necessario operare con delle stringhe, devi provvedere a creare dei buffer usando le funzioni che hai già sfruttato e che già conosci, copiando all'interno di essi il contenuto delle stringhe, in quanto i buffer sono semplici array di byte che puoi gestire come desideri, senza che Delphi intervenga distruggendoli automaticamente.
Riassumendo, non puoi restituire stringhe come valori di ritorno di funzioni esportate dalla DLL.
Se si tratta di funzioni interne, puoi ovviamente fare uso di stringhe string purché tu provveda a memorizzarle in un buffer prima di ritornare alla routine dell'applicazione che chiama la tua funzione esportata.
In breve, quando il contesto passa dall'ambito della tua DLL all'ambito dell'applicazione che utilizza la tua libreria, qualsiasi valore di tipo stringa non deve essere restituito come string, né puoi restituire puntatori a variabili di questo tipo, ma devi restituire necessariamente un puntatore ad un buffer allocato (che non viene modificato da Delphi), oppure scrivere all'interno di un buffer che l'applicazione chiamante provvede ad allocare precedentemente passandoti il suo indirizzo, assieme alla lunghezza massima del buffer oltre alla quale non puoi scrivere (troncando la stringa); quest'ultima è in genere la via scelta per le funzioni API, ad esempio, in cui si alloca un buffer di dimensioni sufficienti e si passa alle funzioni una struttura (record) contenente il puntatore al buffer da riempire, la sua dimensione attuale e altre informazioni di contorno che possono essere utili per svolgere il compito specifico affidato alla funzione all'interno della DLL.
Magari, sfruttando queste indicazioni, verifica come hai steso la tua applicazione e guarda se i casi da te affrontati ricadono nelle condizioni "pericolose" descritte precedentemente.
Ciao!![]()