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 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);
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
)
89 ret
= (oslModule
) hInstance
;
90 rtl_uString_release(Module
);
91 #if OSL_DEBUG_LEVEL < 2
92 SetErrorMode(errorMode
);
95 SAL_INFO( "sal.osl", "} osl_loadModule end: " << (LPTSTR
)&strModuleName
->buffer
);
99 /*****************************************************************************/
100 /* osl_loadModuleAscii */
101 /*****************************************************************************/
102 oslModule SAL_CALL
osl_loadModuleAscii(const sal_Char
*pModuleName
, sal_Int32 nRtldMode
)
104 (void) nRtldMode
; /* avoid warnings */
107 UINT errorMode
= SetErrorMode(SEM_NOOPENFILEERRORBOX
| SEM_FAILCRITICALERRORS
);
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
)
121 ret
= (oslModule
) hInstance
;
122 SetErrorMode(errorMode
);
124 SAL_INFO( "sal.osl", "} osl_loadModule end: " << pModuleName
);
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 /*****************************************************************************/
139 osl_getModuleHandle(rtl_uString
*pModuleName
, oslModule
*pResult
)
141 LPCWSTR pName
= pModuleName
? reinterpret_cast<LPCWSTR
>(pModuleName
->buffer
) : NULL
;
142 HINSTANCE hInstance
= GetModuleHandleW(pName
);
145 *pResult
= (oslModule
) hInstance
;
152 /*****************************************************************************/
153 /* osl_unloadModule */
154 /*****************************************************************************/
155 void SAL_CALL
osl_unloadModule(oslModule Module
)
157 FreeLibrary((HINSTANCE
)Module
);
160 /*****************************************************************************/
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 */
170 #pragma warning(push)
171 #pragma warning(disable:4054)
173 return (void*)(osl_getFunctionSymbol(Module
, strSymbolName
));
179 /*****************************************************************************/
180 /* osl_getFunctionSymbol */
181 /*****************************************************************************/
182 oslGenericFunction SAL_CALL
osl_getFunctionSymbol( oslModule Module
, rtl_uString
*strSymbolName
)
184 rtl_String
*symbolName
= NULL
;
185 oslGenericFunction address
;
188 OSL_ASSERT(strSymbolName
);
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
);
204 /*****************************************************************************/
205 /* osl_getAsciiFunctionSymbol */
206 /*****************************************************************************/
207 oslGenericFunction SAL_CALL
208 osl_getAsciiFunctionSymbol( oslModule Module
, const sal_Char
*pSymbol
)
210 oslGenericFunction fncAddr
= NULL
;
213 fncAddr
=(oslGenericFunction
)GetProcAddress((HINSTANCE
) Module
, pSymbol
);
220 /*****************************************************************************/
221 /* osl_addressGetModuleURL */
222 /*****************************************************************************/
224 /*****************************************************************************/
225 /* Implementation for Windows 95, 98 and Me */
226 /*****************************************************************************/
228 /* Undefine because there is no explicit "A" definition */
234 #ifdef LPMODULEENTRY32
235 #undef LPMODULEENTRY32
238 /***************************************************************************************/
239 /* Implementation for Windows NT, 2K and XP (2K and XP could use the above method too) */
240 /***************************************************************************************/
243 #pragma warning(push,1) /* disable warnings within system headers */
245 #include <imagehlp.h>
250 typedef BOOL (WINAPI
*SymInitialize_PROC
)(
252 LPSTR UserSearchPath
,
256 typedef BOOL (WINAPI
*SymCleanup_PROC
)(
260 typedef BOOL (WINAPI
*SymGetModuleInfo_PROC
)(
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" );
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
, '\\' );
308 pLastBkSlash
> (sal_Char
*)aModuleFileName
309 && *(pLastBkSlash
- 1) != ':'
310 && *(pLastBkSlash
- 1) != '\\'
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
));
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
);
342 bSuccess
= sal_False
;
345 lpfnSymCleanup( GetCurrentProcess() );
348 FreeLibrary( hModImageHelp
);
355 typedef struct _MODULEINFO
{
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
;
383 hModPsapi
= LoadLibrary( "PSAPI.DLL" );
387 EnumProcessModules_PROC lpfnEnumProcessModules
= (EnumProcessModules_PROC
)GetProcAddress( hModPsapi
, "EnumProcessModules" );
388 GetModuleInformation_PROC lpfnGetModuleInformation
= (GetModuleInformation_PROC
)GetProcAddress( hModPsapi
, "GetModuleInformation" );
390 if ( lpfnEnumProcessModules
&& lpfnGetModuleInformation
)
393 HMODULE
*lpModules
= NULL
;
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
);
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. */
450 #pragma warning(push)
451 #pragma warning(disable:4054)
453 return osl_getModuleURLFromAddress((void*)addr
, ppLibraryUrl
);
460 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */