You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
5.0 KiB
136 lines
5.0 KiB
//========= 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<void (*)(const char *)> 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() = default; |
|
|
|
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 |
|
|
|
|