2017-12-21 07:45:38 +08:00
/*
2025-01-14 19:02:26 +08:00
* Copyright ( C ) 2019 - 2025 Intel Corporation
2017-12-21 07:45:38 +08:00
*
2018-09-18 15:11:08 +08:00
* SPDX - License - Identifier : MIT
2017-12-21 07:45:38 +08:00
*
*/
2020-02-24 05:44:01 +08:00
# include "shared/source/os_interface/windows/os_library_win.h"
2017-12-21 07:45:38 +08:00
2024-12-20 00:56:46 +08:00
# include "shared/source/helpers/debug_helpers.h"
# include "shared/source/os_interface/windows/sys_calls.h"
# include <iomanip>
# include <regex>
# include <sstream>
2019-03-26 18:59:46 +08:00
namespace NEO {
2017-12-21 07:45:38 +08:00
2024-10-17 03:53:07 +08:00
OsLibrary * OsLibrary : : load ( const OsLibraryCreateProperties & properties ) {
Windows : : OsLibrary * ptr = new Windows : : OsLibrary ( properties ) ;
2017-12-21 07:45:38 +08:00
if ( ! ptr - > isLoaded ( ) ) {
delete ptr ;
return nullptr ;
}
return ptr ;
}
2020-10-30 20:42:13 +08:00
const std : : string OsLibrary : : createFullSystemPath ( const std : : string & name ) {
CHAR buff [ MAX_PATH ] ;
UINT ret = 0 ;
ret = Windows : : OsLibrary : : getSystemDirectoryA ( buff , MAX_PATH ) ;
buff [ ret ] = ' \\ ' ;
buff [ ret + 1 ] = 0 ;
strncat_s ( & buff [ 0 ] , sizeof ( buff ) , name . c_str ( ) , _TRUNCATE ) ;
return std : : string ( buff ) ;
}
2017-12-21 07:45:38 +08:00
namespace Windows {
2024-10-17 03:53:07 +08:00
decltype ( & GetModuleHandleA ) OsLibrary : : getModuleHandleA = GetModuleHandleA ;
2018-03-02 22:19:29 +08:00
decltype ( & LoadLibraryExA ) OsLibrary : : loadLibraryExA = LoadLibraryExA ;
decltype ( & GetModuleFileNameA ) OsLibrary : : getModuleFileNameA = GetModuleFileNameA ;
2020-10-30 20:42:13 +08:00
decltype ( & GetSystemDirectoryA ) OsLibrary : : getSystemDirectoryA = GetSystemDirectoryA ;
2024-10-17 03:53:07 +08:00
decltype ( & FreeLibrary ) OsLibrary : : freeLibrary = FreeLibrary ;
2018-03-02 22:19:29 +08:00
2023-12-04 18:06:44 +08:00
extern " C " IMAGE_DOS_HEADER __ImageBase ; // NOLINT(readability-identifier-naming)
2023-10-30 19:52:17 +08:00
__inline HINSTANCE getModuleHINSTANCE ( ) { return ( HINSTANCE ) & __ImageBase ; }
2018-03-07 16:11:53 +08:00
2021-03-12 09:01:51 +08:00
void OsLibrary : : getLastErrorString ( std : : string * errorValue ) {
DWORD errorID = GetLastError ( ) ;
if ( errorID & & errorValue ! = nullptr ) {
LPSTR tempErrorMessage = nullptr ;
FormatMessageA ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS ,
NULL , errorID , MAKELANGID ( LANG_NEUTRAL , SUBLANG_DEFAULT ) , ( LPSTR ) & tempErrorMessage , 0 , NULL ) ;
errorValue - > assign ( tempErrorMessage ) ;
LocalFree ( tempErrorMessage ) ;
}
}
2018-03-02 22:19:29 +08:00
HMODULE OsLibrary : : loadDependency ( const std : : string & dependencyFileName ) const {
char dllPath [ MAX_PATH ] ;
2023-10-30 19:52:17 +08:00
DWORD length = getModuleFileNameA ( getModuleHINSTANCE ( ) , dllPath , MAX_PATH ) ;
2018-03-02 22:19:29 +08:00
for ( DWORD idx = length ; idx > 0 ; idx - - ) {
if ( dllPath [ idx - 1 ] = = ' \\ ' ) {
dllPath [ idx ] = ' \0 ' ;
break ;
}
}
strcat_s ( dllPath , MAX_PATH , dependencyFileName . c_str ( ) ) ;
return loadLibraryExA ( dllPath , NULL , 0 ) ;
}
2017-12-21 07:45:38 +08:00
2024-10-17 03:53:07 +08:00
OsLibrary : : OsLibrary ( const OsLibraryCreateProperties & properties ) {
if ( properties . libraryName . empty ( ) ) {
this - > handle = getModuleHandleA ( nullptr ) ;
this - > selfOpen = true ;
2017-12-21 07:45:38 +08:00
} else {
2024-10-17 03:53:07 +08:00
if ( properties . performSelfLoad ) {
this - > handle = getModuleHandleA ( properties . libraryName . c_str ( ) ) ;
this - > selfOpen = true ;
} else {
this - > handle = loadDependency ( properties . libraryName ) ;
if ( this - > handle = = nullptr ) {
this - > handle = loadLibraryExA ( properties . libraryName . c_str ( ) , NULL , LOAD_LIBRARY_SEARCH_SYSTEM32 ) ;
2021-03-12 09:01:51 +08:00
}
2017-12-21 07:45:38 +08:00
}
2024-10-17 03:53:07 +08:00
if ( ( this - > handle = = nullptr ) & & ( properties . errorValue ! = nullptr ) ) {
getLastErrorString ( properties . errorValue ) ;
}
2017-12-21 07:45:38 +08:00
}
}
OsLibrary : : ~ OsLibrary ( ) {
2024-10-17 03:53:07 +08:00
if ( ! this - > selfOpen & & this - > handle ) {
freeLibrary ( this - > handle ) ;
2017-12-21 07:45:38 +08:00
this - > handle = nullptr ;
}
}
bool OsLibrary : : isLoaded ( ) {
return this - > handle ! = nullptr ;
}
void * OsLibrary : : getProcAddress ( const std : : string & procName ) {
2023-10-20 22:34:45 +08:00
return reinterpret_cast < void * > ( : : GetProcAddress ( this - > handle , procName . c_str ( ) ) ) ;
2017-12-21 07:45:38 +08:00
}
2023-08-21 20:00:06 +08:00
std : : string OsLibrary : : getFullPath ( ) {
char dllPath [ MAX_PATH ] ;
2023-10-30 19:52:17 +08:00
getModuleFileNameA ( getModuleHINSTANCE ( ) , dllPath , MAX_PATH ) ;
2023-08-21 20:00:06 +08:00
return std : : string ( dllPath ) ;
}
2018-06-13 03:54:39 +08:00
} // namespace Windows
2024-12-20 00:56:46 +08:00
bool getLoadedLibVersion ( const std : : string & libName , const std : : string & regexVersionPattern , std : : string & outVersion , std : : string & errReason ) {
HMODULE mod = NULL ;
auto ret = SysCalls : : getModuleHandleExW ( GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT , std : : wstring ( libName . begin ( ) , libName . end ( ) ) . c_str ( ) , & mod ) ;
if ( 0 = = ret ) {
errReason = " Failed to read info of " + libName + " - GetModuleHandleExA failed, GetLastError= " + std : : to_string ( SysCalls : : getLastError ( ) ) ;
return false ;
}
wchar_t path [ MAX_PATH ] ;
DWORD length = SysCalls : : getModuleFileNameW ( mod , path , MAX_PATH ) ;
if ( 0 = = length ) {
errReason = " Failed to read info of " + libName + " - GetModuleFileName failed, GetLastError= " + std : : to_string ( SysCalls : : getLastError ( ) ) ;
return false ;
}
std : : wstring trimmedPath = { path , length } ;
DWORD infoVersioSize = SysCalls : : getFileVersionInfoSizeW ( trimmedPath . c_str ( ) , nullptr ) ;
if ( 0 = = infoVersioSize ) {
errReason = " Failed to read info of " + libName + " - GetFileVersionInfoSize failed, GetLastError= " + std : : to_string ( SysCalls : : getLastError ( ) ) ;
return false ;
}
std : : vector < char > fileInformationBackingStorage ;
fileInformationBackingStorage . resize ( infoVersioSize ) ;
ret = SysCalls : : getFileVersionInfoW ( path , 0 , static_cast < DWORD > ( fileInformationBackingStorage . size ( ) ) , fileInformationBackingStorage . data ( ) ) ;
if ( 0 = = ret ) {
errReason = " Failed to read info of " + libName + " - GetFileVersionInfo failed, GetLastError= " + std : : to_string ( SysCalls : : getLastError ( ) ) ;
return false ;
}
struct LangCodePage {
WORD lang ;
WORD codePage ;
} ;
LangCodePage * translateInfo = nullptr ;
unsigned int langCodePagesSize = 0 ;
ret = SysCalls : : verQueryValueW ( fileInformationBackingStorage . data ( ) , L " \\ VarFileInfo \\ Translation " , reinterpret_cast < LPVOID * > ( & translateInfo ) , & langCodePagesSize ) ;
if ( 0 = = ret ) {
errReason = " Failed to read info of " + libName + " - VerQueryValue( \\ VarFileInfo \\ Translation) failed, GetLastError= " + std : : to_string ( SysCalls : : getLastError ( ) ) ;
return false ;
}
auto truncateWstringToString = [ ] ( const std : : wstring & ws ) {
std : : string ret ;
std : : transform ( ws . begin ( ) , ws . end ( ) , std : : back_inserter ( ret ) , [ ] ( wchar_t wc ) { return static_cast < char > ( wc ) ; } ) ;
return ret ;
} ;
size_t langCodePagesCount = ( langCodePagesSize / sizeof ( LangCodePage ) ) ;
std : : regex versionPattern { regexVersionPattern } ;
for ( size_t j = 0 ; j < langCodePagesCount ; + + j ) {
std : : wstringstream subBlockPath ;
subBlockPath < < L " \\ StringFileInfo \\ " ;
subBlockPath < < std : : setw ( 4 ) < < std : : setfill ( L ' 0 ' ) < < std : : hex < < translateInfo [ j ] . lang ;
subBlockPath < < std : : setw ( 4 ) < < std : : setfill ( L ' 0 ' ) < < std : : hex < < translateInfo [ j ] . codePage ;
subBlockPath < < L " \\ ProductVersion " ;
wchar_t * data ;
unsigned int len = 0 ;
ret = SysCalls : : verQueryValueW ( fileInformationBackingStorage . data ( ) , subBlockPath . str ( ) . c_str ( ) , ( LPVOID * ) & data , & len ) ;
if ( 0 = = ret ) {
errReason = " Failed to read info of " + libName + " - VerQueryValue( " + truncateWstringToString ( subBlockPath . str ( ) ) + " ) failed, GetLastError= " + std : : to_string ( SysCalls : : getLastError ( ) ) ;
return false ;
}
auto sdata = truncateWstringToString ( data ) ;
if ( std : : regex_search ( sdata , versionPattern ) ) {
2025-01-14 19:02:26 +08:00
outVersion = std : : move ( sdata ) ;
2024-12-20 00:56:46 +08:00
return true ;
}
}
errReason = " Could not find version info for " + std : : string ( libName ) + " that would satisfy expected pattern \n " ;
return false ;
}
2019-03-26 18:59:46 +08:00
} // namespace NEO