Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / sal / osl / w32 / module.cxx
blob4c384d704f25b3c3d9c860ddc4c8bc181da3455e
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 SAL_INFO( "sal.osl", "{ osl_loadModule start: " << (LPTSTR)&strModuleName->buffer );
52 OSL_ASSERT(strModuleName);
54 nError = osl_getSystemPathFromFileURL(strModuleName, &Module);
56 if ( osl_File_E_None != nError )
57 rtl_uString_assign(&Module, strModuleName);
59 hInstance = LoadLibraryW(reinterpret_cast<LPCWSTR>(Module->buffer));
61 if (hInstance == NULL)
62 hInstance = LoadLibraryExW(reinterpret_cast<LPCWSTR>(Module->buffer), NULL,
63 LOAD_WITH_ALTERED_SEARCH_PATH);
65 //In case of long path names (\\?\c:\...) try to shorten the filename.
66 //LoadLibrary cannot handle file names which exceed 260 letters.
67 //In case the path is to long, the function will fail. However, the error
68 //code can be different. For example, it returned ERROR_FILENAME_EXCED_RANGE
69 //on Windows XP and ERROR_INSUFFICIENT_BUFFER on Windows 7 (64bit)
70 if (hInstance == NULL && Module->length > 260)
72 std::vector<WCHAR, rtl::Allocator<WCHAR> > vec(Module->length + 1);
73 DWORD len = GetShortPathNameW(reinterpret_cast<LPCWSTR>(Module->buffer),
74 reinterpret_cast<LPWSTR>(&vec[0]), Module->length + 1);
75 if (len )
77 hInstance = LoadLibraryW(reinterpret_cast<LPWSTR>(&vec[0]));
79 if (hInstance == NULL)
80 hInstance = LoadLibraryExW(reinterpret_cast<LPWSTR>(&vec[0]), NULL,
81 LOAD_WITH_ALTERED_SEARCH_PATH);
86 if (hInstance <= (HINSTANCE)HINSTANCE_ERROR)
87 hInstance = 0;
89 ret = (oslModule) hInstance;
90 rtl_uString_release(Module);
91 #if OSL_DEBUG_LEVEL < 2
92 SetErrorMode(errorMode);
93 #endif
95 SAL_INFO( "sal.osl", "} osl_loadModule end: " << (LPTSTR)&strModuleName->buffer );
96 return ret;
99 /*****************************************************************************/
100 /* osl_loadModuleAscii */
101 /*****************************************************************************/
102 oslModule SAL_CALL osl_loadModuleAscii(const sal_Char *pModuleName, sal_Int32 nRtldMode )
104 (void) nRtldMode; /* avoid warnings */
106 HINSTANCE hInstance;
107 UINT errorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
108 oslModule ret = 0;
110 SAL_INFO( "sal.osl", "{ osl_loadModule start: " << pModuleName );
111 OSL_ASSERT(pModuleName);
113 hInstance = LoadLibrary(pModuleName);
114 if (hInstance == NULL)
115 hInstance = LoadLibraryEx(pModuleName, NULL,
116 LOAD_WITH_ALTERED_SEARCH_PATH);
118 if (hInstance <= (HINSTANCE)HINSTANCE_ERROR)
119 hInstance = 0;
121 ret = (oslModule) hInstance;
122 SetErrorMode(errorMode);
124 SAL_INFO( "sal.osl", "} osl_loadModule end: " << pModuleName );
125 return ret;
128 oslModule osl_loadModuleRelativeAscii(
129 oslGenericFunction, char const * relativePath, sal_Int32 mode)
131 return osl_loadModuleAscii(relativePath, mode); //TODO: FIXME
134 /*****************************************************************************/
135 /* osl_getModuleHandle */
136 /*****************************************************************************/
138 sal_Bool SAL_CALL
139 osl_getModuleHandle(rtl_uString *pModuleName, oslModule *pResult)
141 LPCWSTR pName = pModuleName ? reinterpret_cast<LPCWSTR>(pModuleName->buffer) : NULL;
142 HINSTANCE hInstance = GetModuleHandleW(pName);
143 if( hInstance )
145 *pResult = (oslModule) hInstance;
146 return sal_True;
149 return sal_False;
152 /*****************************************************************************/
153 /* osl_unloadModule */
154 /*****************************************************************************/
155 void SAL_CALL osl_unloadModule(oslModule Module)
157 FreeLibrary((HINSTANCE)Module);
160 /*****************************************************************************/
161 /* osl_getSymbol */
162 /*****************************************************************************/
163 void* SAL_CALL osl_getSymbol(oslModule Module, rtl_uString *strSymbolName)
165 /* casting from a function pointer to a data pointer is invalid
166 be in this case unavoidable because the API has to stay
167 compitable we need to keep this function which returns a
168 void* by definition */
169 #ifdef _MSC_VER
170 #pragma warning(push)
171 #pragma warning(disable:4054)
172 #endif
173 return (void*)(osl_getFunctionSymbol(Module, strSymbolName));
174 #ifdef _MSC_VER
175 #pragma warning(pop)
176 #endif
179 /*****************************************************************************/
180 /* osl_getFunctionSymbol */
181 /*****************************************************************************/
182 oslGenericFunction SAL_CALL osl_getFunctionSymbol( oslModule Module, rtl_uString *strSymbolName )
184 rtl_String *symbolName = NULL;
185 oslGenericFunction address;
187 OSL_ASSERT(Module);
188 OSL_ASSERT(strSymbolName);
190 rtl_uString2String(
191 &symbolName,
192 strSymbolName->buffer,
193 strSymbolName->length,
194 RTL_TEXTENCODING_UTF8,
195 OUSTRING_TO_OSTRING_CVTFLAGS
198 address=osl_getAsciiFunctionSymbol(Module, rtl_string_getStr(symbolName));
199 rtl_string_release(symbolName);
201 return address;
204 /*****************************************************************************/
205 /* osl_getAsciiFunctionSymbol */
206 /*****************************************************************************/
207 oslGenericFunction SAL_CALL
208 osl_getAsciiFunctionSymbol( oslModule Module, const sal_Char *pSymbol )
210 oslGenericFunction fncAddr = NULL;
212 if( pSymbol )
213 fncAddr=(oslGenericFunction)GetProcAddress((HINSTANCE) Module, pSymbol);
215 return fncAddr;
220 /*****************************************************************************/
221 /* osl_addressGetModuleURL */
222 /*****************************************************************************/
224 /*****************************************************************************/
225 /* Implementation for Windows 95, 98 and Me */
226 /*****************************************************************************/
228 /* Undefine because there is no explicit "A" definition */
230 #ifdef MODULEENTRY32
231 #undef MODULEENTRY32
232 #endif
234 #ifdef LPMODULEENTRY32
235 #undef LPMODULEENTRY32
236 #endif
238 /***************************************************************************************/
239 /* Implementation for Windows NT, 2K and XP (2K and XP could use the above method too) */
240 /***************************************************************************************/
242 #ifdef _MSC_VER
243 #pragma warning(push,1) /* disable warnings within system headers */
244 #endif
245 #include <imagehlp.h>
246 #ifdef _MSC_VER
247 #pragma warning(pop)
248 #endif
250 typedef BOOL (WINAPI *SymInitialize_PROC)(
251 HANDLE hProcess,
252 LPSTR UserSearchPath,
253 BOOL fInvadeProcess
256 typedef BOOL (WINAPI *SymCleanup_PROC)(
257 HANDLE hProcess
260 typedef BOOL (WINAPI *SymGetModuleInfo_PROC)(
261 HANDLE hProcess,
262 DWORD dwAddr,
263 PIMAGEHLP_MODULE ModuleInfo
266 /* 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
267 it's O.K on NT 4 ???!!!
268 BTW: We are using ANSI function because not all version of IMAGEHLP.DLL contain Unicode support
271 static sal_Bool SAL_CALL _osl_addressGetModuleURL_NT4( void *pv, rtl_uString **pustrURL )
273 sal_Bool bSuccess = sal_False; /* Assume failure */
275 /* IMAGEHELP.DLL has a bug that it recursivly scans subdirectories of
276 the root when calling SymInitialize(), so we preferr DBGHELP.DLL
277 which exports the same symbols and is shipped with OOo */
279 HMODULE hModImageHelp = LoadLibrary( "DBGHELP.DLL" );
281 if ( !hModImageHelp )
282 hModImageHelp = LoadLibrary( "IMAGEHLP.DLL" );
284 if ( hModImageHelp )
286 SymGetModuleInfo_PROC lpfnSymGetModuleInfo;
287 SymInitialize_PROC lpfnSymInitialize;
288 SymCleanup_PROC lpfnSymCleanup;
291 lpfnSymInitialize = (SymInitialize_PROC)GetProcAddress( hModImageHelp, "SymInitialize" );
292 lpfnSymCleanup = (SymCleanup_PROC)GetProcAddress( hModImageHelp, "SymCleanup" );
293 lpfnSymGetModuleInfo = (SymGetModuleInfo_PROC)GetProcAddress( hModImageHelp, "SymGetModuleInfo" );
296 if ( lpfnSymInitialize && lpfnSymCleanup && lpfnSymGetModuleInfo )
298 IMAGEHLP_MODULE ModuleInfo;
299 ::osl::LongPathBuffer< sal_Char > aModuleFileName( MAX_LONG_PATH );
300 LPSTR lpSearchPath = NULL;
302 if ( GetModuleFileNameA( NULL, aModuleFileName, aModuleFileName.getBufSizeInSymbols() ) )
304 char *pLastBkSlash = strrchr( aModuleFileName, '\\' );
306 if (
307 pLastBkSlash &&
308 pLastBkSlash > (sal_Char*)aModuleFileName
309 && *(pLastBkSlash - 1) != ':'
310 && *(pLastBkSlash - 1) != '\\'
313 *pLastBkSlash = 0;
314 lpSearchPath = aModuleFileName;
318 lpfnSymInitialize( GetCurrentProcess(), lpSearchPath, TRUE );
320 ZeroMemory( &ModuleInfo, sizeof(ModuleInfo) );
321 ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
323 bSuccess = (sal_Bool)(!!lpfnSymGetModuleInfo( GetCurrentProcess(), (DWORD_PTR)pv, &ModuleInfo ));
325 if ( bSuccess )
327 /* #99182 On localized (non-english) NT4 and XP (!!!) for some libraries the LoadedImageName member of ModuleInfo isn't filled. Because
328 other members ModuleName and ImageName do not contain the full path we can cast the Member
329 BaseOfImage to a HMODULE (on NT it's the same) and use GetModuleFileName to retrieve the full
330 path of the loaded image */
332 if ( ModuleInfo.LoadedImageName[0] || GetModuleFileNameA( (HMODULE)ModuleInfo.BaseOfImage, ModuleInfo.LoadedImageName, sizeof(ModuleInfo.LoadedImageName) ) )
334 rtl_uString *ustrSysPath = NULL;
336 rtl_string2UString( &ustrSysPath, ModuleInfo.LoadedImageName, strlen(ModuleInfo.LoadedImageName), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
337 OSL_ASSERT(ustrSysPath != NULL);
338 osl_getFileURLFromSystemPath( ustrSysPath, pustrURL );
339 rtl_uString_release( ustrSysPath );
341 else
342 bSuccess = sal_False;
345 lpfnSymCleanup( GetCurrentProcess() );
348 FreeLibrary( hModImageHelp );
351 return bSuccess;
355 typedef struct _MODULEINFO {
356 LPVOID lpBaseOfDll;
357 DWORD SizeOfImage;
358 LPVOID EntryPoint;
359 } MODULEINFO, *LPMODULEINFO;
361 typedef BOOL (WINAPI *EnumProcessModules_PROC)(
362 HANDLE hProcess, // handle to the process
363 HMODULE * lphModule, // array to receive the module handles
364 DWORD cb, // size of the array
365 LPDWORD lpcbNeeded // receives the number of bytes returned
368 typedef BOOL (WINAPI *GetModuleInformation_PROC)(
369 HANDLE hProcess, // handle to the process
370 HMODULE hModule, // handle to the module
371 LPMODULEINFO lpmodinfo, // structure that receives information
372 DWORD cb // size of the structure
375 /* This version can fail because PSAPI.DLL is not always part of NT 4 despite MSDN Library 6.0a say so */
377 static sal_Bool SAL_CALL _osl_addressGetModuleURL_NT( void *pv, rtl_uString **pustrURL )
379 sal_Bool bSuccess = sal_False; /* Assume failure */
380 static HMODULE hModPsapi = NULL;
382 if ( !hModPsapi )
383 hModPsapi = LoadLibrary( "PSAPI.DLL" );
385 if ( hModPsapi )
387 EnumProcessModules_PROC lpfnEnumProcessModules = (EnumProcessModules_PROC)GetProcAddress( hModPsapi, "EnumProcessModules" );
388 GetModuleInformation_PROC lpfnGetModuleInformation = (GetModuleInformation_PROC)GetProcAddress( hModPsapi, "GetModuleInformation" );
390 if ( lpfnEnumProcessModules && lpfnGetModuleInformation )
392 DWORD cbNeeded = 0;
393 HMODULE *lpModules = NULL;
394 DWORD nModules = 0;
395 UINT iModule = 0;
396 MODULEINFO modinfo;
398 lpfnEnumProcessModules( GetCurrentProcess(), NULL, 0, &cbNeeded );
400 lpModules = (HMODULE *)_alloca( cbNeeded );
401 lpfnEnumProcessModules( GetCurrentProcess(), lpModules, cbNeeded, &cbNeeded );
403 nModules = cbNeeded / sizeof(HMODULE);
405 for ( iModule = 0; !bSuccess && iModule < nModules; iModule++ )
407 lpfnGetModuleInformation( GetCurrentProcess(), lpModules[iModule], &modinfo, sizeof(modinfo) );
409 if ( (BYTE *)pv >= (BYTE *)modinfo.lpBaseOfDll && (BYTE *)pv < (BYTE *)modinfo.lpBaseOfDll + modinfo.SizeOfImage )
411 ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH );
412 rtl_uString *ustrSysPath = NULL;
414 GetModuleFileNameW( lpModules[iModule], ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer), aBuffer.getBufSizeInSymbols() );
416 rtl_uString_newFromStr( &ustrSysPath, aBuffer );
417 osl_getFileURLFromSystemPath( ustrSysPath, pustrURL );
418 rtl_uString_release( ustrSysPath );
420 bSuccess = sal_True;
427 return bSuccess;
430 /*****************************************************************************/
431 /* Dispatcher for osl_osl_addressGetModuleURL */
432 /*****************************************************************************/
434 sal_Bool SAL_CALL osl_getModuleURLFromAddress( void *pv, rtl_uString **pustrURL )
436 /* Use ..._NT first because ..._NT4 is much slower */
437 return _osl_addressGetModuleURL_NT( pv, pustrURL ) || _osl_addressGetModuleURL_NT4( pv, pustrURL );
440 /*****************************************************************************/
441 /* osl_getModuleURLFromFunctionAddress */
442 /*****************************************************************************/
443 sal_Bool SAL_CALL osl_getModuleURLFromFunctionAddress( oslGenericFunction addr, rtl_uString ** ppLibraryUrl )
445 /* casting a function pointer to a data pointer (void*) is
446 not allowed according to the C/C++ standards. In this case
447 it is unavoidable because we have to stay compatible we
448 cannot remove any function. */
449 #ifdef _MSC_VER
450 #pragma warning(push)
451 #pragma warning(disable:4054)
452 #endif
453 return osl_getModuleURLFromAddress((void*)addr, ppLibraryUrl);
454 #ifdef _MSC_VER
455 #pragma warning(pop)
456 #endif
460 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */