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.

705 lines
19 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #if defined( _WIN32 ) && !defined( _X360 )
  7. #include <windows.h>
  8. #endif
  9. #if !defined( DONT_PROTECT_FILEIO_FUNCTIONS )
  10. #define DONT_PROTECT_FILEIO_FUNCTIONS // for protected_things.h
  11. #endif
  12. #if defined( PROTECTED_THINGS_ENABLE )
  13. #undef PROTECTED_THINGS_ENABLE // from protected_things.h
  14. #endif
  15. #include <stdio.h>
  16. #include "tier1/interface.h"
  17. #include "basetypes.h"
  18. #include "tier0/dbg.h"
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include "tier1/strtools.h"
  22. #include "tier0/icommandline.h"
  23. #include "tier0/dbg.h"
  24. #include "tier0/stacktools.h"
  25. #include "tier0/threadtools.h"
  26. #ifdef _WIN32
  27. #include <direct.h> // getcwd
  28. #endif
  29. #if defined( _X360 )
  30. #include "xbox/xbox_win32stubs.h"
  31. #endif
  32. #ifdef _PS3
  33. #include "sys/prx.h"
  34. #include "tier1/utlvector.h"
  35. #include "ps3/ps3_platform.h"
  36. #include "ps3/ps3_win32stubs.h"
  37. #include "ps3/ps3_helpers.h"
  38. #include "ps3_pathinfo.h"
  39. #elif defined(POSIX)
  40. #include "tier0/platform.h"
  41. #endif // _PS3
  42. // memdbgon must be the last include file in a .cpp file!!!
  43. #include "tier0/memdbgon.h"
  44. // ------------------------------------------------------------------------------------ //
  45. // InterfaceReg.
  46. // ------------------------------------------------------------------------------------ //
  47. #ifdef POSIX
  48. DLL_GLOBAL_EXPORT
  49. #endif
  50. InterfaceReg *s_pInterfaceRegs;
  51. InterfaceReg::InterfaceReg( InstantiateInterfaceFn fn, const char *pName ) :
  52. m_pName(pName)
  53. {
  54. m_CreateFn = fn;
  55. m_pNext = s_pInterfaceRegs;
  56. s_pInterfaceRegs = this;
  57. }
  58. // ------------------------------------------------------------------------------------ //
  59. // CreateInterface.
  60. // This is the primary exported function by a dll, referenced by name via dynamic binding
  61. // that exposes an opqaue function pointer to the interface.
  62. //
  63. // We have the Internal variant so Sys_GetFactoryThis() returns the correct internal
  64. // symbol under GCC/Linux/Mac as CreateInterface is DLL_EXPORT so its global so the loaders
  65. // on those OS's pick exactly 1 of the CreateInterface symbols to be the one that is process wide and
  66. // all Sys_GetFactoryThis() calls find that one, which doesn't work. Using the internal walkthrough here
  67. // makes sure Sys_GetFactoryThis() has the dll specific symbol and GetProcAddress() returns the module specific
  68. // function for CreateInterface again getting the dll specific symbol we need.
  69. // ------------------------------------------------------------------------------------ //
  70. void* CreateInterfaceInternal( const char *pName, int *pReturnCode )
  71. {
  72. InterfaceReg *pCur;
  73. for (pCur=s_pInterfaceRegs; pCur; pCur=pCur->m_pNext)
  74. {
  75. if (strcmp(pCur->m_pName, pName) == 0)
  76. {
  77. if (pReturnCode)
  78. {
  79. *pReturnCode = IFACE_OK;
  80. }
  81. return pCur->m_CreateFn();
  82. }
  83. }
  84. if (pReturnCode)
  85. {
  86. *pReturnCode = IFACE_FAILED;
  87. }
  88. return NULL;
  89. }
  90. void* CreateInterface( const char *pName, int *pReturnCode )
  91. {
  92. return CreateInterfaceInternal( pName, pReturnCode );
  93. }
  94. #if defined( POSIX ) && !defined( _PS3 )
  95. // Linux doesn't have this function so this emulates its functionality
  96. void *GetModuleHandle(const char *name)
  97. {
  98. void *handle;
  99. if( name == NULL )
  100. {
  101. // hmm, how can this be handled under linux....
  102. // is it even needed?
  103. return NULL;
  104. }
  105. if( (handle=dlopen(name, RTLD_NOW))==NULL)
  106. {
  107. printf("DLOPEN Error:%s\n",dlerror());
  108. // couldn't open this file
  109. return NULL;
  110. }
  111. // read "man dlopen" for details
  112. // in short dlopen() inc a ref count
  113. // so dec the ref count by performing the close
  114. dlclose(handle);
  115. return handle;
  116. }
  117. #endif
  118. #if defined( _WIN32 ) && !defined( _X360 )
  119. #define WIN32_LEAN_AND_MEAN
  120. #include "windows.h"
  121. #endif
  122. //-----------------------------------------------------------------------------
  123. // Purpose: returns a pointer to a function, given a module
  124. // Input : pModuleName - module name
  125. // *pName - proc name
  126. //-----------------------------------------------------------------------------
  127. static void *Sys_GetProcAddress( const char *pModuleName, const char *pName )
  128. {
  129. #if defined( _PS3 )
  130. Assert( !"Unsupported, use HMODULE" );
  131. return NULL;
  132. #else // !_PS3
  133. HMODULE hModule = (HMODULE)GetModuleHandle( pModuleName );
  134. #if defined( WIN32 )
  135. return (void *)GetProcAddress( hModule, pName );
  136. #else // !WIN32
  137. return (void *)dlsym( (void *)hModule, pName );
  138. #endif // WIN32
  139. #endif // _PS3
  140. }
  141. static void *Sys_GetProcAddress( HMODULE hModule, const char *pName )
  142. {
  143. #if defined( WIN32 )
  144. return (void *)GetProcAddress( hModule, pName );
  145. #elif defined( _PS3 )
  146. PS3_LoadAppSystemInterface_Parameters_t *pPRX = reinterpret_cast< PS3_LoadAppSystemInterface_Parameters_t * >( hModule );
  147. if ( !pPRX )
  148. return NULL;
  149. if ( !strcmp( pName, CREATEINTERFACE_PROCNAME ) )
  150. return reinterpret_cast< void * >( pPRX->pfnCreateInterface );
  151. Assert( !"Unknown PRX function requested!" );
  152. return NULL;
  153. #else
  154. return (void *)dlsym( (void *)hModule, pName );
  155. #endif
  156. }
  157. bool Sys_IsDebuggerPresent()
  158. {
  159. return Plat_IsInDebugSession();
  160. }
  161. struct ThreadedLoadLibaryContext_t
  162. {
  163. const char *m_pLibraryName;
  164. HMODULE m_hLibrary;
  165. DWORD m_nError;
  166. ThreadedLoadLibaryContext_t() : m_pLibraryName(NULL), m_hLibrary(0), m_nError(0) {}
  167. };
  168. #ifdef _WIN32
  169. // wraps LoadLibraryEx() since 360 doesn't support that
  170. static HMODULE InternalLoadLibrary( const char *pName )
  171. {
  172. #if defined(_X360)
  173. return LoadLibrary( pName );
  174. #else
  175. return LoadLibraryEx( pName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
  176. #endif
  177. }
  178. unsigned ThreadedLoadLibraryFunc( void *pParam )
  179. {
  180. ThreadedLoadLibaryContext_t *pContext = (ThreadedLoadLibaryContext_t*)pParam;
  181. pContext->m_hLibrary = InternalLoadLibrary(pContext->m_pLibraryName);
  182. return 0;
  183. }
  184. #endif
  185. // global to propagate a library load error from thread into Sys_LoadModule
  186. static DWORD g_nLoadLibraryError = 0;
  187. static HMODULE Sys_LoadLibraryGuts( const char *pLibraryName )
  188. {
  189. #ifdef PLATFORM_PS3
  190. PS3_LoadAppSystemInterface_Parameters_t *pPRX = new PS3_LoadAppSystemInterface_Parameters_t;
  191. V_memset( pPRX, 0, sizeof( PS3_LoadAppSystemInterface_Parameters_t ) );
  192. pPRX->cbSize = sizeof( PS3_LoadAppSystemInterface_Parameters_t );
  193. int iResult = PS3_PrxLoad( pLibraryName, pPRX );
  194. if ( iResult < CELL_OK )
  195. {
  196. delete pPRX;
  197. return NULL;
  198. }
  199. return reinterpret_cast< HMODULE >( pPRX );
  200. #else
  201. char str[1024];
  202. // How to get a string out of a #define on the command line.
  203. const char *pModuleExtension = DLL_EXT_STRING;
  204. const char *pModuleAddition = pModuleExtension;
  205. V_strncpy( str, pLibraryName, sizeof(str) );
  206. if ( !V_stristr( str, pModuleExtension ) )
  207. {
  208. if ( IsX360() )
  209. {
  210. V_StripExtension( str, str, sizeof(str) );
  211. }
  212. V_strncat( str, pModuleAddition, sizeof(str) );
  213. }
  214. V_FixSlashes( str );
  215. #ifdef _WIN32
  216. ThreadedLoadLibraryFunc_t threadFunc = GetThreadedLoadLibraryFunc();
  217. if ( !threadFunc )
  218. {
  219. HMODULE retVal = InternalLoadLibrary( str );
  220. if( retVal )
  221. {
  222. StackToolsNotify_LoadedLibrary( str );
  223. }
  224. #if 0 // you can enable this block to help track down why a module isn't loading:
  225. else
  226. {
  227. #ifdef _WINDOWS
  228. char buf[1024];
  229. FormatMessage(
  230. FORMAT_MESSAGE_FROM_SYSTEM |
  231. FORMAT_MESSAGE_IGNORE_INSERTS,
  232. NULL,
  233. GetLastError(),
  234. 0, // Default language
  235. (LPTSTR) buf,
  236. 1023,
  237. NULL // no insert arguments
  238. );
  239. Warning( "Could not load %s: %s\n", str, buf );
  240. #endif
  241. }
  242. #endif
  243. return retVal;
  244. }
  245. ThreadedLoadLibaryContext_t context;
  246. context.m_pLibraryName = str;
  247. context.m_hLibrary = 0;
  248. ThreadHandle_t h = CreateSimpleThread( ThreadedLoadLibraryFunc, &context );
  249. #ifdef _X360
  250. ThreadSetAffinity( h, XBOX_PROCESSOR_3 );
  251. #endif
  252. unsigned int nTimeout = 0;
  253. while( WaitForSingleObject( (HANDLE)h, nTimeout ) == WAIT_TIMEOUT )
  254. {
  255. nTimeout = threadFunc();
  256. }
  257. ReleaseThreadHandle( h );
  258. if( context.m_hLibrary )
  259. {
  260. g_nLoadLibraryError = 0;
  261. StackToolsNotify_LoadedLibrary( str );
  262. }
  263. else
  264. {
  265. g_nLoadLibraryError = context.m_nError;
  266. }
  267. return context.m_hLibrary;
  268. #elif defined( POSIX ) && !defined( _PS3 )
  269. HMODULE ret = (HMODULE)dlopen( str, RTLD_NOW );
  270. if ( ! ret )
  271. {
  272. const char *pError = dlerror();
  273. if ( pError && ( strstr( pError, "No such file" ) == 0 ) && ( strstr( pError, "image not found") == 0 ) )
  274. {
  275. Msg( " failed to dlopen %s error=%s\n", str, pError );
  276. }
  277. }
  278. // if( ret )
  279. // StackToolsNotify_LoadedLibrary( str );
  280. return ret;
  281. #endif
  282. #endif
  283. }
  284. static HMODULE Sys_LoadLibrary( const char *pLibraryName )
  285. {
  286. // load a library. If a library suffix is set, look for the library first with that name
  287. char *pSuffix = NULL;
  288. if ( CommandLine()->FindParm( "-xlsp" ) )
  289. {
  290. pSuffix = "_xlsp";
  291. }
  292. #ifdef POSIX
  293. else if ( CommandLine()->FindParm( "-valveinternal" ) )
  294. {
  295. pSuffix = "_valveinternal";
  296. }
  297. #endif
  298. #ifdef IS_WINDOWS_PC
  299. else if ( CommandLine()->FindParm( "-ds" ) ) // windows DS bins
  300. {
  301. pSuffix = "_ds";
  302. }
  303. #endif
  304. if ( pSuffix )
  305. {
  306. char nameBuf[MAX_PATH];
  307. strcpy( nameBuf, pLibraryName );
  308. char *pDot = strchr( nameBuf, '.' );
  309. if ( pDot )
  310. *pDot = 0;
  311. V_strncat( nameBuf, pSuffix, sizeof( nameBuf ), COPY_ALL_CHARACTERS );
  312. HMODULE hRet = Sys_LoadLibraryGuts( nameBuf );
  313. if ( hRet )
  314. return hRet;
  315. }
  316. return Sys_LoadLibraryGuts( pLibraryName );
  317. }
  318. //-----------------------------------------------------------------------------
  319. // Purpose: Keeps a flag if the current dll/exe loaded any debug modules
  320. // This flag can also get set if the current process discovers any other debug
  321. // modules loaded by other dlls
  322. //-----------------------------------------------------------------------------
  323. static bool s_bRunningWithDebugModules = false;
  324. #ifdef IS_WINDOWS_PC
  325. //-----------------------------------------------------------------------------
  326. // Purpose: Construct a process-specific name for kernel object to track
  327. // if any debug modules were loaded
  328. //-----------------------------------------------------------------------------
  329. static void DebugKernelMemoryObjectName( char *pszNameBuffer )
  330. {
  331. sprintf( pszNameBuffer, "VALVE-MODULE-DEBUG-%08X", GetCurrentProcessId() );
  332. }
  333. #endif
  334. //-----------------------------------------------------------------------------
  335. // Purpose: Loads a DLL/component from disk and returns a handle to it
  336. // Input : *pModuleName - filename of the component
  337. // Output : opaque handle to the module (hides system dependency)
  338. //-----------------------------------------------------------------------------
  339. CSysModule *Sys_LoadModule( const char *pModuleName )
  340. {
  341. // If using the Steam filesystem, either the DLL must be a minimum footprint
  342. // file in the depot (MFP) or a filesystem GetLocalCopy() call must be made
  343. // prior to the call to this routine.
  344. HMODULE hDLL = NULL;
  345. char alteredFilename[ MAX_PATH ];
  346. if ( IsPS3() )
  347. {
  348. // PS3's load module *must* be fed extensions. If the extension is missing, add it.
  349. if (!( strstr(pModuleName, ".sprx") || strstr(pModuleName, ".prx") ))
  350. {
  351. strncpy( alteredFilename, pModuleName, MAX_PATH );
  352. strncat( alteredFilename, DLL_EXT_STRING, MAX_PATH );
  353. pModuleName = alteredFilename;
  354. }
  355. }
  356. else
  357. {
  358. alteredFilename; // just to quash the warning
  359. }
  360. if ( !V_IsAbsolutePath( pModuleName ) )
  361. {
  362. // full path wasn't passed in, using the current working dir
  363. char szAbsoluteModuleName[1024];
  364. #if defined( _PS3 )
  365. // getcwd not supported on ps3; use PRX PATCH path if patched
  366. if ( g_pPS3PathInfo->IsPatched() )
  367. {
  368. V_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/bin/%s",
  369. g_pPS3PathInfo->GamePatchBasePath(), pModuleName );
  370. hDLL = Sys_LoadLibrary( szAbsoluteModuleName );
  371. }
  372. if ( !hDLL ) // use base PRX path
  373. {
  374. V_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/%s",
  375. g_pPS3PathInfo->PrxPath(), pModuleName );
  376. hDLL = Sys_LoadLibrary( szAbsoluteModuleName );
  377. }
  378. #else // !_PS3
  379. char szCwd[1024];
  380. _getcwd( szCwd, sizeof( szCwd ) );
  381. if ( IsX360() )
  382. {
  383. int i = CommandLine()->FindParm( "-basedir" );
  384. if ( i )
  385. {
  386. strcpy( szCwd, CommandLine()->GetParm( i+1 ) );
  387. }
  388. }
  389. if (szCwd[strlen(szCwd) - 1] == '/' || szCwd[strlen(szCwd) - 1] == '\\' )
  390. {
  391. szCwd[strlen(szCwd) - 1] = 0;
  392. }
  393. size_t cCwd = strlen( szCwd );
  394. if ( strstr( pModuleName, "bin/") == pModuleName || ( szCwd[ cCwd - 1 ] == 'n' && szCwd[ cCwd - 2 ] == 'i' && szCwd[ cCwd - 3 ] == 'b' ) )
  395. {
  396. // don't make bin/bin path
  397. V_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/%s", szCwd, pModuleName );
  398. }
  399. else
  400. {
  401. V_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/bin/%s", szCwd, pModuleName );
  402. }
  403. hDLL = Sys_LoadLibrary( szAbsoluteModuleName );
  404. #endif // _PS3
  405. }
  406. if ( !hDLL )
  407. {
  408. // full path failed, let LoadLibrary() try to search the PATH now
  409. hDLL = Sys_LoadLibrary( pModuleName );
  410. #if defined( _DEBUG )
  411. if ( !hDLL )
  412. {
  413. // So you can see what the error is in the debugger...
  414. #if defined( _WIN32 ) && !defined( _X360 )
  415. char *lpMsgBuf;
  416. FormatMessage(
  417. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  418. FORMAT_MESSAGE_FROM_SYSTEM |
  419. FORMAT_MESSAGE_IGNORE_INSERTS,
  420. NULL,
  421. GetLastError(),
  422. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  423. (LPTSTR) &lpMsgBuf,
  424. 0,
  425. NULL
  426. );
  427. LocalFree( (HLOCAL)lpMsgBuf );
  428. #elif defined( _X360 )
  429. DWORD error = g_nLoadLibraryError ? g_nLoadLibraryError : GetLastError();
  430. Msg( "Error(%d) - Failed to load %s:\n", error, pModuleName );
  431. #elif defined( _PS3 )
  432. Msg( "Failed to load %s:\n", pModuleName );
  433. #else
  434. Msg( "Failed to load %s: %s\n", pModuleName, dlerror() );
  435. #endif // _WIN32
  436. }
  437. #endif // DEBUG
  438. }
  439. // If running in the debugger, assume debug binaries are okay, otherwise they must run with -allowdebug
  440. if ( !IsGameConsole() && Sys_GetProcAddress( hDLL, "BuiltDebug" ) )
  441. {
  442. if ( hDLL && !CommandLine()->FindParm( "-allowdebug" ) &&
  443. !Sys_IsDebuggerPresent() )
  444. {
  445. Error( "Module %s is a debug build\n", pModuleName );
  446. }
  447. DevWarning( "Module %s is a debug build\n", pModuleName );
  448. if ( !s_bRunningWithDebugModules )
  449. {
  450. s_bRunningWithDebugModules = true;
  451. #ifdef IS_WINDOWS_PC
  452. char chMemoryName[ MAX_PATH ];
  453. DebugKernelMemoryObjectName( chMemoryName );
  454. (void) CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, chMemoryName );
  455. // Created a shared memory kernel object specific to process id
  456. // Existence of this object indicates that we have debug modules loaded
  457. #endif
  458. }
  459. }
  460. return reinterpret_cast<CSysModule *>(hDLL);
  461. }
  462. //-----------------------------------------------------------------------------
  463. // Purpose: Determine if any debug modules were loaded
  464. //-----------------------------------------------------------------------------
  465. bool Sys_RunningWithDebugModules()
  466. {
  467. if ( !s_bRunningWithDebugModules )
  468. {
  469. #ifdef IS_WINDOWS_PC
  470. char chMemoryName[ MAX_PATH ];
  471. DebugKernelMemoryObjectName( chMemoryName );
  472. HANDLE hObject = OpenFileMapping( FILE_MAP_READ, FALSE, chMemoryName );
  473. if ( hObject && hObject != INVALID_HANDLE_VALUE )
  474. {
  475. CloseHandle( hObject );
  476. s_bRunningWithDebugModules = true;
  477. }
  478. #endif
  479. }
  480. return s_bRunningWithDebugModules;
  481. }
  482. //-----------------------------------------------------------------------------
  483. // Purpose: Unloads a DLL/component from
  484. // Input : *pModuleName - filename of the component
  485. // Output : opaque handle to the module (hides system dependency)
  486. //-----------------------------------------------------------------------------
  487. void Sys_UnloadModule( CSysModule *pModule )
  488. {
  489. if ( !pModule )
  490. return;
  491. HMODULE hDLL = reinterpret_cast<HMODULE>(pModule);
  492. #ifdef _WIN32
  493. FreeLibrary( hDLL );
  494. #elif defined( _PS3 )
  495. PS3_PrxUnload( ( ( PS3_PrxLoadParametersBase_t *)pModule )->sysPrxId );
  496. delete ( PS3_PrxLoadParametersBase_t *)pModule;
  497. #elif defined( POSIX )
  498. dlclose((void *)hDLL);
  499. #endif
  500. }
  501. //-----------------------------------------------------------------------------
  502. // Purpose: returns a pointer to a function, given a module
  503. // Input : module - windows HMODULE from Sys_LoadModule()
  504. // *pName - proc name
  505. // Output : factory for this module
  506. //-----------------------------------------------------------------------------
  507. CreateInterfaceFn Sys_GetFactory( CSysModule *pModule )
  508. {
  509. if ( !pModule )
  510. return NULL;
  511. HMODULE hDLL = reinterpret_cast<HMODULE>(pModule);
  512. #ifdef _WIN32
  513. return reinterpret_cast<CreateInterfaceFn>(GetProcAddress( hDLL, CREATEINTERFACE_PROCNAME ));
  514. #elif defined( _PS3 )
  515. return reinterpret_cast<CreateInterfaceFn>(Sys_GetProcAddress( hDLL, CREATEINTERFACE_PROCNAME ));
  516. #elif defined( POSIX )
  517. // Linux gives this error:
  518. //../public/interface.cpp: In function `IBaseInterface *(*Sys_GetFactory
  519. //(CSysModule *)) (const char *, int *)':
  520. //../public/interface.cpp:154: ISO C++ forbids casting between
  521. //pointer-to-function and pointer-to-object
  522. //
  523. // so lets get around it :)
  524. return (CreateInterfaceFn)(GetProcAddress( (void *)hDLL, CREATEINTERFACE_PROCNAME ));
  525. #endif
  526. }
  527. //-----------------------------------------------------------------------------
  528. // Purpose: returns the instance of this module
  529. // Output : interface_instance_t
  530. //-----------------------------------------------------------------------------
  531. CreateInterfaceFn Sys_GetFactoryThis( void )
  532. {
  533. return &CreateInterfaceInternal;
  534. }
  535. //-----------------------------------------------------------------------------
  536. // Purpose: returns the instance of the named module
  537. // Input : *pModuleName - name of the module
  538. // Output : interface_instance_t - instance of that module
  539. //-----------------------------------------------------------------------------
  540. CreateInterfaceFn Sys_GetFactory( const char *pModuleName )
  541. {
  542. #ifdef _WIN32
  543. return static_cast<CreateInterfaceFn>( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) );
  544. #elif defined( _PS3 )
  545. Assert( 0 );
  546. return NULL;
  547. #elif defined(POSIX)
  548. // see Sys_GetFactory( CSysModule *pModule ) for an explanation
  549. return (CreateInterfaceFn)( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) );
  550. #endif
  551. }
  552. //-----------------------------------------------------------------------------
  553. // Purpose: get the interface for the specified module and version
  554. // Input :
  555. // Output :
  556. //-----------------------------------------------------------------------------
  557. bool Sys_LoadInterface(
  558. const char *pModuleName,
  559. const char *pInterfaceVersionName,
  560. CSysModule **pOutModule,
  561. void **pOutInterface )
  562. {
  563. CSysModule *pMod = Sys_LoadModule( pModuleName );
  564. if ( !pMod )
  565. return false;
  566. CreateInterfaceFn fn = Sys_GetFactory( pMod );
  567. if ( !fn )
  568. {
  569. Sys_UnloadModule( pMod );
  570. return false;
  571. }
  572. *pOutInterface = fn( pInterfaceVersionName, NULL );
  573. if ( !( *pOutInterface ) )
  574. {
  575. Sys_UnloadModule( pMod );
  576. return false;
  577. }
  578. if ( pOutModule )
  579. *pOutModule = pMod;
  580. return true;
  581. }
  582. //-----------------------------------------------------------------------------
  583. // Purpose: Place this as a singleton at module scope (e.g.) and use it to get the factory from the specified module name.
  584. //
  585. // When the singleton goes out of scope (.dll unload if at module scope),
  586. // then it'll call Sys_UnloadModule on the module so that the refcount is decremented
  587. // and the .dll actually can unload from memory.
  588. //-----------------------------------------------------------------------------
  589. CDllDemandLoader::CDllDemandLoader( char const *pchModuleName ) :
  590. m_pchModuleName( pchModuleName ),
  591. m_hModule( 0 ),
  592. m_bLoadAttempted( false )
  593. {
  594. }
  595. CDllDemandLoader::~CDllDemandLoader()
  596. {
  597. Unload();
  598. }
  599. CreateInterfaceFn CDllDemandLoader::GetFactory()
  600. {
  601. if ( !m_hModule && !m_bLoadAttempted )
  602. {
  603. m_bLoadAttempted = true;
  604. m_hModule = Sys_LoadModule( m_pchModuleName );
  605. }
  606. if ( !m_hModule )
  607. {
  608. return NULL;
  609. }
  610. return Sys_GetFactory( m_hModule );
  611. }
  612. void CDllDemandLoader::Unload()
  613. {
  614. if ( m_hModule )
  615. {
  616. Sys_UnloadModule( m_hModule );
  617. m_hModule = 0;
  618. }
  619. }