|
|
|
//========= 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
|
|
|
|
|