开发中常常须要动态调用一些导出函数,试着利用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); }