Updated core
[LibreOffice.git] / sal / osl / w32 / module.cxx
blob373994aa5dd86a8b4ea0dad7742fdbab44054ec5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "system.h"
21 #include <tlhelp32.h>
23 #include "file_url.h"
24 #include "path_helper.hxx"
26 #include <osl/module.h>
27 #include <osl/diagnose.h>
28 #include <osl/thread.h>
29 #include <osl/file.h>
30 #include <rtl/logfile.h>
31 #include <vector>
34 under WIN32, we use the void* oslModule
35 as a WIN32 HANDLE (which is also a 32-bit value)
38 /*****************************************************************************/
39 /* osl_loadModule */
40 /*****************************************************************************/
41 oslModule SAL_CALL osl_loadModule(rtl_uString *strModuleName, sal_Int32 /*nRtldMode*/ )
43 HINSTANCE hInstance;
44 #if OSL_DEBUG_LEVEL < 2
45 UINT errorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
46 #endif
47 rtl_uString* Module = NULL;
48 oslModule ret = 0;
49 oslFileError nError;
51 RTL_LOGFILE_TRACE1( "{ osl_loadModule start: %S", (LPTSTR)&strModuleName->buffer );
53 OSL_ASSERT(strModuleName);
55 nError = osl_getSystemPathFromFileURL(strModuleName, &Module);
57 if ( osl_File_E_None != nError )
58 rtl_uString_assign(&Module, strModuleName);
60 hInstance = LoadLibraryW(reinterpret_cast<LPCWSTR>(Module->buffer));
62 if (hInstance == NULL)
63 hInstance = LoadLibraryExW(reinterpret_cast<LPCWSTR>(Module->buffer), NULL,
64 LOAD_WITH_ALTERED_SEARCH_PATH);
66 //In case of long path names (\\?\c:\...) try to shorten the filename.
67 //LoadLibrary cannot handle file names which exceed 260 letters.
68 //In case the path is to long, the function will fail. However, the error
69 //code can be different. For example, it returned ERROR_FILENAME_EXCED_RANGE
70 //on Windows XP and ERROR_INSUFFICIENT_BUFFER on Windows 7 (64bit)
71 if (hInstance == NULL && Module->length > 260)
73 std::vector<WCHAR, rtl::Allocator<WCHAR> > vec(Module->length + 1);
74 DWORD len = GetShortPathNameW(reinterpret_cast<LPCWSTR>(Module->buffer),
75 reinterpret_cast<LPWSTR>(&vec[0]), Module->length + 1);
76 if (len )
78 hInstance = LoadLibraryW(reinterpret_cast<LPWSTR>(&vec[0]));
80 if (hInstance == NULL)
81 hInstance = LoadLibraryExW(reinterpret_cast<LPWSTR>(&vec[0]), NULL,
82 LOAD_WITH_ALTERED_SEARCH_PATH);
87 if (hInstance <= (HINSTANCE)HINSTANCE_ERROR)
88 hInstance = 0;
90 ret = (oslModule) hInstance;
91 rtl_uString_release(Module);
92 #if OSL_DEBUG_LEVEL < 2
93 SetErrorMode(errorMode);
94 #endif
96 RTL_LOGFILE_TRACE1( "} osl_loadModule end: %S", (LPTSTR)&strModuleName->buffer );
98 return ret;
101 /*****************************************************************************/
102 /* osl_loadModuleAscii */
103 /*****************************************************************************/
104 oslModule SAL_CALL osl_loadModuleAscii(const sal_Char *pModuleName, sal_Int32 nRtldMode )
106 (void) nRtldMode; /* avoid warnings */
108 HINSTANCE hInstance;
109 UINT errorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
110 oslModule ret = 0;
112 RTL_LOGFILE_TRACE1( "{ osl_loadModule start: %s", pModuleName );
114 OSL_ASSERT(pModuleName);
116 hInstance = LoadLibrary(pModuleName);
117 if (hInstance == NULL)
118 hInstance = LoadLibraryEx(pModuleName, NULL,
119 LOAD_WITH_ALTERED_SEARCH_PATH);
121 if (hInstance <= (HINSTANCE)HINSTANCE_ERROR)
122 hInstance = 0;
124 ret = (oslModule) hInstance;
125 SetErrorMode(errorMode);
127 RTL_LOGFILE_TRACE1( "} osl_loadModule end: %s", pModuleName );
129 return ret;
132 oslModule osl_loadModuleRelativeAscii(
133 oslGenericFunction, char const * relativePath, sal_Int32 mode)
135 return osl_loadModuleAscii(relativePath, mode); //TODO: FIXME
138 /*****************************************************************************/
139 /* osl_getModuleHandle */
140 /*****************************************************************************/
142 sal_Bool SAL_CALL
143 osl_getModuleHandle(rtl_uString *pModuleName, oslModule *pResult)
145 LPCWSTR pName = pModuleName ? reinterpret_cast<LPCWSTR>(pModuleName->buffer) : NULL;
146 HINSTANCE hInstance = GetModuleHandleW(pName);
147 if( hInstance )
149 *pResult = (oslModule) hInstance;
150 return sal_True;
153 return sal_False;
156 /*****************************************************************************/
157 /* osl_unloadModule */
158 /*****************************************************************************/
159 void SAL_CALL osl_unloadModule(oslModule Module)
161 FreeLibrary((HINSTANCE)Module);
164 /*****************************************************************************/
165 /* osl_getSymbol */
166 /*****************************************************************************/
167 void* SAL_CALL osl_getSymbol(oslModule Module, rtl_uString *strSymbolName)
169 /* casting from a function pointer to a data pointer is invalid
170 be in this case unavoidable because the API has to stay
171 compitable we need to keep this function which returns a
172 void* by definition */
173 #ifdef _MSC_VER
174 #pragma warning(push)
175 #pragma warning(disable:4054)
176 #endif
177 return (void*)(osl_getFunctionSymbol(Module, strSymbolName));
178 #ifdef _MSC_VER
179 #pragma warning(pop)
180 #endif
183 /*****************************************************************************/
184 /* osl_getFunctionSymbol */
185 /*****************************************************************************/
186 oslGenericFunction SAL_CALL osl_getFunctionSymbol( oslModule Module, rtl_uString *strSymbolName )
188 rtl_String *symbolName = NULL;
189 oslGenericFunction address;
191 OSL_ASSERT(Module);
192 OSL_ASSERT(strSymbolName);
194 rtl_uString2String(
195 &symbolName,
196 strSymbolName->buffer,
197 strSymbolName->length,
198 RTL_TEXTENCODING_UTF8,
199 OUSTRING_TO_OSTRING_CVTFLAGS
202 address=osl_getAsciiFunctionSymbol(Module, rtl_string_getStr(symbolName));
203 rtl_string_release(symbolName);
205 return address;
208 /*****************************************************************************/
209 /* osl_getAsciiFunctionSymbol */
210 /*****************************************************************************/
211 oslGenericFunction SAL_CALL
212 osl_getAsciiFunctionSymbol( oslModule Module, const sal_Char *pSymbol )
214 oslGenericFunction fncAddr = NULL;
216 if( pSymbol )
217 fncAddr=(oslGenericFunction)GetProcAddress((HINSTANCE) Module, pSymbol);
219 return fncAddr;
224 /*****************************************************************************/
225 /* osl_addressGetModuleURL */
226 /*****************************************************************************/
228 /*****************************************************************************/
229 /* Implementation for Windows 95, 98 and Me */
230 /*****************************************************************************/
232 /* Undefine because there is no explicit "A" definition */
234 #ifdef MODULEENTRY32
235 #undef MODULEENTRY32
236 #endif
238 #ifdef LPMODULEENTRY32
239 #undef LPMODULEENTRY32
240 #endif
242 /***************************************************************************************/
243 /* Implementation for Windows NT, 2K and XP (2K and XP could use the above method too) */
244 /***************************************************************************************/
246 #ifdef _MSC_VER
247 #pragma warning(push,1) /* disable warnings within system headers */
248 #endif
249 #include <imagehlp.h>
250 #ifdef _MSC_VER
251 #pragma warning(pop)
252 #endif
254 typedef BOOL (WINAPI *SymInitialize_PROC)(
255 HANDLE hProcess,
256 LPSTR UserSearchPath,
257 BOOL fInvadeProcess
260 typedef BOOL (WINAPI *SymCleanup_PROC)(
261 HANDLE hProcess
264 typedef BOOL (WINAPI *SymGetModuleInfo_PROC)(
265 HANDLE hProcess,
266 DWORD dwAddr,
267 PIMAGEHLP_MODULE ModuleInfo
270 /* Seems that IMAGEHLP.DLL is always available on NT 4. But MSDN from Platform SDK says Win 2K is required. MSDN from VS 6.0a says
271 it's O.K on NT 4 ???!!!
272 BTW: We are using ANSI function because not all version of IMAGEHLP.DLL contain Unicode support
275 static sal_Bool SAL_CALL _osl_addressGetModuleURL_NT4( void *pv, rtl_uString **pustrURL )
277 sal_Bool bSuccess = sal_False; /* Assume failure */
279 /* IMAGEHELP.DLL has a bug that it recursivly scans subdirectories of
280 the root when calling SymInitialize(), so we preferr DBGHELP.DLL
281 which exports the same symbols and is shipped with OOo */
283 HMODULE hModImageHelp = LoadLibrary( "DBGHELP.DLL" );
285 if ( !hModImageHelp )
286 hModImageHelp = LoadLibrary( "IMAGEHLP.DLL" );
288 if ( hModImageHelp )
290 SymGetModuleInfo_PROC lpfnSymGetModuleInfo;
291 SymInitialize_PROC lpfnSymInitialize;
292 SymCleanup_PROC lpfnSymCleanup;
295 lpfnSymInitialize = (SymInitialize_PROC)GetProcAddress( hModImageHelp, "SymInitialize" );
296 lpfnSymCleanup = (SymCleanup_PROC)GetProcAddress( hModImageHelp, "SymCleanup" );
297 lpfnSymGetModuleInfo = (SymGetModuleInfo_PROC)GetProcAddress( hModImageHelp, "SymGetModuleInfo" );
300 if ( lpfnSymInitialize && lpfnSymCleanup && lpfnSymGetModuleInfo )
302 IMAGEHLP_MODULE ModuleInfo;
303 ::osl::LongPathBuffer< sal_Char > aModuleFileName( MAX_LONG_PATH );
304 LPSTR lpSearchPath = NULL;
306 if ( GetModuleFileNameA( NULL, aModuleFileName, aModuleFileName.getBufSizeInSymbols() ) )
308 char *pLastBkSlash = strrchr( aModuleFileName, '\\' );
310 if (
311 pLastBkSlash &&
312 pLastBkSlash > (sal_Char*)aModuleFileName
313 && *(pLastBkSlash - 1) != ':'
314 && *(pLastBkSlash - 1) != '\\'
317 *pLastBkSlash = 0;
318 lpSearchPath = aModuleFileName;
322 lpfnSymInitialize( GetCurrentProcess(), lpSearchPath, TRUE );
324 ZeroMemory( &ModuleInfo, sizeof(ModuleInfo) );
325 ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
327 bSuccess = (sal_Bool)(!!lpfnSymGetModuleInfo( GetCurrentProcess(), (DWORD)pv, &ModuleInfo ));
329 if ( bSuccess )
331 /* #99182 On localized (non-english) NT4 and XP (!!!) for some libraries the LoadedImageName member of ModuleInfo isn't filled. Because
332 other members ModuleName and ImageName do not contain the full path we can cast the Member
333 BaseOfImage to a HMODULE (on NT it's the same) and use GetModuleFileName to retrieve the full
334 path of the loaded image */
336 if ( ModuleInfo.LoadedImageName[0] || GetModuleFileNameA( (HMODULE)ModuleInfo.BaseOfImage, ModuleInfo.LoadedImageName, sizeof(ModuleInfo.LoadedImageName) ) )
338 rtl_uString *ustrSysPath = NULL;
340 rtl_string2UString( &ustrSysPath, ModuleInfo.LoadedImageName, strlen(ModuleInfo.LoadedImageName), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
341 OSL_ASSERT(ustrSysPath != NULL);
342 osl_getFileURLFromSystemPath( ustrSysPath, pustrURL );
343 rtl_uString_release( ustrSysPath );
345 else
346 bSuccess = sal_False;
349 lpfnSymCleanup( GetCurrentProcess() );
352 FreeLibrary( hModImageHelp );
355 return bSuccess;
359 typedef struct _MODULEINFO {
360 LPVOID lpBaseOfDll;
361 DWORD SizeOfImage;
362 LPVOID EntryPoint;
363 } MODULEINFO, *LPMODULEINFO;
365 typedef BOOL (WINAPI *EnumProcessModules_PROC)(
366 HANDLE hProcess, // handle to the process
367 HMODULE * lphModule, // array to receive the module handles
368 DWORD cb, // size of the array
369 LPDWORD lpcbNeeded // receives the number of bytes returned
372 typedef BOOL (WINAPI *GetModuleInformation_PROC)(
373 HANDLE hProcess, // handle to the process
374 HMODULE hModule, // handle to the module
375 LPMODULEINFO lpmodinfo, // structure that receives information
376 DWORD cb // size of the structure
379 /* This version can fail because PSAPI.DLL is not always part of NT 4 despite MSDN Library 6.0a say so */
381 static sal_Bool SAL_CALL _osl_addressGetModuleURL_NT( void *pv, rtl_uString **pustrURL )
383 sal_Bool bSuccess = sal_False; /* Assume failure */
384 static HMODULE hModPsapi = NULL;
386 if ( !hModPsapi )
387 hModPsapi = LoadLibrary( "PSAPI.DLL" );
389 if ( hModPsapi )
391 EnumProcessModules_PROC lpfnEnumProcessModules = (EnumProcessModules_PROC)GetProcAddress( hModPsapi, "EnumProcessModules" );
392 GetModuleInformation_PROC lpfnGetModuleInformation = (GetModuleInformation_PROC)GetProcAddress( hModPsapi, "GetModuleInformation" );
394 if ( lpfnEnumProcessModules && lpfnGetModuleInformation )
396 DWORD cbNeeded = 0;
397 HMODULE *lpModules = NULL;
398 DWORD nModules = 0;
399 UINT iModule = 0;
400 MODULEINFO modinfo;
402 lpfnEnumProcessModules( GetCurrentProcess(), NULL, 0, &cbNeeded );
404 lpModules = (HMODULE *)_alloca( cbNeeded );
405 lpfnEnumProcessModules( GetCurrentProcess(), lpModules, cbNeeded, &cbNeeded );
407 nModules = cbNeeded / sizeof(HMODULE);
409 for ( iModule = 0; !bSuccess && iModule < nModules; iModule++ )
411 lpfnGetModuleInformation( GetCurrentProcess(), lpModules[iModule], &modinfo, sizeof(modinfo) );
413 if ( (BYTE *)pv >= (BYTE *)modinfo.lpBaseOfDll && (BYTE *)pv < (BYTE *)modinfo.lpBaseOfDll + modinfo.SizeOfImage )
415 ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH );
416 rtl_uString *ustrSysPath = NULL;
418 GetModuleFileNameW( lpModules[iModule], ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer), aBuffer.getBufSizeInSymbols() );
420 rtl_uString_newFromStr( &ustrSysPath, aBuffer );
421 osl_getFileURLFromSystemPath( ustrSysPath, pustrURL );
422 rtl_uString_release( ustrSysPath );
424 bSuccess = sal_True;
431 return bSuccess;
434 /*****************************************************************************/
435 /* Dispatcher for osl_osl_addressGetModuleURL */
436 /*****************************************************************************/
438 sal_Bool SAL_CALL osl_getModuleURLFromAddress( void *pv, rtl_uString **pustrURL )
440 /* Use ..._NT first because ..._NT4 is much slower */
441 return _osl_addressGetModuleURL_NT( pv, pustrURL ) || _osl_addressGetModuleURL_NT4( pv, pustrURL );
444 /*****************************************************************************/
445 /* osl_getModuleURLFromFunctionAddress */
446 /*****************************************************************************/
447 sal_Bool SAL_CALL osl_getModuleURLFromFunctionAddress( oslGenericFunction addr, rtl_uString ** ppLibraryUrl )
449 /* casting a function pointer to a data pointer (void*) is
450 not allowed according to the C/C++ standards. In this case
451 it is unavoidable because we have to stay compatible we
452 cannot remove any function. */
453 #ifdef _MSC_VER
454 #pragma warning(push)
455 #pragma warning(disable:4054)
456 #endif
457 return osl_getModuleURLFromAddress((void*)addr, ppLibraryUrl);
458 #ifdef _MSC_VER
459 #pragma warning(pop)
460 #endif
464 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */