Un mapper PE minimal qui charge les DLL directement depuis la mémoire et appelle une interface de plugin propre, sans avoir besoin de LoadLibrary.
Un mappeur PE réflexif minimal avec une interface de plugin interchangeable à chaud pour Windows x64. Mappe une DLL directement depuis un tampon d'octets en mémoire, résout ses exports et appelle une ABI IPlugin propre sans toucher à LoadLibrary. Code d'accompagnement pour l'article de blog sur les loaders réflexifs et les architectures de plugins modulaires.
Voir l'article complet : Using Reflective Loaders to Replace LoadLibrary for Hot-Swappable Modules in C++
# Configure
cmake -B build
# Build
cmake --build build --config Release
# The build produces:
# build/Release/cmdplugin.dll (example plugin)
# build/Release/harness.exe (test harness)
# Map cmdplugin.dll from disk, run "dir C:\"
harness.exe cmdplugin.dll "dir C:\"
# Default: loads cmdplugin.dll, runs "whoami"
harness.exe
Le harness lit la DLL dans un tampon d'octets, la mappe avec le loader réflexif, résout les exports du plugin et distribue la commande via l'interface IPlugin.
ReflectivePluginLoader/
├── CMakeLists.txt # Root build
├── Include/
│ ├── IPlugin.h # Plugin ABI (TaskApi, IPlugin, helpers)
│ └── ReflectiveLoaderEngine.h # PE mapper + export resolver
├── Modules/
│ └── CmdPlugin/
│ ├── cmdplugin.cpp # Example: command execution plugin
│ └── CMakeLists.txt
├── Testing/
│ ├── main.cpp # Test harness (loads DLL from file)
│ └── CMakeLists.txt
└── Tools/
└── file2hex.py # Convert a DLL to a C byte array
Modules/.IPlugin.h et implémentez l'interface IPlugin :#include "IPlugin.h"
class MyPlugin : public IPlugin {
public:
void init() const override { /* setup */ }
void execute(TaskApi* task) const override { /* do work */ }
void cleanup() const override { /* teardown */ }
};
Implémentez les cinq fonctions exportées (create_plugin, destroy_plugin, plugin_init, plugin_exec, plugin_cleanup) en utilisant HeapAlloc/placement new pour une allocation inter-modules sûre vis-à-vis du CRT.
Ajoutez un CMakeLists.txt et enregistrez-le dans le CMakeLists.txt racine avec add_subdirectory().
L'hôte n'a pas besoin de savoir ce que fait votre module en interne. Il mappe, résout, appelle init -> execute -> cleanup, puis passe à autre chose.
Le mappeur gère les bases et s'arrête délibérément là :
Si un module a besoin de l'un de ces éléments, étendez le mappeur ou rejetez le module tôt avec une erreur claire. Un demi-support silencieux est le pire mode de défaillance.