1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "system.h" 29 #include <tlhelp32.h> 30 31 #include "file_url.h" 32 #include "path_helper.hxx" 33 34 #include <osl/module.h> 35 #include <osl/diagnose.h> 36 #include <osl/thread.h> 37 #include <osl/file.h> 38 #include <rtl/logfile.h> 39 #include <vector> 40 41 /* 42 under WIN32, we use the void* oslModule 43 as a WIN32 HANDLE (which is also a 32-bit value) 44 */ 45 46 /*****************************************************************************/ 47 /* osl_loadModule */ 48 /*****************************************************************************/ 49 oslModule SAL_CALL osl_loadModule(rtl_uString *strModuleName, sal_Int32 nRtldMode ) 50 { 51 HINSTANCE hInstance; 52 UINT errorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); 53 rtl_uString* Module = NULL; 54 oslModule ret = 0; 55 oslFileError nError; 56 57 RTL_LOGFILE_TRACE1( "{ osl_loadModule start: %S", (LPTSTR)&strModuleName->buffer ); 58 59 OSL_ASSERT(strModuleName); 60 61 nRtldMode = nRtldMode; /* avoid warnings */ 62 63 nError = osl_getSystemPathFromFileURL(strModuleName, &Module); 64 65 if ( osl_File_E_None != nError ) 66 rtl_uString_assign(&Module, strModuleName); 67 68 hInstance = LoadLibraryW(reinterpret_cast<LPCWSTR>(Module->buffer)); 69 70 if (hInstance == NULL) 71 hInstance = LoadLibraryExW(reinterpret_cast<LPCWSTR>(Module->buffer), NULL, 72 LOAD_WITH_ALTERED_SEARCH_PATH); 73 74 //In case of long path names (\\?\c:\...) try to shorten the filename. 75 //LoadLibrary cannot handle file names which exceed 260 letters. 76 //In case the path is to long, the function will fail. However, the error 77 //code can be different. For example, it returned ERROR_FILENAME_EXCED_RANGE 78 //on Windows XP and ERROR_INSUFFICIENT_BUFFER on Windows 7 (64bit) 79 if (hInstance == NULL && Module->length > 260) 80 { 81 std::vector<WCHAR, rtl::Allocator<WCHAR> > vec(Module->length + 1); 82 DWORD len = GetShortPathNameW(reinterpret_cast<LPCWSTR>(Module->buffer), 83 &vec[0], Module->length + 1); 84 if (len ) 85 { 86 hInstance = LoadLibraryW(&vec[0]); 87 88 if (hInstance == NULL) 89 hInstance = LoadLibraryExW(&vec[0], NULL, 90 LOAD_WITH_ALTERED_SEARCH_PATH); 91 } 92 } 93 94 95 if (hInstance <= (HINSTANCE)HINSTANCE_ERROR) 96 hInstance = 0; 97 98 ret = (oslModule) hInstance; 99 rtl_uString_release(Module); 100 SetErrorMode(errorMode); 101 102 RTL_LOGFILE_TRACE1( "} osl_loadModule end: %S", (LPTSTR)&strModuleName->buffer ); 103 104 return ret; 105 } 106 107 /*****************************************************************************/ 108 /* osl_getModuleHandle */ 109 /*****************************************************************************/ 110 111 sal_Bool SAL_CALL 112 osl_getModuleHandle(rtl_uString *pModuleName, oslModule *pResult) 113 { 114 HINSTANCE hInstance = GetModuleHandleW(reinterpret_cast<LPCWSTR>(pModuleName->buffer)); 115 if( hInstance ) 116 { 117 *pResult = (oslModule) hInstance; 118 return sal_True; 119 } 120 121 return sal_False; 122 } 123 124 /*****************************************************************************/ 125 /* osl_unloadModule */ 126 /*****************************************************************************/ 127 void SAL_CALL osl_unloadModule(oslModule Module) 128 { 129 FreeLibrary((HINSTANCE)Module); 130 } 131 132 /*****************************************************************************/ 133 /* osl_getSymbol */ 134 /*****************************************************************************/ 135 void* SAL_CALL osl_getSymbol(oslModule Module, rtl_uString *strSymbolName) 136 { 137 /* casting from a function pointer to a data pointer is invalid 138 be in this case unavoidable because the API has to stay 139 compitable we need to keep this function which returns a 140 void* by definition */ 141 #ifdef _MSC_VER 142 #pragma warning(push) 143 #pragma warning(disable:4054) 144 #endif 145 return (void*)(osl_getFunctionSymbol(Module, strSymbolName)); 146 #ifdef _MSC_VER 147 #pragma warning(pop) 148 #endif 149 } 150 151 /*****************************************************************************/ 152 /* osl_getFunctionSymbol */ 153 /*****************************************************************************/ 154 oslGenericFunction SAL_CALL osl_getFunctionSymbol( oslModule Module, rtl_uString *strSymbolName ) 155 { 156 rtl_String *symbolName = NULL; 157 oslGenericFunction address; 158 159 OSL_ASSERT(Module); 160 OSL_ASSERT(strSymbolName); 161 162 rtl_uString2String( 163 &symbolName, 164 strSymbolName->buffer, 165 strSymbolName->length, 166 RTL_TEXTENCODING_UTF8, 167 OUSTRING_TO_OSTRING_CVTFLAGS 168 ); 169 170 address=osl_getAsciiFunctionSymbol(Module, rtl_string_getStr(symbolName)); 171 rtl_string_release(symbolName); 172 173 return address; 174 } 175 176 /*****************************************************************************/ 177 /* osl_getAsciiFunctionSymbol */ 178 /*****************************************************************************/ 179 oslGenericFunction SAL_CALL 180 osl_getAsciiFunctionSymbol( oslModule Module, const sal_Char *pSymbol ) 181 { 182 oslGenericFunction fncAddr = NULL; 183 184 if( pSymbol ) 185 fncAddr=(oslGenericFunction)GetProcAddress((HINSTANCE) Module, pSymbol); 186 187 return fncAddr; 188 } 189 190 191 192 /*****************************************************************************/ 193 /* osl_addressGetModuleURL */ 194 /*****************************************************************************/ 195 196 /*****************************************************************************/ 197 /* Implementation for Windows 95, 98 and Me */ 198 /*****************************************************************************/ 199 200 /* Undefine because there is no explicit "A" definition */ 201 202 #ifdef MODULEENTRY32 203 #undef MODULEENTRY32 204 #endif 205 206 #ifdef LPMODULEENTRY32 207 #undef LPMODULEENTRY32 208 #endif 209 210 typedef HANDLE (WINAPI *CreateToolhelp32Snapshot_PROC)( DWORD dwFlags, DWORD th32ProcessID ); 211 typedef BOOL (WINAPI *Module32First_PROC)( HANDLE hSnapshot, LPMODULEENTRY32 lpme32 ); 212 typedef BOOL (WINAPI *Module32Next_PROC)( HANDLE hSnapshot, LPMODULEENTRY32 lpme32 ); 213 214 static sal_Bool SAL_CALL _osl_addressGetModuleURL_Windows( void *pv, rtl_uString **pustrURL ) 215 { 216 sal_Bool bSuccess = sal_False; /* Assume failure */ 217 HMODULE hModKernel32 = GetModuleHandleA( "KERNEL32.DLL" ); 218 219 if ( hModKernel32 ) 220 { 221 CreateToolhelp32Snapshot_PROC lpfnCreateToolhelp32Snapshot = (CreateToolhelp32Snapshot_PROC)GetProcAddress( hModKernel32, "CreateToolhelp32Snapshot" ); 222 Module32First_PROC lpfnModule32First = (Module32First_PROC)GetProcAddress( hModKernel32, "Module32First" ); 223 Module32Next_PROC lpfnModule32Next = (Module32Next_PROC)GetProcAddress( hModKernel32, "Module32Next" ); 224 225 if ( lpfnCreateToolhelp32Snapshot && lpfnModule32First && lpfnModule32Next ) 226 { 227 HANDLE hModuleSnap = NULL; 228 DWORD dwProcessId = GetCurrentProcessId(); 229 230 // Take a snapshot of all modules in the specified process. 231 232 hModuleSnap = lpfnCreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId ); 233 234 if ( INVALID_HANDLE_VALUE != hModuleSnap ) 235 { 236 MODULEENTRY32 me32 = {0}; 237 238 // Fill the size of the structure before using it. 239 240 me32.dwSize = sizeof(MODULEENTRY32); 241 242 // Walk the module list of the process, and find the module of 243 // interest. Then copy the information to the buffer pointed 244 // to by lpMe32 so that it can be returned to the caller. 245 246 if ( lpfnModule32First(hModuleSnap, &me32) ) 247 { 248 do 249 { 250 if ( (BYTE *)pv >= (BYTE *)me32.hModule && (BYTE *)pv < (BYTE *)me32.hModule + me32.modBaseSize ) 251 { 252 rtl_uString *ustrSysPath = NULL; 253 254 rtl_string2UString( &ustrSysPath, me32.szExePath, strlen(me32.szExePath), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS ); 255 OSL_ASSERT(ustrSysPath != NULL); 256 osl_getFileURLFromSystemPath( ustrSysPath, pustrURL ); 257 rtl_uString_release( ustrSysPath ); 258 259 bSuccess = sal_True; 260 } 261 262 } while ( !bSuccess && lpfnModule32Next( hModuleSnap, &me32 ) ); 263 } 264 265 266 // Do not forget to clean up the snapshot object. 267 268 CloseHandle (hModuleSnap); 269 } 270 271 } 272 } 273 274 return bSuccess; 275 } 276 277 /***************************************************************************************/ 278 /* Implementation for Windows NT, 2K and XP (2K and XP could use the above method too) */ 279 /***************************************************************************************/ 280 281 #ifdef _MSC_VER 282 #pragma warning(push,1) /* disable warnings within system headers */ 283 #endif 284 #include <imagehlp.h> 285 #ifdef _MSC_VER 286 #pragma warning(pop) 287 #endif 288 289 typedef BOOL (WINAPI *SymInitialize_PROC)( 290 HANDLE hProcess, 291 LPSTR UserSearchPath, 292 BOOL fInvadeProcess 293 ); 294 295 typedef BOOL (WINAPI *SymCleanup_PROC)( 296 HANDLE hProcess 297 ); 298 299 typedef BOOL (WINAPI *SymGetModuleInfo_PROC)( 300 HANDLE hProcess, 301 DWORD dwAddr, 302 PIMAGEHLP_MODULE ModuleInfo 303 ); 304 305 /* Seems that IMAGEHLP.DLL is always availiable on NT 4. But MSDN from Platform SDK says Win 2K is required. MSDN from VS 6.0a says 306 it's O.K on NT 4 ???!!! 307 BTW: We are using ANSI function because not all version of IMAGEHLP.DLL contain Unicode support 308 */ 309 310 static sal_Bool SAL_CALL _osl_addressGetModuleURL_NT4( void *pv, rtl_uString **pustrURL ) 311 { 312 sal_Bool bSuccess = sal_False; /* Assume failure */ 313 314 /* IMAGEHELP.DLL has a bug that it recursivly scans subdirectories of 315 the root when calling SymInitialize(), so we preferr DBGHELP.DLL 316 which exports the same symbols and is shipped with OOo */ 317 318 HMODULE hModImageHelp = LoadLibrary( "DBGHELP.DLL" ); 319 320 if ( !hModImageHelp ) 321 hModImageHelp = LoadLibrary( "IMAGEHLP.DLL" ); 322 323 if ( hModImageHelp ) 324 { 325 SymGetModuleInfo_PROC lpfnSymGetModuleInfo; 326 SymInitialize_PROC lpfnSymInitialize; 327 SymCleanup_PROC lpfnSymCleanup; 328 329 330 lpfnSymInitialize = (SymInitialize_PROC)GetProcAddress( hModImageHelp, "SymInitialize" ); 331 lpfnSymCleanup = (SymCleanup_PROC)GetProcAddress( hModImageHelp, "SymCleanup" ); 332 lpfnSymGetModuleInfo = (SymGetModuleInfo_PROC)GetProcAddress( hModImageHelp, "SymGetModuleInfo" ); 333 334 335 if ( lpfnSymInitialize && lpfnSymCleanup && lpfnSymGetModuleInfo ) 336 { 337 IMAGEHLP_MODULE ModuleInfo; 338 ::osl::LongPathBuffer< sal_Char > aModuleFileName( MAX_LONG_PATH ); 339 LPSTR lpSearchPath = NULL; 340 341 if ( GetModuleFileNameA( NULL, aModuleFileName, aModuleFileName.getBufSizeInSymbols() ) ) 342 { 343 char *pLastBkSlash = strrchr( aModuleFileName, '\\' ); 344 345 if ( 346 pLastBkSlash && 347 pLastBkSlash > (sal_Char*)aModuleFileName 348 && *(pLastBkSlash - 1) != ':' 349 && *(pLastBkSlash - 1) != '\\' 350 ) 351 { 352 *pLastBkSlash = 0; 353 lpSearchPath = aModuleFileName; 354 } 355 } 356 357 lpfnSymInitialize( GetCurrentProcess(), lpSearchPath, TRUE ); 358 359 ZeroMemory( &ModuleInfo, sizeof(ModuleInfo) ); 360 ModuleInfo.SizeOfStruct = sizeof(ModuleInfo); 361 362 bSuccess = (sal_Bool)(!!lpfnSymGetModuleInfo( GetCurrentProcess(), (DWORD)pv, &ModuleInfo )); 363 364 if ( bSuccess ) 365 { 366 /* #99182 On localized (non-english) NT4 and XP (!!!) for some libraries the LoadedImageName member of ModuleInfo isn't filled. Because 367 other members ModuleName and ImageName do not contain the full path we can cast the Member 368 BaseOfImage to a HMODULE (on NT it's the same) and use GetModuleFileName to retrieve the full 369 path of the loaded image */ 370 371 if ( ModuleInfo.LoadedImageName[0] || GetModuleFileNameA( (HMODULE)ModuleInfo.BaseOfImage, ModuleInfo.LoadedImageName, sizeof(ModuleInfo.LoadedImageName) ) ) 372 { 373 rtl_uString *ustrSysPath = NULL; 374 375 rtl_string2UString( &ustrSysPath, ModuleInfo.LoadedImageName, strlen(ModuleInfo.LoadedImageName), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS ); 376 OSL_ASSERT(ustrSysPath != NULL); 377 osl_getFileURLFromSystemPath( ustrSysPath, pustrURL ); 378 rtl_uString_release( ustrSysPath ); 379 } 380 else 381 bSuccess = sal_False; 382 } 383 384 lpfnSymCleanup( GetCurrentProcess() ); 385 } 386 387 FreeLibrary( hModImageHelp ); 388 } 389 390 return bSuccess; 391 } 392 393 394 typedef struct _MODULEINFO { 395 LPVOID lpBaseOfDll; 396 DWORD SizeOfImage; 397 LPVOID EntryPoint; 398 } MODULEINFO, *LPMODULEINFO; 399 400 typedef BOOL (WINAPI *EnumProcessModules_PROC)( 401 HANDLE hProcess, // handle to the process 402 HMODULE * lphModule, // array to receive the module handles 403 DWORD cb, // size of the array 404 LPDWORD lpcbNeeded // receives the number of bytes returned 405 ); 406 407 typedef BOOL (WINAPI *GetModuleInformation_PROC)( 408 HANDLE hProcess, // handle to the process 409 HMODULE hModule, // handle to the module 410 LPMODULEINFO lpmodinfo, // structure that receives information 411 DWORD cb // size of the structure 412 ); 413 414 #define bufsizeof(buffer) (sizeof(buffer) / sizeof((buffer)[0])) 415 416 /* This version can fail because PSAPI.DLL is not always part of NT 4 despite MSDN Libary 6.0a say so */ 417 418 static sal_Bool SAL_CALL _osl_addressGetModuleURL_NT( void *pv, rtl_uString **pustrURL ) 419 { 420 sal_Bool bSuccess = sal_False; /* Assume failure */ 421 static HMODULE hModPsapi = NULL; 422 423 if ( !hModPsapi ) 424 hModPsapi = LoadLibrary( "PSAPI.DLL" ); 425 426 if ( hModPsapi ) 427 { 428 EnumProcessModules_PROC lpfnEnumProcessModules = (EnumProcessModules_PROC)GetProcAddress( hModPsapi, "EnumProcessModules" ); 429 GetModuleInformation_PROC lpfnGetModuleInformation = (GetModuleInformation_PROC)GetProcAddress( hModPsapi, "GetModuleInformation" ); 430 431 if ( lpfnEnumProcessModules && lpfnGetModuleInformation ) 432 { 433 DWORD cbNeeded = 0; 434 HMODULE *lpModules = NULL; 435 DWORD nModules = 0; 436 UINT iModule = 0; 437 MODULEINFO modinfo; 438 439 lpfnEnumProcessModules( GetCurrentProcess(), NULL, 0, &cbNeeded ); 440 441 lpModules = (HMODULE *)_alloca( cbNeeded ); 442 lpfnEnumProcessModules( GetCurrentProcess(), lpModules, cbNeeded, &cbNeeded ); 443 444 nModules = cbNeeded / sizeof(HMODULE); 445 446 for ( iModule = 0; !bSuccess && iModule < nModules; iModule++ ) 447 { 448 lpfnGetModuleInformation( GetCurrentProcess(), lpModules[iModule], &modinfo, sizeof(modinfo) ); 449 450 if ( (BYTE *)pv >= (BYTE *)modinfo.lpBaseOfDll && (BYTE *)pv < (BYTE *)modinfo.lpBaseOfDll + modinfo.SizeOfImage ) 451 { 452 ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH ); 453 rtl_uString *ustrSysPath = NULL; 454 455 GetModuleFileNameW( lpModules[iModule], ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer), aBuffer.getBufSizeInSymbols() ); 456 457 rtl_uString_newFromStr( &ustrSysPath, aBuffer ); 458 osl_getFileURLFromSystemPath( ustrSysPath, pustrURL ); 459 rtl_uString_release( ustrSysPath ); 460 461 bSuccess = sal_True; 462 } 463 } 464 } 465 466 } 467 468 return bSuccess; 469 } 470 471 /*****************************************************************************/ 472 /* Dispatcher for osl_osl_addressGetModuleURL */ 473 /*****************************************************************************/ 474 475 sal_Bool SAL_CALL osl_getModuleURLFromAddress( void *pv, rtl_uString **pustrURL ) 476 { 477 /* Use ..._NT first because ..._NT4 is much slower */ 478 if ( IS_NT ) 479 return _osl_addressGetModuleURL_NT( pv, pustrURL ) || _osl_addressGetModuleURL_NT4( pv, pustrURL ); 480 else 481 return _osl_addressGetModuleURL_Windows( pv, pustrURL ); 482 } 483 484 /*****************************************************************************/ 485 /* osl_getModuleURLFromFunctionAddress */ 486 /*****************************************************************************/ 487 sal_Bool SAL_CALL osl_getModuleURLFromFunctionAddress( oslGenericFunction addr, rtl_uString ** ppLibraryUrl ) 488 { 489 /* casting a function pointer to a data pointer (void*) is 490 not allowed according to the C/C++ standards. In this case 491 it is unavoidable because we have to stay compatible we 492 cannot remove any function. */ 493 #ifdef _MSC_VER 494 #pragma warning(push) 495 #pragma warning(disable:4054) 496 #endif 497 return osl_getModuleURLFromAddress((void*)addr, ppLibraryUrl); 498 #ifdef _MSC_VER 499 #pragma warning(pop) 500 #endif 501 } 502 503 504