diff --git a/public/interface.cpp b/public/interface.cpp index 0ba14bf..5877391 100644 --- a/public/interface.cpp +++ b/public/interface.cpp @@ -61,7 +61,7 @@ InterfaceReg::InterfaceReg(InstantiateInterfaceFn fn, const char* pName) : m_pNa // ------------------------------------------------------------------------------------ // // CreateInterface. // ------------------------------------------------------------------------------------ // -DLLEXPORT IBaseInterface* CreateInterface(const char* pName, int* pReturnCode) +EXPORT_FUNCTION void* CreateInterface(const char* pName, int* pReturnCode) { InterfaceReg* pCur; @@ -84,6 +84,8 @@ DLLEXPORT IBaseInterface* CreateInterface(const char* pName, int* pReturnCode) return NULL; } +// BEN-NOTE: unifying this on all platforms +#if 0 //Local version of CreateInterface, marked static so that it is never merged with the version in other libraries static IBaseInterface* CreateInterfaceLocal(const char* pName, int* pReturnCode) { @@ -107,6 +109,7 @@ static IBaseInterface* CreateInterfaceLocal(const char* pName, int* pReturnCode) } return NULL; } +#endif // 0 //----------------------------------------------------------------------------- // Purpose: returns a pointer to a function, given a module @@ -220,5 +223,10 @@ CreateInterfaceFn Sys_GetFactory(CSysModule* pModule) //----------------------------------------------------------------------------- CreateInterfaceFn Sys_GetFactoryThis() { + // BEN-NOTE: unifying this on all platforms +#if 0 return CreateInterfaceLocal; +#else + return CreateInterface; +#endif } diff --git a/public/interface.h b/public/interface.h index eef9c00..a01db53 100644 --- a/public/interface.h +++ b/public/interface.h @@ -14,9 +14,12 @@ // for legacy code). In this case, you need to make a new version name for your new interface, and make a wrapper interface and // expose it for the old interface. -//#if _MSC_VER >= 1300 // VC7 -//#include "tier1/interface.h" -//#else +// JoshA: Everything uses this now. +#if 1 +#include "tier1/interface.h" +#else + +#error use proper interface only #pragma once @@ -79,9 +82,18 @@ public: static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); // Use this to expose a singleton interface. This creates the global variable for you automatically. +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) #define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ static className __g_##className##_singleton; \ EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) +#else +#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ + namespace _SUBSYSTEM \ + { \ + static className __g_##className##_singleton; \ + } \ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) +#endif // This function is automatically exported and allows you to access any interfaces exposed with the above macros. // if pReturnCode is set, it will return one of the following values @@ -113,4 +125,4 @@ extern void Sys_UnloadModule(CSysModule* pModule); extern CreateInterfaceFn Sys_GetFactory(CSysModule* pModule); -//#endif // MSVC 6.0 +#endif // MSVC 6.0 diff --git a/public/tier1/interface.h b/public/tier1/interface.h new file mode 100644 index 0000000..aa212cf --- /dev/null +++ b/public/tier1/interface.h @@ -0,0 +1,218 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +// This header defines the interface convention used in the valve engine. +// To make an interface and expose it: +// 1. The interface must be ALL pure virtuals, and have no data members. +// 2. Define a name for it. +// 3. In its implementation file, use EXPOSE_INTERFACE or EXPOSE_SINGLE_INTERFACE. + +// Versioning +// There are two versioning cases that are handled by this: +// 1. You add functions to the end of an interface, so it is binary compatible with the previous interface. In this case, +// you need two EXPOSE_INTERFACEs: one to expose your class as the old interface and one to expose it as the new interface. +// 2. You update an interface so it's not compatible anymore (but you still want to be able to expose the old interface +// for legacy code). In this case, you need to make a new version name for your new interface, and make a wrapper interface and +// expose it for the old interface. + +// Static Linking: +// Must mimic unique seperate class 'InterfaceReg' constructors per subsystem. +// Each subsystem can then import and export interfaces as expected. +// This is achieved through unique namespacing 'InterfaceReg' via symbol _SUBSYSTEM. +// Static Linking also needs to generate unique symbols per interface so as to +// provide a 'stitching' method whereby these interface symbols can be referenced +// via the lib's primary module (usually the lib's interface exposure) +// therby stitching all of that lib's code/data together for eventual final exe link inclusion. + +#ifndef INTERFACE_H +#define INTERFACE_H + +#ifdef _WIN32 +#pragma once +#endif + +#ifdef _LINUX +#include // dlopen,dlclose, et al +#include + +#define HMODULE void * +#define GetProcAddress dlsym + +#define _snprintf snprintf +#endif + +// All interfaces derive from this. +class IBaseInterface +{ +public: + virtual ~IBaseInterface() {} +}; + + +#define CREATEINTERFACE_PROCNAME "CreateInterface" +typedef void* (*CreateInterfaceFn)(const char *pName, int *pReturnCode); +typedef void* (*InstantiateInterfaceFn)(); + + + +// Used internally to register classes. +class InterfaceReg +{ +public: + InterfaceReg(InstantiateInterfaceFn fn, const char *pName); + +public: + InstantiateInterfaceFn m_CreateFn; + const char *m_pName; + + InterfaceReg *m_pNext; // For the global list. + static InterfaceReg *s_pInterfaceRegs; +}; + +#if defined(_STATIC_LINKED) && defined(_SUBSYSTEM) + +#endif + +// Use this to expose an interface that can have multiple instances. +// e.g.: +// EXPOSE_INTERFACE( CInterfaceImp, IInterface, "MyInterface001" ) +// This will expose a class called CInterfaceImp that implements IInterface (a pure class) +// clients can receive a pointer to this class by calling CreateInterface( "MyInterface001" ) +// +// In practice, the shared header file defines the interface (IInterface) and version name ("MyInterface001") +// so that each component can use these names/vtables to communicate +// +// A single class can support multiple interfaces through multiple inheritance +// +// Use this if you want to write the factory function. +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \ + static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName); +#else +#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \ + namespace _SUBSYSTEM \ + { \ + static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName); \ + } +#endif + +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_INTERFACE(className, interfaceName, versionName) \ + static void* __Create##className##_interface() {return (interfaceName *)new className;} \ + static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); +#else +#define EXPOSE_INTERFACE(className, interfaceName, versionName) \ + namespace _SUBSYSTEM \ + { \ + static void* __Create##className##_interface() {return (interfaceName *)new className;} \ + static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); \ + } +#endif + +// Use this to expose a singleton interface with a global variable you've created. +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \ + static void* __Create##className##interfaceName##_interface() {return (interfaceName *)&globalVarName;} \ + static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); +#else +#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \ + namespace _SUBSYSTEM \ + { \ + static void* __Create##className##interfaceName##_interface() {return (interfaceName *)&globalVarName;} \ + static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); \ + } +#endif + +// Use this to expose a singleton interface. This creates the global variable for you automatically. +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ + static className __g_##className##_singleton; \ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) +#else +#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ + namespace _SUBSYSTEM \ + { \ + static className __g_##className##_singleton; \ + } \ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) +#endif + +// This function is automatically exported and allows you to access any interfaces exposed with the above macros. +// if pReturnCode is set, it will return one of the following values +// extend this for other error conditions/code + +// load/unload components +class CSysModule; + +// interface return status +enum +{ + IFACE_OK = 0, + IFACE_FAILED +}; + +#if defined(_STATIC_LINKED) && defined(_SUBSYSTEM) + +#endif + +#ifdef WIN32 +#define EXPORT_FUNCTION __declspec(dllexport) +#else +#define EXPORT_FUNCTION __attribute__ ((visibility("default"))) +#endif + +#ifndef DLL_EXPORT +#define DLL_EXPORT EXPORT_FUNCTION +#endif + +//----------------------------------------------------------------------------- +// This function is automatically exported and allows you to access any interfaces exposed with the above macros. +// if pReturnCode is set, it will return one of the following values (IFACE_OK, IFACE_FAILED) +// extend this for other error conditions/code +//----------------------------------------------------------------------------- +extern "C" DLL_EXPORT void* CreateInterface(const char *pName, int *pReturnCode); + +extern CreateInterfaceFn Sys_GetFactoryThis( void ); + + +//----------------------------------------------------------------------------- +// UNDONE: This is obsolete, use the module load/unload/get instead!!! +//----------------------------------------------------------------------------- +extern CreateInterfaceFn Sys_GetFactory( const char *pModuleName ); + + +struct ModuleCount_t +{ + CSysModule *m_pSysModule; + int m_cRef; + bool operator==( const ModuleCount_t &rhs ) const { return rhs.m_pSysModule == m_pSysModule; } +}; + +//----------------------------------------------------------------------------- +// Load & Unload should be called in exactly one place for each module +// The factory for that module should be passed on to dependent components for +// proper versioning. +//----------------------------------------------------------------------------- +extern CSysModule *Sys_LoadModule( const char *pModuleName ); +extern void Sys_UnloadModule( CSysModule *pModule ); + +extern CreateInterfaceFn Sys_GetFactory( CSysModule *pModule ); + +// This is a helper function to load a module, get its factory, and get a specific interface. +// You are expected to free all of these things. +// Returns false and cleans up if any of the steps fail. +bool Sys_LoadInterface( + const char *pModuleName, + const char *pInterfaceVersionName, + CSysModule **pOutModule, + void **pOutInterface ); + +#endif + + +