//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// // This makes it easy to dynamically load a shared library and lookup a // function in that library. // // Usage: // CDynamicFunction MyPuts(libname, "puts"); // if (MyPuts) // MyPuts("Hello world!"); // // Please note that this interface does not distinguish between functions and // data. If you look up a global variable in your shared library, or simply // mess up the function signature, you'll get a valid pointer and a crash // if you call it as a function. #ifndef DYNFUNCTION_H #define DYNFUNCTION_H #pragma once #include "tier0/platform.h" // The heavy lifting isn't template-specific, so we move it out of the header. DLL_EXPORT void *VoidFnPtrLookup_Tier0(const char *libname, const char *fn, void *fallback); template < class FunctionType > class CDynamicFunction { public: // Construct with a NULL function pointer. You must manually call // Lookup() before you can call a dynamic function through this interface. CDynamicFunction() : m_pFn(NULL) {} // Construct and do a lookup right away. You will need to make sure that // the lookup actually succeeded, as (libname) might have failed to load // or (fn) might not exist in it. CDynamicFunction(const char *libname, const char *fn, FunctionType fallback=NULL) : m_pFn(NULL) { Lookup(libname, fn, fallback); } // Construct and do a lookup right away. See comments in Lookup() about what (okay) does. CDynamicFunction(const char *libname, const char *fn, bool &okay, FunctionType fallback=NULL) : m_pFn(NULL) { Lookup(libname, fn, okay, fallback); } // Load library if necessary, look up symbol. Returns true and sets // m_pFn on successful lookup, returns false otherwise. If the // function pointer is already looked up, this return true immediately. // Use Reset() first if you want to look up the symbol again. // This function will return false immediately unless (okay) is true. // This allows you to chain lookups like this: // bool okay = true; // x.Lookup(lib, "x", okay); // y.Lookup(lib, "y", okay); // z.Lookup(lib, "z", okay); // if (okay) { printf("All functions were loaded successfully!\n"); } // If you supply a fallback, it'll be used if the lookup fails (and if // non-NULL, means this will always return (okay)). bool Lookup(const char *libname, const char *fn, bool &okay, FunctionType fallback=NULL) { if (!okay) return false; else if (m_pFn == NULL) m_pFn = (FunctionType) VoidFnPtrLookup_Tier0(libname, fn, (void *) fallback); okay = m_pFn != NULL; return okay; } // Load library if necessary, look up symbol. Returns true and sets // m_pFn on successful lookup, returns false otherwise. If the // function pointer is already looked up, this return true immediately. // Use Reset() first if you want to look up the symbol again. // This function will return false immediately unless (okay) is true. // If you supply a fallback, it'll be used if the lookup fails (and if // non-NULL, means this will always return true). bool Lookup(const char *libname, const char *fn, FunctionType fallback=NULL) { bool okay = true; return Lookup(libname, fn, okay, fallback); } // Invalidates the current lookup. Makes the function pointer NULL. You // will need to call Lookup() before you can call a dynamic function // through this interface again. void Reset() { m_pFn = NULL; } // Force this to be a specific function pointer. void Force(FunctionType ptr) { m_pFn = ptr; } // Retrieve the actual function pointer. FunctionType Pointer() const { return m_pFn; } operator FunctionType() const { return m_pFn; } // Can be used to verify that we have an actual function looked up and // ready to call: if (!MyDynFunc) { printf("Function not found!\n"); } operator bool () const { return m_pFn != NULL; } bool operator !() const { return m_pFn == NULL; } protected: FunctionType m_pFn; }; // This is the same as CDynamicFunction, but we made the default constructor // private, forcing you to do loading/lookup during construction. // The usage pattern is to have a list of dynamic functions that are // constructed en masse as part of another class's constructor, with the // possibility of human error removed (the compiler will complain if you // forget to initialize one). template < class FunctionType > class CDynamicFunctionMustInit : public CDynamicFunction < FunctionType > { private: // forbid default constructor. CDynamicFunctionMustInit() {} public: CDynamicFunctionMustInit(const char *libname, const char *fn, FunctionType fallback=NULL) : CDynamicFunction< FunctionType >(libname, fn, fallback) { } CDynamicFunctionMustInit(const char *libname, const char *fn, bool &okay, FunctionType fallback=NULL) : CDynamicFunction< FunctionType >(libname, fn, okay, fallback) { } }; #endif // DYNFUNCTION_H