1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
24 #include "path_helper.hxx"
26 #include <osl/module.h>
27 #include <osl/diagnose.h>
28 #include <osl/thread.h>
30 #include <rtl/logfile.h>
34 under WIN32, we use the void* oslModule
35 as a WIN32 HANDLE (which is also a 32-bit value)
38 /*****************************************************************************/
40 /*****************************************************************************/
41 oslModule SAL_CALL
osl_loadModule(rtl_uString
*strModuleName
, sal_Int32
/*nRtldMode*/ )
44 #if OSL_DEBUG_LEVEL < 2
45 UINT errorMode
= SetErrorMode(SEM_NOOPENFILEERRORBOX
| SEM_FAILCRITICALERRORS
);
47 rtl_uString
* Module
= NULL
;
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);
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
)
90 ret
= (oslModule
) hInstance
;
91 rtl_uString_release(Module
);
92 #if OSL_DEBUG_LEVEL < 2
93 SetErrorMode(errorMode
);
96 RTL_LOGFILE_TRACE1( "} osl_loadModule end: %S", (LPTSTR
)&strModuleName
->buffer
);
101 /*****************************************************************************/
102 /* osl_loadModuleAscii */
103 /*****************************************************************************/
104 oslModule SAL_CALL
osl_loadModuleAscii(const sal_Char
*pModuleName
, sal_Int32 nRtldMode
)
106 (void) nRtldMode
; /* avoid warnings */
109 UINT errorMode
= SetErrorMode(SEM_NOOPENFILEERRORBOX
| SEM_FAILCRITICALERRORS
);
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
)
124 ret
= (oslModule
) hInstance
;
125 SetErrorMode(errorMode
);
127 RTL_LOGFILE_TRACE1( "} osl_loadModule end: %s", pModuleName
);
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 /*****************************************************************************/
143 osl_getModuleHandle(rtl_uString
*pModuleName
, oslModule
*pResult
)
145 LPCWSTR pName
= pModuleName
? reinterpret_cast<LPCWSTR
>(pModuleName
->buffer
) : NULL
;
146 HINSTANCE hInstance
= GetModuleHandleW(pName
);
149 *pResult
= (oslModule
) hInstance
;
156 /*****************************************************************************/
157 /* osl_unloadModule */
158 /*****************************************************************************/
159 void SAL_CALL
osl_unloadModule(oslModule Module
)
161 FreeLibrary((HINSTANCE
)Module
);
164 /*****************************************************************************/
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 */
174 #pragma warning(push)
175 #pragma warning(disable:4054)
177 return (void*)(osl_getFunctionSymbol(Module
, strSymbolName
));
183 /*****************************************************************************/
184 /* osl_getFunctionSymbol */
185 /*****************************************************************************/
186 oslGenericFunction SAL_CALL
osl_getFunctionSymbol( oslModule Module
, rtl_uString
*strSymbolName
)
188 rtl_String
*symbolName
= NULL
;
189 oslGenericFunction address
;
192 OSL_ASSERT(strSymbolName
);
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
);
208 /*****************************************************************************/
209 /* osl_getAsciiFunctionSymbol */
210 /*****************************************************************************/
211 oslGenericFunction SAL_CALL
212 osl_getAsciiFunctionSymbol( oslModule Module
, const sal_Char
*pSymbol
)
214 oslGenericFunction fncAddr
= NULL
;
217 fncAddr
=(oslGenericFunction
)GetProcAddress((HINSTANCE
) Module
, pSymbol
);
224 /*****************************************************************************/
225 /* osl_addressGetModuleURL */
226 /*****************************************************************************/
228 /*****************************************************************************/
229 /* Implementation for Windows 95, 98 and Me */
230 /*****************************************************************************/
232 /* Undefine because there is no explicit "A" definition */
238 #ifdef LPMODULEENTRY32
239 #undef LPMODULEENTRY32
242 /***************************************************************************************/
243 /* Implementation for Windows NT, 2K and XP (2K and XP could use the above method too) */
244 /***************************************************************************************/
247 #pragma warning(push,1) /* disable warnings within system headers */
249 #include <imagehlp.h>
254 typedef BOOL (WINAPI
*SymInitialize_PROC
)(
256 LPSTR UserSearchPath
,
260 typedef BOOL (WINAPI
*SymCleanup_PROC
)(
264 typedef BOOL (WINAPI
*SymGetModuleInfo_PROC
)(
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" );
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
, '\\' );
312 pLastBkSlash
> (sal_Char
*)aModuleFileName
313 && *(pLastBkSlash
- 1) != ':'
314 && *(pLastBkSlash
- 1) != '\\'
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
));
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
);
346 bSuccess
= sal_False
;
349 lpfnSymCleanup( GetCurrentProcess() );
352 FreeLibrary( hModImageHelp
);
359 typedef struct _MODULEINFO
{
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
;
387 hModPsapi
= LoadLibrary( "PSAPI.DLL" );
391 EnumProcessModules_PROC lpfnEnumProcessModules
= (EnumProcessModules_PROC
)GetProcAddress( hModPsapi
, "EnumProcessModules" );
392 GetModuleInformation_PROC lpfnGetModuleInformation
= (GetModuleInformation_PROC
)GetProcAddress( hModPsapi
, "GetModuleInformation" );
394 if ( lpfnEnumProcessModules
&& lpfnGetModuleInformation
)
397 HMODULE
*lpModules
= NULL
;
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
);
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. */
454 #pragma warning(push)
455 #pragma warning(disable:4054)
457 return osl_getModuleURLFromAddress((void*)addr
, ppLibraryUrl
);
464 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */