1. 核心原理 要实现“注入并显示”,DLL 必须能把自己挂载到主程序的渲染循环里。在 raylib 中,由于它是顺序执行的,最简单的“注入”方式是:
主程序提供一个入口 (类似一个“插件槽位”)。
2. DLL 端代码: searchbox_dll.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 #include "IPlugin.h" #include <vector> static char inputText[64 ] = { 0 };static int letterCount = 0 ;static bool active = false ;void SearchOnInit () { TraceLog (LOG_INFO, "[SearchBox DLL] Plugin Initialized." ); } void SearchOnTick () { if (IsKeyPressed (KEY_F2)) active = !active; if (!active) return ; int key = GetCharPressed (); while (key > 0 ) { if (key >= 32 && key <= 125 && letterCount < 63 ) { inputText[letterCount++] = (char )key; inputText[letterCount] = '\0' ; } key = GetCharPressed (); } if (IsKeyPressed (KEY_BACKSPACE) && letterCount > 0 ) inputText[--letterCount] = '\0' ; if (IsKeyPressed (KEY_ENTER)) { if (letterCount > 0 ) { TraceLog (LOG_INFO, "[SearchBox] Searching for: %s" , inputText); letterCount = 0 ; inputText[0 ] = '\0' ; active = false ; } } Rectangle box = { GetScreenWidth () / 2.0f - 200 , 20 , 400 , 40 }; DrawRectangleRounded (box, 0.3f , 8 , Fade (BLACK, 0.8f )); DrawRectangleRoundedLines (box, 0.3f , 8 , active ? SKYBLUE : GRAY); DrawText (inputText, (int )box.x + 15 , (int )box.y + 10 , 20 , RAYWHITE); } void SearchOnUnload () { TraceLog (LOG_INFO, "[SearchBox DLL] Plugin Unloaded." ); } extern "C" __declspec(dllexport) PluginInterface* GetPluginAPI () { static PluginInterface api = { {"Global Search" , "1.0" }, SearchOnInit, SearchOnTick, SearchOnUnload }; return &api; }
IPlugin.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #ifndef IPLUGIN_H #define IPLUGIN_H #include "raylib.h" struct PluginInfo { const char * name; const char * version; }; typedef struct { PluginInfo info; void (*OnInit)(); void (*OnTick)(); void (*OnUnload)(); } PluginInterface; typedef PluginInterface* (*GetPluginAPI_Func)();#endif
dllmain.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <windows.h> BOOL APIENTRY DllMain ( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break ; } return TRUE; }
3. 主程序端代码:预留“注入接口” 在主程序渲染中调用dll
main.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include "raylib.h" #include "PluginLoader.h" int main () { InitWindow (800 , 600 , "Clean Plugin System" ); SetTargetFPS (60 ); PluginInstance searchBox ("searchbox.dll" ) ; searchBox.Load (); while (!WindowShouldClose ()) { if (IsKeyPressed (KEY_F5)) searchBox.Reload (); BeginDrawing (); ClearBackground (DARKGRAY); if (searchBox.IsLoaded ()) { DrawCircle (780 , 20 , 10 , GREEN); searchBox.Update (); } else { DrawCircle (780 , 20 , 10 , RED); DrawText ("PLUGIN NOT LOADED!" , 600 , 40 , 10 , RED); } EndDrawing (); } CloseWindow (); return 0 ; }
PluginLoader.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #ifndef PLUGIN_LOADER_H #define PLUGIN_LOADER_H #include "IPlugin.h" #include <string> class PluginInstance {public : explicit PluginInstance (const std::string& path) ; ~PluginInstance (); bool Load () ; void Unload () ; void Reload () ; void Update () ; bool IsLoaded () const ; private : std::string dllPath; void * hModule; PluginInterface* api; }; #endif
PluginLoader.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #include "PluginLoader.h" #define NOGDI #define NOUSER #define WIN32_LEAN_AND_MEAN #include <windows.h> PluginInstance::PluginInstance (const std::string& path) : dllPath (path), hModule (nullptr ), api (nullptr ) { } PluginInstance::~PluginInstance () { Unload (); } bool PluginInstance::Load () { hModule = (void *)LoadLibraryA (dllPath.c_str ()); if (!hModule) { DWORD error = GetLastError (); TraceLog (LOG_ERROR, "[Loader] LoadLibraryA failed. Error Code: %lu. Path: %s" , error, dllPath.c_str ()); return false ; } auto GetAPI = (GetPluginAPI_Func)GetProcAddress ((HMODULE)hModule, "GetPluginAPI" ); if (!GetAPI) { TraceLog (LOG_ERROR, "[Loader] GetProcAddress failed. Could not find 'GetPluginAPI' in %s" , dllPath.c_str ()); Unload (); return false ; } api = GetAPI (); if (api && api->OnInit) { api->OnInit (); TraceLog (LOG_INFO, "[Loader] Plugin %s loaded and initialized." , dllPath.c_str ()); } return true ; } void PluginInstance::Unload () { if (api && api->OnUnload) api->OnUnload (); if (hModule) { FreeLibrary ((HMODULE)hModule); hModule = nullptr ; } api = nullptr ; } void PluginInstance::Reload () { Unload (); Load (); } void PluginInstance::Update () { if (api && api->OnTick) api->OnTick (); } bool PluginInstance::IsLoaded () const { return (hModule != nullptr && api != nullptr ); }
IPlugin.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #ifndef IPLUGIN_H #define IPLUGIN_H #include "raylib.h" struct PluginInfo { const char * name; const char * version; }; typedef struct { PluginInfo info; void (*OnInit)(); void (*OnTick)(); void (*OnUnload)(); } PluginInterface; typedef PluginInterface* (*GetPluginAPI_Func)();#endif