開發中常常須要動態調用一些導出函數,試着利用C++11特性封裝一下windows
常規使用緩存
typedef int WINAPI (*TMessageBoxA)(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType); if (HMODULE m = LoadLibraryA("user32")) { if (FARPROC proc = GetProcAddress(m,"MessageBoxA")) { TMessageBoxA msgBox = reinterpret_cast<TMessageBoxA>(fn); msgBox(0,0,0,0); // call it ... } FreeLibrary(m); }
流程很清晰,只是寫多了看着不爽 ;-)
曾經利用 decltype function bind 實現過另個版本,此次嘗試更純粹一些函數
參考std::function實現方式,僅使用"Variadic Templates"code
#include <windows.h> template<typename _T> class Api; template<typename _Res, typename... _ArgTypes> class Api<_Res(_ArgTypes...)> { public: Api(const char* dllName, const char* funcName) { _M_module = LoadLibraryA(dllName); _M_func = reinterpret_cast<_Func>(GetProcAddress(_M_module, funcName)); } ~Api() { if (_M_module) FreeLibrary(_M_module); } _Res operator()(_ArgTypes... __args) const { return _M_func(__args...); } private: typedef _Res (*_Func)(_ArgTypes...); _Func _M_func; HMODULE _M_module; }; int main() { Api<int(HWND,LPCTSTR,LPCTSTR,UINT)> msgbox("user32", "MessageBoxA"); msgbox(0,0,0,0); }
注意,爲了最小利用特性,這裏沒有利用final、delete進行使用限制,也沒有對HMODULE進行緩存管理,生產環境請自行抉擇。
有更好的方式,請留言交流;-)開發
仍是附上另外一種更經常使用的方法string
#include <map> #include <string> #include <functional> #include <windows.h> class WinDll { public: WinDll(const char* dll) { mMoudle = LoadLibraryA(dll); } WinDll(const wchar_t* dll) { mMoudle = LoadLibraryW(dll); } ~WinDll() { if (mMoudle) FreeLibrary(mMoudle); } FARPROC RawApi(const std::string& fn) { auto it = mFuncCaches.find(fn); if (it == mFuncCaches.end()) { FARPROC func = GetProcAddress(mMoudle, fn.c_str()); if (!func) throw "not found!"; mFuncCaches[fn] = func; return func; } return it->second; } template<typename _T> std::function<_T> ApiFunc(const std::string& fn) { return std::function<_T>(reinterpret_cast<_T*>(RawApi(fn))); } private: HMODULE mMoudle; std::map<std::string,FARPROC> mFuncCaches; }; int main() { WinDll user32("user32"); using TMessageBoxA = int(HWND,LPCTSTR,LPCTSTR,UINT); auto msgBox = user32.ApiFunc<TMessageBoxA>("MessageBoxA"); msgBox(0,0,0,0); }