Counter Strike : Global Offensive Source Code
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.

701 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. HMODULE result = LoadLibrary( pName );
  174. if (result == NULL)
  175. {
  176. Warning( "Failed to load library %s: %d\n", pName, GetLastError() );
  177. }
  178. return result;
  179. #else
  180. return LoadLibraryEx( pName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
  181. #endif
  182. }
  183. uintp ThreadedLoadLibraryFunc( void *pParam )
  184. {
  185. ThreadedLoadLibaryContext_t *pContext = (ThreadedLoadLibaryContext_t*)pParam;
  186. pContext->m_hLibrary = InternalLoadLibrary(pContext->m_pLibraryName);
  187. return 0;
  188. }
  189. #endif
  190. // global to propagate a library load error from thread into Sys_LoadModule
  191. static DWORD g_nLoadLibraryError = 0;
  192. static HMODULE Sys_LoadLibraryGuts( const char *pLibraryName )
  193. {
  194. #ifdef PLATFORM_PS3
  195. PS3_LoadAppSystemInterface_Parameters_t *pPRX = new PS3_LoadAppSystemInterface_Parameters_t;
  196. Q_memset( pPRX, 0, sizeof( PS3_LoadAppSystemInterface_Parameters_t ) );
  197. pPRX->cbSize = sizeof( PS3_LoadAppSystemInterface_Parameters_t );
  198. int iResult = PS3_PrxLoad( pLibraryName, pPRX );
  199. if ( iResult < CELL_OK )
  200. {
  201. delete pPRX;
  202. return NULL;
  203. }
  204. return reinterpret_cast< HMODULE >( pPRX );
  205. #else
  206. char str[1024];
  207. // How to get a string out of a #define on the command line.
  208. const char *pModuleExtension = DLL_EXT_STRING;
  209. const char *pModuleAddition = pModuleExtension;
  210. Q_strncpy( str, pLibraryName, sizeof(str) );
  211. if ( !Q_stristr( str, pModuleExtension ) )
  212. {
  213. if ( IsX360() )
  214. {
  215. Q_StripExtension( str, str, sizeof(str) );
  216. }
  217. Q_strncat( str, pModuleAddition, sizeof(str) );
  218. }
  219. Q_FixSlashes( str );
  220. #ifdef _WIN32
  221. ThreadedLoadLibraryFunc_t threadFunc = GetThreadedLoadLibraryFunc();
  222. if ( !threadFunc )
  223. {
  224. HMODULE retVal = InternalLoadLibrary( str );
  225. if( retVal )
  226. {
  227. StackToolsNotify_LoadedLibrary( str );
  228. }
  229. #if 0 // you can enable this block to help track down why a module isn't loading:
  230. else
  231. {
  232. #ifdef _WINDOWS
  233. char buf[1024];
  234. FormatMessage(
  235. FORMAT_MESSAGE_FROM_SYSTEM |
  236. FORMAT_MESSAGE_IGNORE_INSERTS,
  237. NULL,
  238. GetLastError(),
  239. 0, // Default language
  240. (LPTSTR) buf,
  241. 1023,
  242. NULL // no insert arguments
  243. );
  244. Warning( "Could not load %s: %s\n", str, buf );
  245. #endif
  246. }
  247. #endif
  248. return retVal;
  249. }
  250. ThreadedLoadLibaryContext_t context;
  251. context.m_pLibraryName = str;
  252. context.m_hLibrary = 0;
  253. ThreadHandle_t h = CreateSimpleThread( ThreadedLoadLibraryFunc, &context );
  254. #ifdef _X360
  255. ThreadSetAffinity( h, XBOX_PROCESSOR_3 );
  256. #endif
  257. unsigned int nTimeout = 0;
  258. while( WaitForSingleObject( (HANDLE)h, nTimeout ) == WAIT_TIMEOUT )
  259. {
  260. nTimeout = threadFunc();
  261. }
  262. ReleaseThreadHandle( h );
  263. if( context.m_hLibrary )
  264. {
  265. g_nLoadLibraryError = 0;
  266. StackToolsNotify_LoadedLibrary( str );
  267. }
  268. else
  269. {
  270. g_nLoadLibraryError = context.m_nError;
  271. }
  272. return context.m_hLibrary;
  273. #elif defined( POSIX ) && !defined( _PS3 )
  274. HMODULE ret = (HMODULE)dlopen( str, RTLD_NOW );
  275. if ( ! ret )
  276. {
  277. const char *pError = dlerror();
  278. if ( pError && ( strstr( pError, "No such file" ) == 0 ) && ( strstr( pError, "image not found") == 0 ) )
  279. {
  280. Msg( " failed to dlopen %s error=%s\n", str, pError );
  281. }
  282. }
  283. // if( ret )
  284. // StackToolsNotify_LoadedLibrary( str );
  285. return ret;
  286. #endif
  287. #endif
  288. }
  289. static HMODULE Sys_LoadLibrary( const char *pLibraryName )
  290. {
  291. // load a library. If a library suffix is set, look for the library first with that name
  292. char *pSuffix = NULL;
  293. if ( CommandLine()->FindParm( "-xlsp" ) )
  294. {
  295. pSuffix = "_xlsp";
  296. }
  297. #ifdef POSIX
  298. else if ( CommandLine()->FindParm( "-valveinternal" ) )
  299. {
  300. pSuffix = "_valveinternal";
  301. }
  302. #endif
  303. #ifdef IS_WINDOWS_PC
  304. else if ( CommandLine()->FindParm( "-ds" ) ) // windows DS bins
  305. {
  306. pSuffix = "_ds";
  307. }
  308. #endif
  309. if ( pSuffix )
  310. {
  311. char nameBuf[MAX_PATH];
  312. strcpy( nameBuf, pLibraryName );
  313. char *pDot = strchr( nameBuf, '.' );
  314. if ( pDot )
  315. *pDot = 0;
  316. V_strncat( nameBuf, pSuffix, sizeof( nameBuf ), COPY_ALL_CHARACTERS );
  317. HMODULE hRet = Sys_LoadLibraryGuts( nameBuf );
  318. if ( hRet )
  319. return hRet;
  320. }
  321. return Sys_LoadLibraryGuts( pLibraryName );
  322. }
  323. //-----------------------------------------------------------------------------
  324. // Purpose: Keeps a flag if the current dll/exe loaded any debug modules
  325. // This flag can also get set if the current process discovers any other debug
  326. // modules loaded by other dlls
  327. //-----------------------------------------------------------------------------
  328. static bool s_bRunningWithDebugModules = false;
  329. #ifdef IS_WINDOWS_PC
  330. //-----------------------------------------------------------------------------
  331. // Purpose: Construct a process-specific name for kernel object to track
  332. // if any debug modules were loaded
  333. //-----------------------------------------------------------------------------
  334. static void DebugKernelMemoryObjectName( char *pszNameBuffer )
  335. {
  336. sprintf( pszNameBuffer, "VALVE-MODULE-DEBUG-%08X", GetCurrentProcessId() );
  337. }
  338. #endif
  339. //-----------------------------------------------------------------------------
  340. // Purpose: Loads a DLL/component from disk and returns a handle to it
  341. // Input : *pModuleName - filename of the component
  342. // Output : opaque handle to the module (hides system dependency)
  343. //-----------------------------------------------------------------------------
  344. CSysModule *Sys_LoadModule( const char *pModuleName )
  345. {
  346. // If using the Steam filesystem, either the DLL must be a minimum footprint
  347. // file in the depot (MFP) or a filesystem GetLocalCopy() call must be made
  348. // prior to the call to this routine.
  349. HMODULE hDLL = NULL;
  350. char alteredFilename[ MAX_PATH ];
  351. if ( IsPS3() )
  352. {
  353. // PS3's load module *must* be fed extensions. If the extension is missing, add it.
  354. if (!( strstr(pModuleName, ".sprx") || strstr(pModuleName, ".prx") ))
  355. {
  356. strncpy( alteredFilename, pModuleName, MAX_PATH );
  357. strncat( alteredFilename, DLL_EXT_STRING, MAX_PATH );
  358. pModuleName = alteredFilename;
  359. }
  360. }
  361. else
  362. {
  363. alteredFilename; // just to quash the warning
  364. }
  365. if ( !Q_IsAbsolutePath( pModuleName ) )
  366. {
  367. // full path wasn't passed in, using the current working dir
  368. char szAbsoluteModuleName[1024];
  369. #if defined( _PS3 )
  370. // getcwd not supported on ps3; use PRX path instead (TODO: fallback to DISK path too)
  371. Q_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/%s",
  372. g_pPS3PathInfo->PrxPath(), pModuleName );
  373. hDLL = Sys_LoadLibrary( szAbsoluteModuleName );
  374. #else // !_PS3
  375. char szCwd[1024];
  376. _getcwd( szCwd, sizeof( szCwd ) );
  377. if ( IsX360() )
  378. {
  379. int i = CommandLine()->FindParm( "-basedir" );
  380. if ( i )
  381. {
  382. strcpy( szCwd, CommandLine()->GetParm( i+1 ) );
  383. }
  384. }
  385. if (szCwd[strlen(szCwd) - 1] == '/' || szCwd[strlen(szCwd) - 1] == '\\' )
  386. {
  387. szCwd[strlen(szCwd) - 1] = 0;
  388. }
  389. size_t cCwd = strlen( szCwd );
  390. if ( strstr( pModuleName, "bin/") == pModuleName || ( szCwd[ cCwd - 1 ] == 'n' && szCwd[ cCwd - 2 ] == 'i' && szCwd[ cCwd - 3 ] == 'b' ) )
  391. {
  392. // don't make bin/bin path
  393. Q_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/%s", szCwd, pModuleName );
  394. }
  395. else
  396. {
  397. Q_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/bin/%s", szCwd, pModuleName );
  398. }
  399. hDLL = Sys_LoadLibrary( szAbsoluteModuleName );
  400. #endif // _PS3
  401. }
  402. if ( !hDLL )
  403. {
  404. // full path failed, let LoadLibrary() try to search the PATH now
  405. hDLL = Sys_LoadLibrary( pModuleName );
  406. #if defined( _DEBUG )
  407. if ( !hDLL )
  408. {
  409. // So you can see what the error is in the debugger...
  410. #if defined( _WIN32 ) && !defined( _X360 )
  411. char *lpMsgBuf;
  412. FormatMessage(
  413. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  414. FORMAT_MESSAGE_FROM_SYSTEM |
  415. FORMAT_MESSAGE_IGNORE_INSERTS,
  416. NULL,
  417. GetLastError(),
  418. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  419. (LPTSTR) &lpMsgBuf,
  420. 0,
  421. NULL
  422. );
  423. LocalFree( (HLOCAL)lpMsgBuf );
  424. #elif defined( _X360 )
  425. DWORD error = g_nLoadLibraryError ? g_nLoadLibraryError : GetLastError();
  426. Msg( "Error(%d) - Failed to load %s:\n", error, pModuleName );
  427. #elif defined( _PS3 )
  428. Msg( "Failed to load %s:\n", pModuleName );
  429. #else
  430. Msg( "Failed to load %s: %s\n", pModuleName, dlerror() );
  431. #endif // _WIN32
  432. }
  433. #endif // DEBUG
  434. }
  435. // If running in the debugger, assume debug binaries are okay, otherwise they must run with -allowdebug
  436. if ( !IsGameConsole() && Sys_GetProcAddress( hDLL, "BuiltDebug" ) )
  437. {
  438. if ( hDLL && !CommandLine()->FindParm( "-allowdebug" ) &&
  439. !Sys_IsDebuggerPresent() )
  440. {
  441. Error( "Module %s is a debug build\n", pModuleName );
  442. }
  443. DevWarning( "Module %s is a debug build\n", pModuleName );
  444. if ( !s_bRunningWithDebugModules )
  445. {
  446. s_bRunningWithDebugModules = true;
  447. #ifdef IS_WINDOWS_PC
  448. char chMemoryName[ MAX_PATH ];
  449. DebugKernelMemoryObjectName( chMemoryName );
  450. (void) CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, chMemoryName );
  451. // Created a shared memory kernel object specific to process id
  452. // Existence of this object indicates that we have debug modules loaded
  453. #endif
  454. }
  455. }
  456. return reinterpret_cast<CSysModule *>(hDLL);
  457. }
  458. //-----------------------------------------------------------------------------
  459. // Purpose: Determine if any debug modules were loaded
  460. //-----------------------------------------------------------------------------
  461. bool Sys_RunningWithDebugModules()
  462. {
  463. if ( !s_bRunningWithDebugModules )
  464. {
  465. #ifdef IS_WINDOWS_PC
  466. char chMemoryName[ MAX_PATH ];
  467. DebugKernelMemoryObjectName( chMemoryName );
  468. HANDLE hObject = OpenFileMapping( FILE_MAP_READ, FALSE, chMemoryName );
  469. if ( hObject && hObject != INVALID_HANDLE_VALUE )
  470. {
  471. CloseHandle( hObject );
  472. s_bRunningWithDebugModules = true;
  473. }
  474. #endif
  475. }
  476. return s_bRunningWithDebugModules;
  477. }
  478. //-----------------------------------------------------------------------------
  479. // Purpose: Unloads a DLL/component from
  480. // Input : *pModuleName - filename of the component
  481. // Output : opaque handle to the module (hides system dependency)
  482. //-----------------------------------------------------------------------------
  483. void Sys_UnloadModule( CSysModule *pModule )
  484. {
  485. if ( !pModule )
  486. return;
  487. HMODULE hDLL = reinterpret_cast<HMODULE>(pModule);
  488. #ifdef _WIN32
  489. FreeLibrary( hDLL );
  490. #elif defined( _PS3 )
  491. PS3_PrxUnload( ( ( PS3_PrxLoadParametersBase_t *)pModule )->sysPrxId );
  492. delete ( PS3_PrxLoadParametersBase_t *)pModule;
  493. #elif defined( POSIX )
  494. //$$$$$$ mikesart: for testing with valgrind don't unload so... dlclose((void *)hDLL);
  495. #endif
  496. }
  497. //-----------------------------------------------------------------------------
  498. // Purpose: returns a pointer to a function, given a module
  499. // Input : module - windows HMODULE from Sys_LoadModule()
  500. // *pName - proc name
  501. // Output : factory for this module
  502. //-----------------------------------------------------------------------------
  503. CreateInterfaceFn Sys_GetFactory( CSysModule *pModule )
  504. {
  505. if ( !pModule )
  506. return NULL;
  507. HMODULE hDLL = reinterpret_cast<HMODULE>(pModule);
  508. #ifdef _WIN32
  509. return reinterpret_cast<CreateInterfaceFn>(GetProcAddress( hDLL, CREATEINTERFACE_PROCNAME ));
  510. #elif defined( _PS3 )
  511. return reinterpret_cast<CreateInterfaceFn>(Sys_GetProcAddress( hDLL, CREATEINTERFACE_PROCNAME ));
  512. #elif defined( POSIX )
  513. // Linux gives this error:
  514. //../public/interface.cpp: In function `IBaseInterface *(*Sys_GetFactory
  515. //(CSysModule *)) (const char *, int *)':
  516. //../public/interface.cpp:154: ISO C++ forbids casting between
  517. //pointer-to-function and pointer-to-object
  518. //
  519. // so lets get around it :)
  520. return (CreateInterfaceFn)(GetProcAddress( (void *)hDLL, CREATEINTERFACE_PROCNAME ));
  521. #endif
  522. }
  523. //-----------------------------------------------------------------------------
  524. // Purpose: returns the instance of this module
  525. // Output : interface_instance_t
  526. //-----------------------------------------------------------------------------
  527. CreateInterfaceFn Sys_GetFactoryThis( void )
  528. {
  529. return &CreateInterfaceInternal;
  530. }
  531. //-----------------------------------------------------------------------------
  532. // Purpose: returns the instance of the named module
  533. // Input : *pModuleName - name of the module
  534. // Output : interface_instance_t - instance of that module
  535. //-----------------------------------------------------------------------------
  536. CreateInterfaceFn Sys_GetFactory( const char *pModuleName )
  537. {
  538. #ifdef _WIN32
  539. return static_cast<CreateInterfaceFn>( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) );
  540. #elif defined( _PS3 )
  541. Assert( 0 );
  542. return NULL;
  543. #elif defined(POSIX)
  544. // see Sys_GetFactory( CSysModule *pModule ) for an explanation
  545. return (CreateInterfaceFn)( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) );
  546. #endif
  547. }
  548. //-----------------------------------------------------------------------------
  549. // Purpose: get the interface for the specified module and version
  550. // Input :
  551. // Output :
  552. //-----------------------------------------------------------------------------
  553. bool Sys_LoadInterface(
  554. const char *pModuleName,
  555. const char *pInterfaceVersionName,
  556. CSysModule **pOutModule,
  557. void **pOutInterface )
  558. {
  559. CSysModule *pMod = Sys_LoadModule( pModuleName );
  560. if ( !pMod )
  561. return false;
  562. CreateInterfaceFn fn = Sys_GetFactory( pMod );
  563. if ( !fn )
  564. {
  565. Sys_UnloadModule( pMod );
  566. return false;
  567. }
  568. *pOutInterface = fn( pInterfaceVersionName, NULL );
  569. if ( !( *pOutInterface ) )
  570. {
  571. Sys_UnloadModule( pMod );
  572. return false;
  573. }
  574. if ( pOutModule )
  575. *pOutModule = pMod;
  576. return true;
  577. }
  578. //-----------------------------------------------------------------------------
  579. // Purpose: Place this as a singleton at module scope (e.g.) and use it to get the factory from the specified module name.
  580. //
  581. // When the singleton goes out of scope (.dll unload if at module scope),
  582. // then it'll call Sys_UnloadModule on the module so that the refcount is decremented
  583. // and the .dll actually can unload from memory.
  584. //-----------------------------------------------------------------------------
  585. CDllDemandLoader::CDllDemandLoader( char const *pchModuleName ) :
  586. m_pchModuleName( pchModuleName ),
  587. m_hModule( 0 ),
  588. m_bLoadAttempted( false )
  589. {
  590. }
  591. CDllDemandLoader::~CDllDemandLoader()
  592. {
  593. Unload();
  594. }
  595. CreateInterfaceFn CDllDemandLoader::GetFactory()
  596. {
  597. if ( !m_hModule && !m_bLoadAttempted )
  598. {
  599. m_bLoadAttempted = true;
  600. m_hModule = Sys_LoadModule( m_pchModuleName );
  601. }
  602. if ( !m_hModule )
  603. {
  604. return NULL;
  605. }
  606. return Sys_GetFactory( m_hModule );
  607. }
  608. void CDllDemandLoader::Unload()
  609. {
  610. if ( m_hModule )
  611. {
  612. Sys_UnloadModule( m_hModule );
  613. m_hModule = 0;
  614. }
  615. }