csgo-2018-source/tier0/platform_com.cpp

225 lines
5.8 KiB
C++
Raw Normal View History

2021-07-25 12:11:47 +08:00
//=========== (C) Copyright 2015 Valve, L.L.C. All rights reserved. ===========
//
// The copyright to the contents herein is the property of Valve, L.L.C.
// The contents may be used and/or copied only with the written permission of
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// Shares dynamic loading of COM/ole32/oleaut32 out of tier0.
//=============================================================================
#include "tier0/platform_com.h"
#include "tier0/threadtools.h"
#ifdef PLATFORM_WINDOWS
typedef int32 ThreadInitOnce_t;
typedef class CSysModule* PlatModule_t;
#define PLAT_MODULE_INVALID ( (PlatModule_t)0 )
static PlatCOMFunctions_t g_COMFunctions;
static PlatModule_t g_hCOM;
static ThreadInitOnce_t g_COMFunctionsInit;
static const char *g_COMFunctionNames[] =
{
"CoInitializeEx",
"CoUninitialize",
"CoCreateInstance",
"CoTaskMemAlloc",
"CoTaskMemRealloc",
"CoTaskMemFree",
};
enum PlatGetProcAddressesFlags_t
{
k_nPlatGetProcAddresses_Default = 0x00000000,
k_nPlatGetProcAddresses_Optional = 0x00000001,
};
// Plat_GetProcAddresses copied from Source2 platform.cpp
// Added here to avoid changing platform.h...
void *Plat_GetProcAddresses( const char *pModuleName,
int nNames,
const char **pNames,
size_t nTotalPointerBytes,
void *pPointers,
size_t nTotalFlagsBytes,
uint32 *pFlags,
bool bFailFatal )
{
if ( (nTotalPointerBytes & (sizeof( void* ) - 1)) != 0 )
{
Plat_FatalError( "%s: invalid pointer byte count\n", __FUNCTION__ );
}
if ( (size_t)nNames != nTotalPointerBytes / sizeof( void* ) )
{
Plat_FatalError( "%s: different number of names and pointers\n", __FUNCTION__ );
}
if ( (nTotalFlagsBytes & (sizeof( *pFlags ) - 1)) != 0 )
{
Plat_FatalError( "%s: invalid flag byte count\n", __FUNCTION__ );
}
if ( pFlags )
{
if ( (size_t)nNames != nTotalFlagsBytes / sizeof( *pFlags ) )
{
Plat_FatalError( "%s: different number of names and flags\n", __FUNCTION__ );
}
}
HMODULE hModule = ::LoadLibrary( pModuleName );
if ( hModule == 0 )
{
if ( bFailFatal )
{
int nErr = GetLastError();
Plat_FatalError( "%s: unable to load '%s', error %d\n", __FUNCTION__, pModuleName, nErr );
}
return NULL;
}
void** pFunc = (void**)pPointers;
for ( int i = 0; i < nNames; i++ )
{
uint32 nFlags = pFlags ? pFlags[i] : 0;
*pFunc = ::GetProcAddress( hModule, pNames[i] );
if ( !*pFunc &&
(nFlags & k_nPlatGetProcAddresses_Optional) == 0 )
{
if ( bFailFatal )
{
Plat_FatalError( "%s: unable to find %s in '%s'\n", __FUNCTION__, pNames[i], pModuleName );
}
::FreeLibrary( hModule );
memset( pPointers, 0, nTotalPointerBytes );
return NULL;
}
pFunc++;
}
return hModule;
}
static bool Plat_LoadCOM_Once( ThreadInitOnce_t *pMarker )
{
const char *pCOMName = "ole32.dll";
g_hCOM = (PlatModule_t)Plat_GetProcAddresses( pCOMName,
ARRAYSIZE( g_COMFunctionNames ),
g_COMFunctionNames,
sizeof( g_COMFunctions ),
&g_COMFunctions,
0,
NULL,
false );
// We always succeed in this routine as we
// handle failure at a higher level.
return true;
}
PlatCOMFunctions_t *Plat_LoadCOM()
{
ThreadInitOnceCall( &g_COMFunctionsInit, Plat_LoadCOM_Once );
return &g_COMFunctions;
}
PlatCOMFunctions_t *Plat_CheckCOM()
{
if ( g_hCOM == PLAT_MODULE_INVALID )
{
return NULL;
}
return &g_COMFunctions;
}
PlatCOMFunctions_t *Plat_RequireCOM()
{
if ( g_hCOM == PLAT_MODULE_INVALID )
{
Plat_FatalError( "Unable to load COM\n" );
}
return &g_COMFunctions;
}
void Plat_UnloadCOM()
{
// We do not unload COM currently but we have a stub
// that callers should use so that we can drop in unloading
// if we need it in the future.
}
static PlatOleAutFunctions_t g_OleAutFunctions;
static PlatModule_t g_hOleAut;
static ThreadInitOnce_t g_OleAutFunctionsInit;
static const char *g_OleAutFunctionNames[] =
{
"VariantInit",
"VariantClear",
"VariantCopy",
"SysAllocString",
"SysAllocStringByteLen",
"SysAllocStringLen",
"SysFreeString",
"SysReAllocString",
"SysReAllocStringLen",
"SysStringByteLen",
"SysStringLen",
};
static bool Plat_LoadOleAut_Once( ThreadInitOnce_t *pMarker )
{
const char *pOleAutName = "oleaut32.dll";
g_hOleAut = (PlatModule_t)Plat_GetProcAddresses( pOleAutName,
ARRAYSIZE( g_OleAutFunctionNames ),
g_OleAutFunctionNames,
sizeof( g_OleAutFunctions ),
&g_OleAutFunctions,
0,
NULL,
false );
// We always succeed in this routine as we
// handle failure at a higher level.
return true;
}
PlatOleAutFunctions_t *Plat_LoadOleAut()
{
ThreadInitOnceCall( &g_OleAutFunctionsInit, Plat_LoadOleAut_Once );
return &g_OleAutFunctions;
}
PlatOleAutFunctions_t *Plat_CheckOleAut()
{
if ( g_hOleAut == PLAT_MODULE_INVALID )
{
return NULL;
}
return &g_OleAutFunctions;
}
PlatOleAutFunctions_t *Plat_RequireOleAut()
{
if ( g_hOleAut == PLAT_MODULE_INVALID )
{
Plat_FatalError( "Unable to load oleaut32\n" );
}
return &g_OleAutFunctions;
}
void Plat_UnloadOleAut()
{
// We do not unload oleaut32 currently but we have a stub
// that callers should use so that we can drop in unloading
// if we need it in the future.
}
#endif // #ifdef PLATFORM_WINDOWS