DynamicLinkLibraryAPI.h
尝试使用,动态链接库技术,来实现脚本刷新。
#pragma once #if defined(WIN32) || defined(WIN64) #include <Windows.h> typedef HINSTANCE DLLHANDLER; #elif defined(__linux__) #include <dlfcn.h> typedef void* DLLHANDLER; #endif namespace dll { // 打开动态链接库。 bool OpenDLL(DLLHANDLER* pDLLHander, const char* path #if defined(__linux__) , int mode = RTLD_NOW #endif ); // 通过名称获得动态链接库中的函数或变量地址。 void* GetDLL(DLLHANDLER* pDLLHander, const char* name); // 关闭动态链接库 bool CloseDLL(DLLHANDLER* pDLLHander); }
DynamicLinkLibraryAPI.cpp
#include "DynamicLinkLibraryAPI.h" #include <stdio.h> namespace dll { bool OpenDLL(DLLHANDLER* pDLLHander, const char* path #if defined(__linux__) , int mode #endif ) { if (!pDLLHander || !path) { #ifndef NDEBUG printf("\n=====================================================\n"); printf("\tDEBUG:\n%s[%d]%s\t", __FILE__, __LINE__, "openDLL fial: null args"); printf("\n=====================================================\n"); #endif return false; } #if defined(WIN32) || defined(WIN64) *pDLLHander = LoadLibrary(path); #elif defined(__linux__) *pDLLHander = dlopen(path, mode); #endif #ifndef NDEBUG #if defined(WIN32) || defined(WIN64) printf("\n=====================================================\n"); printf("\tDEBUG:\n%s[%d]path=[%s]\t", __FILE__, __LINE__, path); printf("\n=====================================================\n"); #elif defined(__linux__) printf("\n=====================================================\n"); printf("\tDEBUG:\n%s[%d]path=[%s] mode=[%d]\t", __FILE__, __LINE__, path, mode); printf("\n=====================================================\n"); #endif #endif return pDLLHander != nullptr; } void* GetDLL(DLLHANDLER* pDLLHander, const char* name) { if (!pDLLHander || !name) { #ifndef NDEBUG printf("\n=====================================================\n"); printf("\tDEBUG:\n%s[%d]%s\t", __FILE__, __LINE__, "getDLL fial: null args"); printf("\n=====================================================\n"); #endif return nullptr; } #if defined(WIN32) || defined(WIN64) return GetProcAddress(*pDLLHander, name); #elif defined(__linux__) return dlsym(*pDLLHander, name); #endif } bool CloseDLL(DLLHANDLER* pDLLHander) { bool flag = false; if (pDLLHander) { #if defined(WIN32) || defined(WIN64) flag = FreeLibrary(*pDLLHander); #elif defined(__linux__) flag = (dlclose(*pDLLHander) == 0); #endif } #ifndef NDEBUG if (flag) { printf("\n=====================================================\n"); printf("\tDEBUG:\n%s[%d] %s\t", __FILE__, __LINE__, "closeDLL succ"); printf("\n=====================================================\n"); } else { printf("\n=====================================================\n"); printf("\tDEBUG:\n%s[%d] %s\t", __FILE__, __LINE__, "closeDLL fail"); printf("\n=====================================================\n"); } #endif return flag; } }
#pragma once #include "DynamicLinkLibraryAPI.h" #include <ostream> #include <set> #include <map> #include <ctime> #include <string.h> #include <iostream> // 创建已知类型的脚本函数类,及对象。 #define SCRIPTCLASS(NAME, DEFFUN) \ class C##NAME { \ protected: \ typedef DEFFUN; \ \ static C##NAME* m_Instance; \ \ C##NAME() { \ m_pScripts = new std::set<DEF>; \ } \ public: \ \ bool operator==(const C##NAME& ref) { \ return m_Version == ref.m_Version; \ } \ \ static C##NAME* Instance() { \ if (!m_Instance) { \ m_Instance = new C##NAME; \ } \ return m_Instance; \ } \ \ const double GetVersion() const { \ return m_Version; \ } \ \ void SetVersion(double version) { \ m_Version = version; \ } \ \ const time_t GerCtime() const { \ return m_Ctime; \ } \ \ bool Reg(DLLHANDLER* dllHandler, const char* name) { \ void* p = dll::GetDLL(dllHandler, name); \ if (!p) { \ std::cout << "can not find " << name << " dll fun" << std::endl; \ return false; \ } \ if (p) { \ m_pScripts->insert((DEF)p); \ } \ return true; \ } \ \ std::set<DEF>* GetScripts() { \ return this->m_pScripts; \ } \ \ void Clear() { \ this->m_pScripts->clear(); \ } \ private: \ double m_Version; \ time_t m_Ctime; \ std::set<DEF>* m_pScripts; \ }; \ C##NAME* C##NAME::m_Instance = nullptr; \ // 动态函数 class CDynamicLinkFun { // 类中声明 friend std::ostream& operator<<(std::ostream& os, const CDynamicLinkFun& ref); public: CDynamicLinkFun(const char* name, const char* tname, void* fun) ; private: char m_Name[64]; char m_Tname[128]; void* m_Fun; time_t m_Ctime; }; class CDynamicLinkLibrary { public: CDynamicLinkLibrary(const char* name, const char* path) ; ~CDynamicLinkLibrary() ; // 获得动态库地址 const char* GetPath() const ; // 设置动态库地址 void SetPath(const char* path) ; // 初始化 bool Init() ; // 销毁 bool Destory() ; // 重新加载 bool Reload() ; private: // 库名称 char m_Name[64]; // 库地址 char m_Path[128]; // 加载时间 time_t m_Ctime; // 该动态库中的所有函数 std::map<const char*, CDynamicLinkFun*> m_Scripts; // 动态链接库描述 DLLHANDLER* m_pDLLHander; // 状态:0为默认,1为已初始化 int m_State; }; class CDynamicLinkLibraryMgr { public: // 重新加载所有 int reloadDLLs(); };
DynamicLinkLibraryMgr.cpp
#include "DynamicLinkLibraryMgr.h" // 类外定义 std::ostream& operator<<(std::ostream& os, const CDynamicLinkFun& ref) { os << " Name:" << ref.m_Name << " TName:" << ref.m_Tname << " Address:" << std::showpoint << ref.m_Fun; return os; } CDynamicLinkFun::CDynamicLinkFun(const char* name, const char* tname, void* fun) { strcpy(m_Name, name); strcpy(m_Tname, tname); m_Fun = fun; time(&m_Ctime); } CDynamicLinkLibrary::CDynamicLinkLibrary(const char* name, const char* path) { m_State = 0; m_pDLLHander = new DLLHANDLER; strcpy(m_Name, name); strcpy(m_Path, path); time(&m_Ctime); } CDynamicLinkLibrary::~CDynamicLinkLibrary() { Destory(); m_pDLLHander = nullptr; } const char* CDynamicLinkLibrary::GetPath() const { return this->m_Path; } void CDynamicLinkLibrary::SetPath(const char* path) { strcpy(m_Path, path); } bool CDynamicLinkLibrary::Init() { if (m_State) { #ifndef NDEBUG printf("\n=====================================================\n"); printf("\tDEBUG:\n%s[%d] %s\t", __FILE__, __LINE__, "动态链接库已初始化,无法再初始化!"); printf("\n=====================================================\n"); #endif return false; } if (dll::OpenDLL(m_pDLLHander, m_Path)) { m_State = 1; // void GetScripts(std::map<const char*, const char*>& scripts) void (*GetScripts)(std::map<const char*, const char*>& scripts) = reinterpret_cast<void (*) (std::map<const char*, const char*>& scripts)>(dll::GetDLL(m_pDLLHander, "GetScripts")); if (!GetScripts) { return false; } std::map<const char*, const char*> __map; GetScripts(__map); for (auto kv : __map) { std::cout << kv.first << " " << kv.second << std::endl; #ifndef NDEBUG bool flag = true; #endif if (strlen(kv.first) > 0 && strlen(kv.second) > 0) { void* fun = dll::GetDLL(m_pDLLHander, kv.first); if (fun) { m_Scripts.insert(std::make_pair(kv.first, new CDynamicLinkFun(kv.first, kv.second, fun))); #ifndef NDEBUG flag = false; #endif } } #ifndef NDEBUG if (flag) { printf("\n=====================================================\n"); printf("\tDEBUG:\n%s[%d]%s %s %s\t", __FILE__, __LINE__, "load function fail", kv.first, kv.second); printf("\n=====================================================\n"); } #endif } std::cout << "\n---------------------------" << std::endl; #ifndef NDEBUG for (auto kv : m_Scripts) { std::cout << *(kv.second) << std::endl; } #endif return true; } return false; } bool CDynamicLinkLibrary::Destory() { if (!m_State) { #ifndef NDEBUG printf("\n=====================================================\n"); printf("\tDEBUG:\n%s[%d] %s\t", __FILE__, __LINE__, "动态链接库尚未初始化,无法销毁!"); printf("\n=====================================================\n"); #endif return false; } bool rt = dll::CloseDLL(m_pDLLHander); if (rt) { m_State = 0; } for (auto kv : m_Scripts) { kv.second = nullptr; } m_Scripts.clear(); return rt; } bool CDynamicLinkLibrary::Reload() { Destory(); return Init(); }
#include "DynamicLinkLibraryMgr.h" #include <iostream> #include <thread> #include <fstream> #include <string> #include <string.h> #if defined(WIN32) || defined(WIN64) #define path "../Debug/SayHello.dll" #elif defined(__linux__) #define path "../Debug/SayHello.so" #endif bool bReload = true; char path2[126] = {0}; int test(DLLHANDLER* pHandler); int reload(DLLHANDLER* pHandler); // SCRIPTCLASS(LoginPreScript, void (*DEF) (void*) ) int main(int argc, char **argv) { CDynamicLinkLibrary* pDynamicLinkLibrary = nullptr; if (argc == 2) { strcpy(path2, argv[1]); std::cout << "path2 " << path2 << std::endl; pDynamicLinkLibrary = new CDynamicLinkLibrary("test" ,path2); } else { pDynamicLinkLibrary = new CDynamicLinkLibrary("test", path); } pDynamicLinkLibrary->Init(); return 0; } // // int main(int argc, char **argv) { // // if (argc == 2) { // strcpy(path2, argv[1]); // std::cout << "path2 " << path2 << std::endl; // } // // DLLHANDLER* pHandler = new DLLHANDLER; // std::thread t( // [&pHandler](){ // // for (;;) { // test(pHandler); // } // } // ); // t.detach(); // // for (;;) { // // std::string str; // std::getline(std::cin, str); // strcpy(path2, str.c_str()); // std::cout << "path2 " << path2 << std::endl; // reload(pHandler); // // // } // // return 0; // } // // int reload(DLLHANDLER* pHandler) { // bReload = true; // return dll::CloseDLL(pHandler); // } // // int test(DLLHANDLER* pHandler) { // // std::cout << "bReload :: " << std::boolalpha << bReload << std::endl; // std::cout << "path2 :: " << path2 << std::endl; // if (bReload) { // bReload = false; // // bool ret = false; // if (strlen(path2) > 0) { // ret = dll::OpenDLL(pHandler, path2); // } else { // ret = dll::OpenDLL(pHandler, path); // } // // if (!ret) { // std::cout << "can not open dll" << std::endl; // return -1; // } // // CLoginPreScript::Instance()->Clear(); // CLoginPreScript::Instance()->Reg(pHandler, "loginPre1"); // CLoginPreScript::Instance()->Reg(pHandler, "loginPre2"); // // } // // auto scripts = CLoginPreScript::Instance()->GetScripts(); // for (auto loginpre = scripts->begin(); loginpre != scripts->end(); loginpre++) { // (*loginpre)(nullptr); // } // // // // bool ret = dll::closeDLL(pHandler); // // if (ret) { // // std::cout << "关闭成功" << std::endl; // // } else { // // std::cout << "关闭失败" << std::endl; // // } // // // // ret = dll::openDLL(pHandler, path); // // if (!ret) { // // std::cout << "打开动态链接库失败" << std::endl; // // return -1; // // } // // // // // // // // void* p = dll::getDLL(pHandler, "add"); // // if (!p) { // // std::cout << "can not get dll method" << std::endl; // // return -2; // // } // // // // int (*addFun)(int, int) = (int(*)(int, int))p; // // int sum = addFun(1, 8); // // // // std::cout << "sum = " << sum << std::endl; // // // // // // void* p2 = dll::getDLL(pHandler, "add2"); // // if (!p2) { // // std::cout << "can not get dll method" << std::endl; // // return -3; // // } // // // // int (*add2Fun)(int, int, int) = (int(*)(int, int, int))p2; // // int sum2 = add2Fun(1, 8, 10); // // // // std::cout << "sum2 = " << sum2 << std::endl; // // // // // // void* p3 = dll::getDLL(pHandler, "sayHello"); // // if (!p3) { // // std::cout << "can not get dll method" << std::endl; // // return -4; // // } // // void (*sayHelloFun)() = (void(*)()) p3; // // // // sayHelloFun(); // // // // void* (*getUser)() = (void* (*)()) dll::getDLL(pHandler, "getUser"); // // // // void* pU = getUser(); // // // // void (*printUser)(void*) = (void (*)(void*)) dll::getDLL(pHandler, "printUser"); // // // // printUser(pU); // // // // #if defined(WIN32) || defined(WIN64) // // #elif defined(__linux__) // // char** name = (char**) dll::getDLL(pHandler, "name"); // // int* age = (int*) dll::getDLL(pHandler, "age"); // // std::cout << *name << std::endl; // // std::cout << *age << std::endl; // // // // #endif // // std::this_thread::sleep_for(std::chrono::seconds(10)); // // return 1; // // }
以下是动态链接库项目:
DynamicLinkLibraryScript.cpp
#include <map> #ifndef DLL_API #if defined(WIN32) || defined(WIN64) #define DLL_API __declspec(dllexport) #elif defined(__linux__) #define DLL_API #endif #endif extern "C" DLL_API void GetScripts(std::map<const char*, const char*>& scripts) { scripts.insert(std::make_pair("loginPre1", "void (*loginPre1)(void*)")); scripts.insert(std::make_pair("loginPre2", "void (*loginPre2)(void*)")); scripts.insert(std::make_pair("add", "int (*add)(int ,int )")); scripts.insert(std::make_pair("add2", "int (*add2)(int , int , int )")); scripts.insert(std::make_pair("sayHello", "void (*sayHello)()")); scripts.insert(std::make_pair("getUser", "void* (*getUser)()")); scripts.insert(std::make_pair("printUser", "void (*printUser)(void*)")); }
LoginPreScript.cpp
#include <iostream> // void (*LoginPre) (void*) #ifndef DLL_API #if defined(WIN32) || defined(WIN64) #define DLL_API __declspec(dllexport) #elif defined(__linux__) #define DLL_API #endif #endif extern "C" DLL_API void loginPre1(void* p) { std::cout << "loginPre1 yyyyyy" << std::endl; } extern "C" DLL_API void loginPre2(void* p) { std::cout << "loginPre2 xxxxxx" << std::endl; }
Math.h
#pragma once #ifndef DLL_API #if defined(WIN32) || defined(WIN64) #define DLL_API __declspec(dllexport) #elif defined(__linux__) #define DLL_API #endif #endif extern "C" int DLL_API add(int x,int y);
#include "Math.h" int add(int x,int y) { return x + y; }
Math2.cpp
#ifndef DLL_API #if defined(WIN32) || defined(WIN64) #define DLL_API __declspec(dllexport) #elif defined(__linux__) #define DLL_API #endif #endif extern "C" int DLL_API add2(int i, int j, int k) { return i + j + k + 100000; }
SayHello2.cpp
#include <iostream> #include <string.h> #ifndef DLL_API #if defined(WIN32) || defined(WIN64) #define DLL_API __declspec(dllexport) #elif defined(__linux__) #define DLL_API #endif #endif char* name = "jack"; int age = 27; extern "C" DLL_API void sayHello() { std::cout << "hello 3!" << name << age << std::endl; } class User { // 类中声明 friend std::ostream& operator<<(std::ostream& os, const User& ref); public: User(const char* username, const char* password) { strcpy(this->username, username); strcpy(this->password, password); } const char* getUsername() const { return this->username; } const char* getPassword() const { return this->password; } private: char username[64]; char password[64]; }; // 类外定义 std::ostream& operator<<(std::ostream& os, const User& ref) { os << ref.username << " " << ref.password; return os; } User* pU = new User("jack", "pswd"); extern "C" DLL_API User* getUser() { return pU; } extern "C" DLL_API void printUser(User* u) { std::cout << *u << std::endl; }