Ce qui se passe est fondamentalement ceci. Chaque morceau de code compilé séparément (DLL ou EXE) contient son propre code qui alloue la mémoire du système et la gère, appelée le gestionnaire de mémoire. En termes simples, lorsque ce morceau de code est initialisé, il alloue un gros bloc de mémoire du système. Plus tard, quand GetMem le fait ou alloue des chaînes, des tableaux et cetera, le gestionnaire de mémoire marque les parties de ce gros bloc comme utilisées. Lorsque vous utilisez FreeMem/libérez-les, ils sont marqués comme inutilisés.
Imaginez maintenant que vous avez EXE et DLL, les deux avec leurs propres gestionnaires de mémoire. EXE appelle la procédure DLL, DLL alloue une chaîne (PChar), marquant ainsi une partie de son grand bloc de mémoire tel qu'utilisé. Il renvoie ensuite le pointeur sur l'EXE, qui l'utilise et décide plus tard de libérer. EXE donne le pointeur à son propre gestionnaire de mémoire et demande à le libérer, mais ce n'est même pas du grand bloc de mémoire d'EXE!Le gestionnaire de mémoire d'EXE ne sait pas comment "libérer" la mémoire de quelqu'un d'autre. C'est pourquoi vous devez appeler DllReleaseString(), renvoyant ainsi le pointeur de mémoire empruntée à la DLL et laissant le propre gestionnaire de mémoire interne de DLL le libérer. Maintenant, ce que font les gestionnaires de mémoire partagée, ils se connectent les uns aux autres. Gestionnaire de mémoire dans votre DLL et gestionnaire de mémoire dans votre EXE savent comment se parler, et lorsque vous donnez le pointeur mémoire de DLL au gestionnaire de mémoire d'EXE, il comprend qu'il est de DLL et libère le gestionnaire de mémoire DLL. Bien sûr, cela n'est possible que lorsque les deux gestionnaires de mémoire DLL et EXE sont construits à partir du même code de gestionnaire de mémoire (ou bien ils ne se reconnaîtraient pas!). Si votre gestionnaire de mémoire DLL est un partage, et votre gestionnaire de mémoire EXE est quelque chose d'autre, gestionnaire de mémoire DLL ne sera pas en mesure de "demander" EXE pour libérer de la mémoire, et le gestionnaire de mémoire EXE ne va même pas essayer. Par conséquent, si vous voulez que votre DLL soit universelle, vous ne pouvez pas compter sur les gestionnaires de mémoire qui se parlent. Votre DLL peut être utilisée avec des fichiers EXE ou DLL qui dépendent d'un gestionnaire de mémoire différent, peut-être écrit dans une langue différente. Le partage de gestionnaires de mémoire n'est possible que lorsque vous contrôlez toutes les parties de votre projet et que vous pouvez configurer explicitement un seul et même gestionnaire partout.
+1. J'espérais vraiment que je pourrais retourner PChar mais votre argument semble solide. – Ampere
Vous pouvez appliquer des choses aussi bien que COM le fait. Si vous n'utilisez pas les fonctions COM pour libérer de la mémoire allouée par COM, vous obtenez des erreurs. C'est comme ça que "fait respecter" les choses. Vous pouvez appliquer l'utilisation du code de gestion de la mémoire de votre DLL de la même manière. Il n'y a aucun danger à allouer et renvoyer des pointeurs de votre DLL. Il y a un risque que l'EXE fasse un mauvais usage de la mémoire, mais il y a * toujours * un risque que d'autres codes aient des bogues. Ce n'est pas ton problème. –
Le problème est que les langues qui ne connaissent pas les pointeurs peuvent encore passer des tampons et ces tampons sont automatiquement gérés. IMHO est beaucoup mieux de laisser l'appelant gérer sa mémoire et juste manipuler un tampon déjà alloué, que d'en allouer un et demander à l'appelant de le libérer, surtout si vous ne pouvez pas appliquer vos nouveaux types de données comme le fait COM. Le code peut comporter des bogues, mais certaines techniques sont plus susceptibles d'introduire des bogues que d'autres. –