XBMC是一个相当酷的音频/视频播放器,号称家庭影视中心。
我是希望静态将一些库链接进可执行程序的,这样我用的ArchLinux就不用天天在更新一些东西了
但XBMC试了很多次,编译成功后,总是在运行是段错误。
后面没办法,走读代码发现XBMC使用了一个很巧妙的办法实现动态链接库的载入。
XBMC定义了一个动态链接类DllDynamic,其中定义了Load/UnLoad/IsLoaded/ResolveExports几个接口
然后定义了一堆宏用于新类继承DllDynamic实现指定库的动态载入。
#pragma once /* * Copyright (C) 2005-2012 Team XBMC * http://www.xbmc.org * * This Program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This Program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with XBMC; see the file COPYING. If not, see * <http://www.gnu.org/licenses/>. * */ #include "cores/DllLoader/LibraryLoader.h" #include "utils/StdString.h" #include "DllPaths.h" /////////////////////////////////////////////////////////// // // DECLARE_DLL_WRAPPER // // Declares the constructor of the wrapper class. // This must be followed by one or more // DEFINE_METHODX/DEFINE_METHOD_LINKAGEX and // one BEGIN_METHOD_RESOLVE/END_METHOD_RESOLVE block. // // classname: name of the wrapper class to construct // dllname: file including path of the dll to wrap #define DECLARE_DLL_WRAPPER(classname, dllname) XDECLARE_DLL_WRAPPER(classname,dllname) #define XDECLARE_DLL_WRAPPER(classname, dllname) public: classname () : DllDynamic( dllname ) {} /////////////////////////////////////////////////////////// // // DECLARE_DLL_WRAPPER_TEMPLATE_BEGIN // // Declares the constructor of the wrapper class. // The method SetFile(strDllName) can be used to set the // dll of this wrapper. // This must be followed by one or more // DEFINE_METHODX/DEFINE_METHOD_LINKAGEX and // one BEGIN_METHOD_RESOLVE/END_METHOD_RESOLVE block. // // classname: name of the wrapper class to construct // #define DECLARE_DLL_WRAPPER_TEMPLATE(classname) public: classname () {} /////////////////////////////////////////////////////////// // // LOAD_SYMBOLS // // Tells the dllloader to load Debug symblos when possible #define LOAD_SYMBOLS() protected: virtual bool LoadSymbols() { return true; } /////////////////////////////////////////////////////////// // // DEFINE_GLOBAL // // Defines a global for export from the dll as well as // a function for accessing it (Get_name). // // type: The variables type. // name: Name of the variable. // #define DEFINE_GLOBAL_PTR(type, name) protected: union { type* m_##name; void* m_##name##_ptr; }; public: virtual type* Get_##name (void) { return m_##name; } #define DEFINE_GLOBAL(type, name) protected: union { type* m_##name; void* m_##name##_ptr; }; public: virtual type Get_##name (void) { return *m_##name; } /////////////////////////////////////////////////////////// // // DEFINE_METHOD_LINKAGE // // Defines a function for an export from a dll, if the // calling convention is not __cdecl. // Use DEFINE_METHOD_LINKAGE for each function to be resolved. // // result: Result of the function // linkage: Calling convention of the function // name: Name of the function // args: Arguments of the function, enclosed in parentheses // #define DEFINE_METHOD_LINKAGE_FP(result, linkage, name, args) protected: typedef result (linkage * name##_METHOD) args; public: union { name##_METHOD name; void* name##_ptr; }; #define DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, args2) protected: typedef result (linkage * name##_METHOD) args; union { name##_METHOD m_##name; void* m_##name##_ptr; }; public: virtual result name args { return m_##name args2; } #define DEFINE_METHOD_LINKAGE0(result, linkage, name) DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, () , ()) #define DEFINE_METHOD_LINKAGE1(result, linkage, name, args) DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1)) #define DEFINE_METHOD_LINKAGE2(result, linkage, name, args) DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2)) #define DEFINE_METHOD_LINKAGE3(result, linkage, name, args) DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3)) #define DEFINE_METHOD_LINKAGE4(result, linkage, name, args) DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4)) #define DEFINE_METHOD_LINKAGE5(result, linkage, name, args) DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4, p5)) #define DEFINE_METHOD_LINKAGE6(result, linkage, name, args) DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4, p5, p6)) #define DEFINE_METHOD_LINKAGE7(result, linkage, name, args) DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4, p5, p6, p7)) #define DEFINE_METHOD_LINKAGE8(result, linkage, name, args) DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4, p5, p6, p7, p8)) #define DEFINE_METHOD_LINKAGE9(result, linkage, name, args) DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4, p5, p6, p7, p8, p9)) #define DEFINE_METHOD_LINKAGE10(result, linkage, name, args) DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)) #define DEFINE_METHOD_LINKAGE11(result, linkage, name, args) DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)) /////////////////////////////////////////////////////////// // // DEFINE_METHOD_FP // // Defines a function for an export from a dll as a fuction pointer. // Use DEFINE_METHOD_FP for each function to be resolved. Functions // defined like this are not listed by IntelliSence. // // result: Result of the function // name: Name of the function // args: Arguments of the function, enclosed in parentheses // The parameter names can be anything // #define DEFINE_METHOD_FP(result, name, args) DEFINE_METHOD_LINKAGE_FP(result, __cdecl, name, args) /////////////////////////////////////////////////////////// // // DEFINE_METHODX // // Defines a function for an export from a dll. // Use DEFINE_METHODX for each function to be resolved. // where X is the number of parameter the function has. // // result: Result of the function // name: Name of the function // args: Arguments of the function, enclosed in parentheses // The parameter names have to be renamed to px, where // x is the number of the parameter // #define DEFINE_METHOD0(result, name) DEFINE_METHOD_LINKAGE0(result, __cdecl, name) #define DEFINE_METHOD1(result, name, args) DEFINE_METHOD_LINKAGE1(result, __cdecl, name, args) #define DEFINE_METHOD2(result, name, args) DEFINE_METHOD_LINKAGE2(result, __cdecl, name, args) #define DEFINE_METHOD3(result, name, args) DEFINE_METHOD_LINKAGE3(result, __cdecl, name, args) #define DEFINE_METHOD4(result, name, args) DEFINE_METHOD_LINKAGE4(result, __cdecl, name, args) #define DEFINE_METHOD5(result, name, args) DEFINE_METHOD_LINKAGE5(result, __cdecl, name, args) #define DEFINE_METHOD6(result, name, args) DEFINE_METHOD_LINKAGE6(result, __cdecl, name, args) #define DEFINE_METHOD7(result, name, args) DEFINE_METHOD_LINKAGE7(result, __cdecl, name, args) #define DEFINE_METHOD8(result, name, args) DEFINE_METHOD_LINKAGE8(result, __cdecl, name, args) #define DEFINE_METHOD9(result, name, args) DEFINE_METHOD_LINKAGE9(result, __cdecl, name, args) #define DEFINE_METHOD10(result, name, args) DEFINE_METHOD_LINKAGE10(result, __cdecl, name, args) #define DEFINE_METHOD11(result, name, args) DEFINE_METHOD_LINKAGE11(result, __cdecl, name, args) #ifdef _MSC_VER /////////////////////////////////////////////////////////// // // DEFINE_FUNC_ALIGNED 0-X // // Defines a function for an export from a dll, wich // require a aligned stack on function call // Use DEFINE_FUNC_ALIGNED for each function to be resolved. // // result: Result of the function // linkage: Calling convention of the function // name: Name of the function // args: Argument types of the function // // Actual function call will expand to something like this // this will align the stack (esp) at the point of function // entry as required by gcc compiled dlls, it is abit abfuscated // to allow for different sized variables // // int64_t test(int64_t p1, char p2, char p3) // { // int o,s = ((sizeof(p1)+3)&~3)+((sizeof(p2)+3)&~3)+((sizeof(p3)+3)&~3); // __asm mov [o],esp; // __asm sub esp, [s]; // __asm and esp, ~15; // __asm add esp, [s] // m_test(p1, p2, p3); //return value will still be correct aslong as we don't mess with it // __asm mov esp,[o]; // }; #define ALS(a) ((sizeof(a)+3)&~3) #define DEFINE_FUNC_PART1(result, linkage, name, args) private: typedef result (linkage * name##_type)##args; union { name##_type m_##name; void* m_##name##_ptr; }; public: virtual result name##args #define DEFINE_FUNC_PART2(size) { int o,s = size; __asm { __asm mov [o], esp __asm sub esp, [s] __asm and esp, ~15 __asm add esp, [s] } #define DEFINE_FUNC_PART3(name,args) m_##name##args; __asm { __asm mov esp,[o] } } #define DEFINE_FUNC_ALIGNED0(result, linkage, name) DEFINE_FUNC_PART1(result, linkage, name, ()) DEFINE_FUNC_PART2(0) DEFINE_FUNC_PART3(name,()) #define DEFINE_FUNC_ALIGNED1(result, linkage, name, t1) DEFINE_FUNC_PART1(result, linkage, name, (t1 p1)) DEFINE_FUNC_PART2(ALS(p1)) DEFINE_FUNC_PART3(name,(p1)) #define DEFINE_FUNC_ALIGNED2(result, linkage, name, t1, t2) DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2)) DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)) DEFINE_FUNC_PART3(name,(p1, p2)) #define DEFINE_FUNC_ALIGNED3(result, linkage, name, t1, t2, t3) DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2, t3 p3)) DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)+ALS(p3)) DEFINE_FUNC_PART3(name,(p1, p2, p3)) #define DEFINE_FUNC_ALIGNED4(result, linkage, name, t1, t2, t3, t4) DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4)) DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)+ALS(p3)+ALS(p4)) DEFINE_FUNC_PART3(name,(p1, p2, p3, p4)) #define DEFINE_FUNC_ALIGNED5(result, linkage, name, t1, t2, t3, t4, t5) DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5)) DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)+ALS(p3)+ALS(p4)+ALS(p5)) DEFINE_FUNC_PART3(name,(p1, p2, p3, p4, p5)) #define DEFINE_FUNC_ALIGNED6(result, linkage, name, t1, t2, t3, t4, t5, t6) DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6)) DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)+ALS(p3)+ALS(p4)+ALS(p5)+ALS(p6)) DEFINE_FUNC_PART3(name,(p1, p2, p3, p4, p5, p6)) #define DEFINE_FUNC_ALIGNED7(result, linkage, name, t1, t2, t3, t4, t5, t6, t7) DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7)) DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)+ALS(p3)+ALS(p4)+ALS(p5)+ALS(p6)+ALS(p7)) DEFINE_FUNC_PART3(name,(p1, p2, p3, p4, p5, p6, p7)) #define DEFINE_FUNC_ALIGNED8(result, linkage, name, t1, t2, t3, t4, t5, t6, t7, t8) DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8)) DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)+ALS(p3)+ALS(p4)+ALS(p5)+ALS(p6)+ALS(p7)+ALS(p8)) DEFINE_FUNC_PART3(name,(p1, p2, p3, p4, p5, p6, p7, p8)) #define DEFINE_FUNC_ALIGNED9(result, linkage, name, t1, t2, t3, t4, t5, t6, t7, t8, t9) DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9)) DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)+ALS(p3)+ALS(p4)+ALS(p5)+ALS(p6)+ALS(p7)+ALS(p8)+ALS(p9)) DEFINE_FUNC_PART3(name,(p1, p2, p3, p4, p5, p6, p7, p8, p9)) #else #define DEFINE_FUNC_ALIGNED0(result, linkage, name) DEFINE_METHOD_LINKAGE0 (result, linkage, name) #define DEFINE_FUNC_ALIGNED1(result, linkage, name, t1) DEFINE_METHOD_LINKAGE1 (result, linkage, name, (t1 p1) ) #define DEFINE_FUNC_ALIGNED2(result, linkage, name, t1, t2) DEFINE_METHOD_LINKAGE2 (result, linkage, name, (t1 p1, t2 p2) ) #define DEFINE_FUNC_ALIGNED3(result, linkage, name, t1, t2, t3) DEFINE_METHOD_LINKAGE3 (result, linkage, name, (t1 p1, t2 p2, t3 p3) ) #define DEFINE_FUNC_ALIGNED4(result, linkage, name, t1, t2, t3, t4) DEFINE_METHOD_LINKAGE4 (result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4) ) #define DEFINE_FUNC_ALIGNED5(result, linkage, name, t1, t2, t3, t4, t5) DEFINE_METHOD_LINKAGE5 (result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) ) #define DEFINE_FUNC_ALIGNED6(result, linkage, name, t1, t2, t3, t4, t5, t6) DEFINE_METHOD_LINKAGE6 (result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) ) #define DEFINE_FUNC_ALIGNED7(result, linkage, name, t1, t2, t3, t4, t5, t6, t7) DEFINE_METHOD_LINKAGE7 (result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) ) #define DEFINE_FUNC_ALIGNED8(result, linkage, name, t1, t2, t3, t4, t5, t6, t7, t8) DEFINE_METHOD_LINKAGE8 (result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) ) #define DEFINE_FUNC_ALIGNED9(result, linkage, name, t1, t2, t3, t4, t5, t6, t7, t8, t9) DEFINE_METHOD_LINKAGE9 (result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9) ) #define DEFINE_FUNC_ALIGNED10(result, linkage, name, t1, t2, t3, t4, t5, t6, t7, t8, t10) DEFINE_METHOD_LINKAGE10(result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9, t10 p10) ) #define DEFINE_FUNC_ALIGNED11(result, linkage, name, t1, t2, t3, t4, t5, t6, t7, t8, t10, t11) DEFINE_METHOD_LINKAGE11(result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9, t10 p10, t11 p11) ) #endif /////////////////////////////////////////////////////////// // // BEGIN_METHOD_RESOLVE/END_METHOD_RESOLVE // // Defines a method that resolves the exported functions // defined with DEFINE_METHOD or DEFINE_METHOD_LINKAGE. // There must be a RESOLVE_METHOD or RESOLVE_METHOD_RENAME // for each DEFINE_METHOD or DEFINE_METHOD_LINKAGE within this // block. This block must be followed by an END_METHOD_RESOLVE. // #define BEGIN_METHOD_RESOLVE() protected: virtual bool ResolveExports() { return ( #define END_METHOD_RESOLVE() 1 ); } /////////////////////////////////////////////////////////// // // RESOLVE_METHOD // // Resolves a method from a dll // // method: Name of the method defined with DEFINE_METHOD // or DEFINE_METHOD_LINKAGE // #define RESOLVE_METHOD(method) m_dll->ResolveExport( #method , & m_##method##_ptr ) && #define RESOLVE_METHOD_FP(method) m_dll->ResolveExport( #method , & method##_ptr ) && /////////////////////////////////////////////////////////// // // RESOLVE_METHOD_RENAME // // Resolves a method from a dll // // dllmethod: Name of the function exported from the dll // method: Name of the method defined with DEFINE_METHOD // or DEFINE_METHOD_LINKAGE // #define RESOLVE_METHOD_RENAME(dllmethod, method) m_dll->ResolveExport( #dllmethod , & m_##method##_ptr ) && #define RESOLVE_METHOD_RENAME_FP(dllmethod, method) m_dll->ResolveExport( #dllmethod , & method##_ptr ) && //////////////////////////////////////////////////////////////////// // // Example declaration of a dll wrapper class // // 1. Define a class with pure virtual functions with all functions // exported from the dll. This is needed to use the IntelliSence // feature of the Visual Studio Editor. // // class DllExampleInterface // { // public: // virtual void foo (unsigned int type, char* szTest)=0; // virtual void bar (char* szTest, unsigned int type)=0; // }; // // 2. Define a class, derived from DllDynamic and the previously defined // interface class. Define the constructor of the class using the // DECLARE_DLL_WRAPPER macro. Use the DEFINE_METHODX/DEFINE_METHOD_LINKAGEX // macros to define the functions from the interface above, where X is number of // parameters the function has. The function parameters // have to be enclosed in parentheses. The parameter names have to be changed to px // where x is the number on which position the parameter appears. // Use the RESOLVE_METHOD/RESOLVE_METHOD_RENAME to do the actually resolve the functions // from the dll when it's loaded. The RESOLVE_METHOD/RESOLVE_METHOD_RENAME have to // be between the BEGIN_METHOD_RESOLVE/END_METHOD_RESOLVE block. // // class DllExample : public DllDynamic, DllExampleInterface // { // DECLARE_DLL_WRAPPER(DllExample, special://xbmcbin/system/Example.dll) // LOAD_SYMBOLS() // add this if you want to load debug symbols for the dll // DEFINE_METHOD2(void, foo, (int p1, char* p2)) // DEFINE_METHOD_LINKAGE2(void, __stdcall, bar, (char* p1, int p2)) // DEFINE_METHOD_FP(void, foobar, (int type, char* szTest)) // No need to define this function in the // // interface class, as it's a function pointer. // // But its not recognised by IntelliSence // BEGIN_METHOD_RESOLVE() // RESOLVE_METHOD(foo) // RESOLVE_METHOD_RENAME("_bar@8", bar) // RESOLVE_METHOD_FP(foobar) // END_METHOD_RESOLVE() // }; // // The above macros will expand to a class that will look like this // // class DllExample : public DllDynamic, DllExampleInterface // { // public: // DllExample() : DllDynamic( "special://xbmcbin/system/Example.dll" ) {} // protected: // virtual bool LoadSymbols() { return true; } // protected: // typedef void (* foo_METHOD) ( int p1, char* p2 ); // foo_METHOD m_foo; // public: // virtual void foo( int p1, char* p2 ) // { // return m_foo(p1, p2); // } // protected: // typedef void (__stdcall * bar_METHOD) ( char* p1, int p2 ); // bar_METHOD m_bar; // public: // virtual void bar( char* p1, int p2 ) // { // return m_bar(p1, p2); // } // protected: // typedef void (* foobar_METHOD) (int type, char* szTest); // public: // foobar_METHOD foobar; // protected: // virtual bool ResolveExports() // { // return ( // m_dll->ResolveExport( "foo", (void**)& m_foo ) && // m_dll->ResolveExport( "_bar@8", (void**)& m_bar ) && // m_dll->ResolveExport( "foobar" , (void**)& foobar ) && // 1 // ); // } // }; // // Usage of the class // // DllExample dll; // dll.Load(); // if (dll.IsLoaded()) // { // dll.foo(1, "bar"); // dll.Unload(); // } // /////////////////////////////////////////////////////////// // // Baseclass for a Dynamically loaded dll // use the above macros to create a dll wrapper // class DllDynamic { public: DllDynamic(); DllDynamic(const CStdString& strDllName); virtual ~DllDynamic(); virtual bool Load(); virtual void Unload(); virtual bool IsLoaded() { return m_dll!=NULL; } bool CanLoad(); bool EnableDelayedUnload(bool bOnOff); bool SetFile(const CStdString& strDllName); protected: virtual bool ResolveExports()=0; virtual bool LoadSymbols() { return false; } bool m_DelayUnload; LibraryLoader* m_dll; CStdString m_strDllName; };
/* * Copyright (C) 2005-2012 Team XBMC * http://www.xbmc.org * * This Program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This Program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with XBMC; see the file COPYING. If not, see * <http://www.gnu.org/licenses/>. * */ #include "DynamicDll.h" #include "SectionLoader.h" #include "filesystem/File.h" #include "utils/log.h" using namespace XFILE; DllDynamic::DllDynamic() { m_dll=NULL; m_DelayUnload=true; } DllDynamic::DllDynamic(const CStdString& strDllName) { m_strDllName=strDllName; m_dll=NULL; m_DelayUnload=true; } DllDynamic::~DllDynamic() { Unload(); } bool DllDynamic::Load() { if (m_dll) return true; if (!(m_dll=CSectionLoader::LoadDLL(m_strDllName, m_DelayUnload, LoadSymbols()))) return false; if (!ResolveExports()) { CLog::Log(LOGERROR, "Unable to resolve exports from dll %s", m_strDllName.c_str()); Unload(); return false; } return true; } void DllDynamic::Unload() { if(m_dll) CSectionLoader::UnloadDLL(m_strDllName); m_dll=NULL; } bool DllDynamic::CanLoad() { return CFile::Exists(m_strDllName); } bool DllDynamic::EnableDelayedUnload(bool bOnOff) { if (m_dll) return false; m_DelayUnload=bOnOff; return true; } bool DllDynamic::SetFile(const CStdString& strDllName) { if (m_dll) return false; m_strDllName=strDllName; return true; }
一个类继承自DllDynamic,按指定格式定义函数接口后,就可以较轻易的实现动态链接一个新库
比如:
#pragma once /* * Copyright (C) 2005-2012 Team XBMC * http://www.xbmc.org * * This Program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This Program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with XBMC; see the file COPYING. If not, see * <http://www.gnu.org/licenses/>. * */ #if (defined HAVE_CONFIG_H) && (!defined WIN32) #include "config.h" #endif /* undefine byte from PlatformDefs.h since it's used in mad.h */ #undef byte #if defined(_LINUX) || defined(TARGET_DARWIN) #include <mad.h> #else #include "libmad/mad.h" #endif #include "DynamicDll.h" class DllLibMadInterface { public: virtual ~DllLibMadInterface() {} virtual void mad_synth_init(struct mad_synth *)=0; virtual void mad_stream_init(struct mad_stream *)=0; virtual void mad_frame_init(struct mad_frame *)=0; virtual void mad_stream_finish(struct mad_stream *)=0; virtual void mad_frame_finish(struct mad_frame *)=0; virtual void mad_stream_buffer(struct mad_stream *, unsigned char const *, unsigned long)=0; virtual void mad_synth_frame(struct mad_synth *, struct mad_frame const *)=0; virtual int mad_frame_decode(struct mad_frame *, struct mad_stream *)=0; virtual int mad_stream_sync(struct mad_stream *) = 0; virtual char const* mad_stream_errorstr(struct mad_stream const *) = 0; virtual void mad_frame_mute(struct mad_frame *) = 0; virtual void mad_synth_mute(struct mad_synth *) = 0; virtual void mad_timer_add(mad_timer_t *, mad_timer_t) = 0; virtual mad_timer_t Get_mad_timer_zero() = 0; }; class DllLibMad : public DllDynamic, DllLibMadInterface { DECLARE_DLL_WRAPPER(DllLibMad, DLL_PATH_LIBMAD) DEFINE_METHOD1(void, mad_synth_init, (struct mad_synth * p1)) DEFINE_METHOD1(void, mad_stream_init, (struct mad_stream * p1)) DEFINE_METHOD1(void, mad_frame_init, (struct mad_frame * p1)) DEFINE_METHOD1(void, mad_stream_finish, (struct mad_stream * p1)) DEFINE_METHOD1(void, mad_frame_finish, (struct mad_frame * p1)) DEFINE_METHOD3(void, mad_stream_buffer, (struct mad_stream * p1, unsigned char const *p2, unsigned long p3)) DEFINE_METHOD2(void, mad_synth_frame, (struct mad_synth *p1, struct mad_frame const *p2)) DEFINE_METHOD2(int, mad_frame_decode, (struct mad_frame *p1, struct mad_stream *p2)) DEFINE_METHOD1(int, mad_stream_sync, (struct mad_stream *p1)) DEFINE_METHOD1(void, mad_frame_mute, (struct mad_frame *p1)) DEFINE_METHOD1(void, mad_synth_mute, (struct mad_synth *p1)) DEFINE_METHOD2(void, mad_timer_add, (mad_timer_t *p1, mad_timer_t p2)) DEFINE_METHOD1(char const*, mad_stream_errorstr, (struct mad_stream const *p1)) DEFINE_GLOBAL(mad_timer_t, mad_timer_zero) BEGIN_METHOD_RESOLVE() RESOLVE_METHOD(mad_synth_init) RESOLVE_METHOD(mad_stream_init) RESOLVE_METHOD(mad_frame_init) RESOLVE_METHOD(mad_stream_finish) RESOLVE_METHOD(mad_frame_finish) RESOLVE_METHOD(mad_stream_buffer) RESOLVE_METHOD(mad_synth_frame) RESOLVE_METHOD(mad_frame_decode) RESOLVE_METHOD(mad_stream_sync) RESOLVE_METHOD(mad_frame_mute) RESOLVE_METHOD(mad_synth_mute) RESOLVE_METHOD(mad_timer_add) RESOLVE_METHOD(mad_stream_errorstr) RESOLVE_METHOD(mad_timer_zero) END_METHOD_RESOLVE() };
想实现静态链接库进来,就得在类继承这儿动手脚
我写了两个头文件,如下:
#ifndef __DEF_STATIC_LIB_METHOD_H__ #define __DEF_STATIC_LIB_METHOD_H__ #undef DECLARE_DLL_WRAPPER #undef XDECLARE_DLL_WRAPPER #undef RESOLVE_METHOD #undef RESOLVE_METHOD_FP #undef RESOLVE_METHOD_RENAME #undef RESOLVE_METHOD_RENAME_FP #define DECLARE_DLL_WRAPPER(classname, dllname) XDECLARE_DLL_WRAPPER(classname,dllname) #define XDECLARE_DLL_WRAPPER(classname, dllname) public: classname () : DllDynamic( dllname ) {} virtual bool Load() { if (m_dll) return true; m_dll = (LibraryLoader*)1; return ResolveExports(); } virtual void Unload() { m_dll = 0; } #define RESOLVE_METHOD(method) ( m_##method##_ptr = (void*) & :: method ) && #define RESOLVE_METHOD_FP(method) ( method##_ptr = (void*) & :: method ) && #define RESOLVE_METHOD_RENAME(dllmethod, method) ( m_##method##_ptr = (void*) & :: dllmethod ) && #define RESOLVE_METHOD_RENAME_FP(dllmethod, method) ( method##_ptr = (void*) & :: dllmethod ) && #undef __DEF_SHARED_SO_METHOD_H__ #endif
#ifndef __DEF_SHARED_SO_METHOD_H__ #define __DEF_SHARED_SO_METHOD_H__ #undef DECLARE_DLL_WRAPPER #undef XDECLARE_DLL_WRAPPER #undef RESOLVE_METHOD #undef RESOLVE_METHOD_FP #undef RESOLVE_METHOD_RENAME #undef RESOLVE_METHOD_RENAME_FP #define DECLARE_DLL_WRAPPER(classname, dllname) XDECLARE_DLL_WRAPPER(classname,dllname) #define XDECLARE_DLL_WRAPPER(classname, dllname) public: classname () : DllDynamic( dllname ) {} #define RESOLVE_METHOD(method) m_dll->ResolveExport( #method , & m_##method##_ptr ) && #define RESOLVE_METHOD_FP(method) m_dll->ResolveExport( #method , & method##_ptr ) && #define RESOLVE_METHOD_RENAME(dllmethod, method) m_dll->ResolveExport( #dllmethod , & m_##method##_ptr ) && #define RESOLVE_METHOD_RENAME_FP(dllmethod, method) m_dll->ResolveExport( #dllmethod , & method##_ptr ) && #undef __DEF_STATIC_LIB_METHOD_H__ #endif
如何使用?
只需要在类定义之前包含def_static_lib_method.h,在之后再包含def_shared_so_method.h即可
静态链接的秘诀就在替换了RESOLVE_METHOD那几个宏,将函数调用替换成指针赋值
亮点在于,两个头文件,在末尾分别undef对方的头文件包含宏,这样就可以任意次在不同的头文件中
成对使用这两个头文件包含了