Partage de la mémoire entre applications et DLL sous Windows
Sous Windows, une DLL et une application ne partagent pas le même tas (heap), et c’est parfois bien dommage... Lorsque qu’une application passe un pointeur sur un bloc de mémoire, la DLL ne peut pas en changer sa taille ni le libérer, puisque le pointeur a été alloué par l’autre module. Ainsi, lorsqu’une DLL doit retourner un nombre variable de structures de données, il est ainsi d’usage d’allouer un tampon "suffisamment grand" pour en contenir assez.... ce qui n’est pas vraiment optimal en terme de consommation mémoire et franchement corsé quand ce "assez" n’est pas borné.
Une solution est de passer à la DLL un jeu de pointeurs de fonction, qui référencent des procédures exposées dans l’application permettant d’allouer ou de désallouer de la mémoire :
Autrement dit, on définir une structure dont les trois membres sont des pointeurs sur fonction. Ici le “packed” sert à empêcher le compilateur d’introduire des octets d’alignement, permettant la "traduction" de cette structure en C/C++ et son exploitation par des DLL écrites dans ce langage; et le "stdcall" permet l’appel interprocessus sous Win32 (c’est la convention d’appel par défaut des API Windows).
Où est l’astuce ? Lorsque la DLL alloue/libère de la mémoire via le jeu de fonctions, c’est le tas de l’application qui est utilisé dans tous les cas, puisque les fonctions pointées sont exportées depuis celle-ci.
Côté application, il faut implémenter ces fonctions. Par exemple :
...et créer une fonction initialisant les champs de la structure :
On peut créer des fonctions "utilitaires" pour allouer plus facilement de la mémoire à partir de notre structure de données :
C’est fini ! L’application n’a plus qu’à plus appeller GetDefaultMalloc(), passer une structure de type IMalloc à la DLL, qui utilisera SharedGetMem() pour allouer de la mémoire sur un pointeur passé en paramètre. Pour un code orthogonal, l’application appellera SharedFreeMem() sur le pointeur retourné par la DLL une fois les résultats renvoyés.
Côté application (un exemple tiré d’UltraBackup) :
Côté DLL :
Voilà...La même chose a été mis en place avec IMalloc de COM, mais cette solution a l’avantage d’être légère et multiplateforme.