动态调用DLL技术很常见也没有什么特别困难的,但是我总是感觉写起来很烦,要用typedef定义,加载DLL、查找地址,很烦人,所以我找了一个方式,把DLL动态调用的逻辑都封装成了一个类,使用起来就简单多了。
直接动态调用的方法,示例如下:
1、预定义
typedef LinphoneCore* (*funlinphone_core_new)(const LinphoneCoreVTable *vtable,const char *config_path, const char *factory_config, void* userdata);
2、定义函数指针变量 funlinphone_core_new pfn_core_new ;
3、动态加载函数 handle = LoadLibrary( "liblinphone-4.dll"); pfn_core_new = (funlinphone_core_new)GetProcAddress( handle,"linphone_core_new");
4、调用
pfn_core_new(....);
|
这样调用就完成了,还得负责清理(函数指针指向NULL,卸载DLL等工作)。
使用类封装,先要使用下面一个类(添加到工程即可)
/**************************************************************************** * DEFINE_PROC * Inputs: * result: The result type; if a linkage type such as WINAPI, CALLBACK, * etc. is required, use DEFINE_PROC_LINKAGE * name: The function name * args: The argument list, enclosed in parentheses * Notes: * There are as many of these as required for your methods to be called ****************************************************************************/ #define DEFINE_PROC(result, name, args) \ protected: \ typedef result (*name##_PROC) args; \ public: \ name##_PROC name; /**************************************************************************** * DEFINE_PROC_LINKAGE * Inputs: * result: Result type * linkage: Linkage type, e.g., CALLBACK, WINAPI * name: Function name * args: Argument list enclosed in ( )s * Notes: * There are as many of these as required for your methods to be called ****************************************************************************/ #define DEFINE_PROC_LINKAGE(result, linkage, name, args) \ protected: \ typedef result (linkage * name##_PROC) args; \ public: \ name##_PROC name; /**************************************************************************** * IMPLEMENT_PROC * Inputs: * name: The name of the function, as used as the second argument of * DEFINE_PROC. * Notes: * This must appear between a BEGIN_PROC_TABLE and END_PROC_TABLE ****************************************************************************/ #define IMPLEMENT_PROC(name) \ IMPLEMENT_PROC_SPECIAL(name, #name) /**************************************************************************** * IMPLEMENT_PROC_SPECIAL * Inputs: * name: The name as defined by IMPLEMENT_PROC or IMPLEMENT_PROC_LINKAGE * externalname: The external name * Notes: * This must appear between a BEGIN_PROC_TABLE and END_PROC_TABLE ****************************************************************************/ #define IMPLEMENT_PROC_SPECIAL(name, externalname) \ name = loading ? (name##_PROC)GetProcAddress(library, externalname) : NULL; \ { \ DWORD err = ::GetLastError(); \ if(loading) \ ASSERT(name != NULL); \ if(loading && name == NULL) \ { \ ::SetLastError(err); \ } \ } /**************************************************************************** * BEGIN_PROC_TABLE * END_PROC_TABLE * Effect: * This declares the method that initializes the method pointers. * There can be only one BEGIN_PROC_TABLE declaration per class. * Following this are some number of IMPLEMENT_PROC lines, * followed by END_PROC_TABLE ****************************************************************************/ #define BEGIN_PROC_TABLE() protected: virtual BOOL Define(BOOL loading) { ::SetLastError(ERROR_SUCCESS); #define END_PROC_TABLE() return TRUE; } /**************************************************************************** * DECLARE_PROC_DLL * Inputs: * myclass: The name of your subclass. This must be the same as * the class name you used to declare the class * superclass: This allows you to derive additional subclasses; * normally you will use the DynamicDLL class here * Effect: * Defines the constructors and destructors for the subclass ****************************************************************************/ #define DECLARE_PROC_DLL(myclass, superclass) \ public: \ myclass() : superclass() {} \ myclass(LPCTSTR module) : superclass(module) { Load(module); } \ virtual ~myclass() { Free(); } /**************************************************************************** * DynamicDLL * This is the abstract superclass on which all other classes are based * It defines the basic behavior of the class. ****************************************************************************/ class DynamicDLL { public: DynamicDLL() { Init(); } DynamicDLL(LPCTSTR name) { Init(); } virtual ~DynamicDLL() { } BOOL Load(LPCTSTR name) { ::SetLastError(ERROR_SUCCESS); ASSERT(library == NULL); // Attempt to load twice? if(library != NULL) { /* already loaded */ //::SetLastError(ERROR_INVALID_HANDLE); return FALSE; } /* already loaded */ library = ::LoadLibrary(name); if(library != NULL) return Define(TRUE); Free(); return FALSE; } void Free() {if(library != NULL) ::FreeLibrary(library); library = NULL; Define(FALSE); } BOOL IsLoaded() { return library != NULL; } protected: void Init( ) { library = NULL; } HINSTANCE library; virtual BOOL Define(BOOL loading) { ASSERT(FALSE); return FALSE; } // must define in subclass // Did you forget to do a BEGIN_PROC_TABLE? }; /**************************************************************************** * Example ****************************************************************************/ //class TestDynDLL: public DynamicDLL { // DECLARE_PROC_DLL(TestDynDLL, DynamicDLL) // // DEFINE_PROC(LRESULT, Test, (LPCTSTR, int)) // DEFINE_PROC_LINKAGE(BOOL, WINAPI, Test2, ( ) ) // // BEGIN_PROC_TABLE() // IMPLEMENT_PROC(Test) // IMPLEMENT_PROC_SPECIAL(Test2, "_Test2@0") // END_PROC_TABLE() // //}; |
有了这个类,就可以作为封装DLL调用的基础。
示例如下,例如调用windows中,user32.dll中的函数MessageBoxA,步骤如下:
首先,建立一个新的类,继承DynamicDLL类,在其中,声明所需使用的函数:
#include "DynamicDLL.h" class TestDynDLL: public DynamicDLL { DECLARE_PROC_DLL(TestDynDLL, DynamicDLL) DEFINE_PROC_LINKAGE(int, WINAPI, MessageBoxA, ( HWND,LPCSTR,LPCSTR,UINT) ) BEGIN_PROC_TABLE() IMPLEMENT_PROC(MessageBoxA) END_PROC_TABLE() }; |
在需要调用的地方,调用上面这个类:
TestDynDLL * DLL; DLL = new TestDynDLL(_T("user32.dll")); ASSERT(DLL->IsLoaded()); int rr = DLL->MessageBoxA(this->GetSafeHwnd(),(LPCSTR)"22",(LPCSTR)"dsasdsa",MB_OK); delete DLL; |
怎么样,是不是感觉好用多了?我没有在Linux下面测,估计稍加改动,Linux也能使用这种机制。
需要注意的是,在继承类中的这个声明,需要仔细写,函数名、参数、返回值、调用约定都需要保持一致,否则会出错的哦。