Team Fortress 2 Source Code as on 22/4/2020
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.

230 lines
9.0 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // This header defines the interface convention used in the valve engine.
  9. // To make an interface and expose it:
  10. // 1. The interface must be ALL pure virtuals, and have no data members.
  11. // 2. Define a name for it.
  12. // 3. In its implementation file, use EXPOSE_INTERFACE or EXPOSE_SINGLE_INTERFACE.
  13. // Versioning
  14. // There are two versioning cases that are handled by this:
  15. // 1. You add functions to the end of an interface, so it is binary compatible with the previous interface. In this case,
  16. // you need two EXPOSE_INTERFACEs: one to expose your class as the old interface and one to expose it as the new interface.
  17. // 2. You update an interface so it's not compatible anymore (but you still want to be able to expose the old interface
  18. // for legacy code). In this case, you need to make a new version name for your new interface, and make a wrapper interface and
  19. // expose it for the old interface.
  20. // Static Linking:
  21. // Must mimic unique seperate class 'InterfaceReg' constructors per subsystem.
  22. // Each subsystem can then import and export interfaces as expected.
  23. // This is achieved through unique namespacing 'InterfaceReg' via symbol _SUBSYSTEM.
  24. // Static Linking also needs to generate unique symbols per interface so as to
  25. // provide a 'stitching' method whereby these interface symbols can be referenced
  26. // via the lib's primary module (usually the lib's interface exposure)
  27. // therby stitching all of that lib's code/data together for eventual final exe link inclusion.
  28. #ifndef INTERFACE_H
  29. #define INTERFACE_H
  30. #ifdef _WIN32
  31. #pragma once
  32. #endif
  33. #ifdef _LINUX
  34. #include <dlfcn.h> // dlopen,dlclose, et al
  35. #include <unistd.h>
  36. #define GetProcAddress dlsym
  37. #ifdef _snprintf
  38. #undef _snprintf
  39. #endif
  40. #define _snprintf snprintf
  41. #endif
  42. // TODO: move interface.cpp into tier0 library.
  43. #include "tier0/platform.h"
  44. // All interfaces derive from this.
  45. class IBaseInterface
  46. {
  47. public:
  48. virtual ~IBaseInterface() {}
  49. };
  50. #if !defined( _X360 )
  51. #define CREATEINTERFACE_PROCNAME "CreateInterface"
  52. #else
  53. // x360 only allows ordinal exports, .def files export "CreateInterface" at 1
  54. #define CREATEINTERFACE_PROCNAME ((const char*)1)
  55. #endif
  56. typedef void* (*CreateInterfaceFn)(const char *pName, int *pReturnCode);
  57. typedef void* (*InstantiateInterfaceFn)();
  58. // Used internally to register classes.
  59. class InterfaceReg
  60. {
  61. public:
  62. InterfaceReg(InstantiateInterfaceFn fn, const char *pName);
  63. public:
  64. InstantiateInterfaceFn m_CreateFn;
  65. const char *m_pName;
  66. InterfaceReg *m_pNext; // For the global list.
  67. static InterfaceReg *s_pInterfaceRegs;
  68. };
  69. // Use this to expose an interface that can have multiple instances.
  70. // e.g.:
  71. // EXPOSE_INTERFACE( CInterfaceImp, IInterface, "MyInterface001" )
  72. // This will expose a class called CInterfaceImp that implements IInterface (a pure class)
  73. // clients can receive a pointer to this class by calling CreateInterface( "MyInterface001" )
  74. //
  75. // In practice, the shared header file defines the interface (IInterface) and version name ("MyInterface001")
  76. // so that each component can use these names/vtables to communicate
  77. //
  78. // A single class can support multiple interfaces through multiple inheritance
  79. //
  80. // Use this if you want to write the factory function.
  81. #if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM)
  82. #define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \
  83. static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName);
  84. #else
  85. #define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \
  86. namespace _SUBSYSTEM \
  87. { \
  88. static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName); \
  89. }
  90. #endif
  91. #if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM)
  92. #define EXPOSE_INTERFACE(className, interfaceName, versionName) \
  93. static void* __Create##className##_interface() {return static_cast<interfaceName *>( new className );} \
  94. static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName );
  95. #else
  96. #define EXPOSE_INTERFACE(className, interfaceName, versionName) \
  97. namespace _SUBSYSTEM \
  98. { \
  99. static void* __Create##className##_interface() {return static_cast<interfaceName *>( new className );} \
  100. static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); \
  101. }
  102. #endif
  103. // Use this to expose a singleton interface with a global variable you've created.
  104. #if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM)
  105. #define EXPOSE_SINGLE_INTERFACE_GLOBALVAR_WITH_NAMESPACE(className, interfaceNamespace, interfaceName, versionName, globalVarName) \
  106. static void* __Create##className##interfaceName##_interface() {return static_cast<interfaceNamespace interfaceName *>( &globalVarName );} \
  107. static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName);
  108. #else
  109. #define EXPOSE_SINGLE_INTERFACE_GLOBALVAR_WITH_NAMESPACE(className, interfaceNamespace, interfaceName, versionName, globalVarName) \
  110. namespace _SUBSYSTEM \
  111. { \
  112. static void* __Create##className##interfaceName##_interface() {return static_cast<interfaceNamespace interfaceName *>( &globalVarName );} \
  113. static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); \
  114. }
  115. #endif
  116. #define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \
  117. EXPOSE_SINGLE_INTERFACE_GLOBALVAR_WITH_NAMESPACE(className, , interfaceName, versionName, globalVarName)
  118. // Use this to expose a singleton interface. This creates the global variable for you automatically.
  119. #if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM)
  120. #define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \
  121. static className __g_##className##_singleton; \
  122. EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton)
  123. #else
  124. #define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \
  125. namespace _SUBSYSTEM \
  126. { \
  127. static className __g_##className##_singleton; \
  128. } \
  129. EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton)
  130. #endif
  131. // load/unload components
  132. class CSysModule;
  133. // interface return status
  134. enum
  135. {
  136. IFACE_OK = 0,
  137. IFACE_FAILED
  138. };
  139. //-----------------------------------------------------------------------------
  140. // This function is automatically exported and allows you to access any interfaces exposed with the above macros.
  141. // if pReturnCode is set, it will return one of the following values (IFACE_OK, IFACE_FAILED)
  142. // extend this for other error conditions/code
  143. //-----------------------------------------------------------------------------
  144. DLL_EXPORT void* CreateInterface(const char *pName, int *pReturnCode);
  145. #if defined( _X360 )
  146. DLL_EXPORT void *CreateInterfaceThunk( const char *pName, int *pReturnCode );
  147. #endif
  148. //-----------------------------------------------------------------------------
  149. // UNDONE: This is obsolete, use the module load/unload/get instead!!!
  150. //-----------------------------------------------------------------------------
  151. extern CreateInterfaceFn Sys_GetFactory( CSysModule *pModule );
  152. extern CreateInterfaceFn Sys_GetFactory( const char *pModuleName );
  153. extern CreateInterfaceFn Sys_GetFactoryThis( void );
  154. enum Sys_Flags
  155. {
  156. SYS_NOFLAGS = 0x00,
  157. SYS_NOLOAD = 0x01 // no loading, no ref-counting, only returns handle if lib is loaded.
  158. };
  159. //-----------------------------------------------------------------------------
  160. // Load & Unload should be called in exactly one place for each module
  161. // The factory for that module should be passed on to dependent components for
  162. // proper versioning.
  163. //-----------------------------------------------------------------------------
  164. extern CSysModule *Sys_LoadModule( const char *pModuleName, Sys_Flags flags = SYS_NOFLAGS );
  165. extern void Sys_UnloadModule( CSysModule *pModule );
  166. // This is a helper function to load a module, get its factory, and get a specific interface.
  167. // You are expected to free all of these things.
  168. // Returns false and cleans up if any of the steps fail.
  169. bool Sys_LoadInterface(
  170. const char *pModuleName,
  171. const char *pInterfaceVersionName,
  172. CSysModule **pOutModule,
  173. void **pOutInterface );
  174. bool Sys_IsDebuggerPresent();
  175. //-----------------------------------------------------------------------------
  176. // Purpose: Place this as a singleton at module scope (e.g.) and use it to get the factory from the specified module name.
  177. //
  178. // When the singleton goes out of scope (.dll unload if at module scope),
  179. // then it'll call Sys_UnloadModule on the module so that the refcount is decremented
  180. // and the .dll actually can unload from memory.
  181. //-----------------------------------------------------------------------------
  182. class CDllDemandLoader
  183. {
  184. public:
  185. CDllDemandLoader( char const *pchModuleName );
  186. virtual ~CDllDemandLoader();
  187. CreateInterfaceFn GetFactory();
  188. void Unload();
  189. private:
  190. char const *m_pchModuleName;
  191. CSysModule *m_hModule;
  192. bool m_bLoadAttempted;
  193. };
  194. #endif