
Un mapper PE minimale che carica le DLL direttamente dalla memoria e richiama un'interfaccia plugin pulita, senza bisogno di LoadLibrary.
Un mapper PE riflessivo minimale con un'interfaccia plugin hot-swappable per Windows x64. Mappa una DLL direttamente da un buffer di byte in memoria, ne risolve le esportazioni e chiama un'ABI IPlugin pulita senza toccare LoadLibrary. Codice di accompagnamento per il post del blog sui loader riflessivi e le architetture plugin modulari.
Vedi l'articolo completo: 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
L'harness legge la DLL in un buffer di byte, la mappa con il loader riflessivo, risolve le esportazioni del plugin e invia il comando attraverso l'interfaccia 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 e implementa l'interfaccia 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 */ }
};
Implementa le cinque funzioni esportate (create_plugin, destroy_plugin, plugin_init, plugin_exec, plugin_cleanup) usando HeapAlloc/placement new per un'allocazione cross-module sicura per il CRT.
Aggiungi un CMakeLists.txt e registralo nel CMakeLists.txt radice con add_subdirectory().
L'host non ha bisogno di sapere cosa fa internamente il tuo modulo. Mappa, risolve, chiama init -> execute -> cleanup e prosegue.
Il mapper gestisce le funzionalità di base e si ferma deliberatamente lì:
Se un modulo necessita di una di queste funzionalità, estendi il mapper o rifiuta il modulo in anticipo con un errore chiaro. Il supporto parziale silenzioso è la peggiore modalità di fallimento.