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 .
23 #include "file_url.hxx"
24 #include "path_helper.hxx"
26 #include <osl/module.h>
27 #include <osl/diagnose.h>
28 #include <osl/thread.h>
30 #include <sal/log.hxx>
31 #include <o3tl/char16_t2wchar_t.hxx>
35 under WIN32, we use the void* oslModule
36 as a WIN32 HANDLE (which is also a 32-bit value)
39 oslModule SAL_CALL
osl_loadModule(rtl_uString
*strModuleName
, sal_Int32
/*nRtldMode*/ )
42 #if OSL_DEBUG_LEVEL < 2
43 UINT errorMode
= SetErrorMode(SEM_NOOPENFILEERRORBOX
| SEM_FAILCRITICALERRORS
);
45 rtl_uString
* Module
= nullptr;
46 oslModule ret
= nullptr;
49 SAL_INFO( "sal.osl", "osl_loadModule: " << OUString(strModuleName
->buffer
, wcslen(o3tl::toW(strModuleName
->buffer
))) );
50 OSL_ASSERT(strModuleName
);
52 nError
= osl_getSystemPathFromFileURL(strModuleName
, &Module
);
54 if ( osl_File_E_None
!= nError
)
55 rtl_uString_assign(&Module
, strModuleName
);
57 h
= LoadLibraryW(o3tl::toW(Module
->buffer
));
60 h
= LoadLibraryExW(o3tl::toW(Module
->buffer
), nullptr, LOAD_WITH_ALTERED_SEARCH_PATH
);
62 // In case of long path names (\\?\c:\...) try to shorten the filename.
63 // LoadLibrary cannot handle file names which exceed 260 letters.
64 // In case the path is to long, the function will fail. However, the error
65 // code can be different. For example, it returned ERROR_FILENAME_EXCED_RANGE
66 // on Windows XP and ERROR_INSUFFICIENT_BUFFER on Windows 7 (64bit)
67 if (h
== nullptr && Module
->length
> 260)
69 std::vector
<WCHAR
> vec(Module
->length
+ 1);
70 DWORD len
= GetShortPathNameW(o3tl::toW(Module
->buffer
), &vec
[0], Module
->length
+ 1);
73 h
= LoadLibraryW(&vec
[0]);
76 h
= LoadLibraryExW(&vec
[0], nullptr, LOAD_WITH_ALTERED_SEARCH_PATH
);
80 ret
= static_cast<oslModule
>(h
);
81 rtl_uString_release(Module
);
82 #if OSL_DEBUG_LEVEL < 2
83 SetErrorMode(errorMode
);
89 oslModule SAL_CALL
osl_loadModuleAscii(const sal_Char
*pModuleName
, sal_Int32
)
92 UINT errorMode
= SetErrorMode(SEM_NOOPENFILEERRORBOX
| SEM_FAILCRITICALERRORS
);
93 oslModule ret
= nullptr;
95 SAL_INFO( "sal.osl", "osl_loadModule: " << pModuleName
);
96 OSL_ASSERT(pModuleName
);
98 h
= LoadLibraryA(pModuleName
);
100 h
= LoadLibraryExA(pModuleName
, nullptr,
101 LOAD_WITH_ALTERED_SEARCH_PATH
);
103 ret
= static_cast<oslModule
>(h
);
104 SetErrorMode(errorMode
);
109 oslModule
osl_loadModuleRelativeAscii(
110 oslGenericFunction
, char const * relativePath
, sal_Int32 mode
)
112 return osl_loadModuleAscii(relativePath
, mode
); //TODO: FIXME
116 osl_getModuleHandle(rtl_uString
*pModuleName
, oslModule
*pResult
)
118 LPCWSTR pName
= pModuleName
? o3tl::toW(pModuleName
->buffer
) : nullptr;
119 HMODULE h
= GetModuleHandleW(pName
);
122 *pResult
= static_cast<oslModule
>(h
);
129 void SAL_CALL
osl_unloadModule(oslModule Module
)
131 FreeLibrary(static_cast<HMODULE
>(Module
));
134 void* SAL_CALL
osl_getSymbol(oslModule Module
, rtl_uString
*strSymbolName
)
136 /* casting from a function pointer to a data pointer is invalid
137 be in this case unavoidable because the API has to stay
138 compatible. We need to keep this function which returns a
139 void* by definition */
141 #pragma warning(push)
142 #pragma warning(disable:4054)
144 return reinterpret_cast<void*>(osl_getFunctionSymbol(Module
, strSymbolName
));
150 oslGenericFunction SAL_CALL
osl_getFunctionSymbol( oslModule Module
, rtl_uString
*strSymbolName
)
152 rtl_String
*symbolName
= nullptr;
153 oslGenericFunction address
;
156 OSL_ASSERT(strSymbolName
);
160 strSymbolName
->buffer
,
161 strSymbolName
->length
,
162 RTL_TEXTENCODING_UTF8
,
163 OUSTRING_TO_OSTRING_CVTFLAGS
166 address
=osl_getAsciiFunctionSymbol(Module
, rtl_string_getStr(symbolName
));
167 rtl_string_release(symbolName
);
172 oslGenericFunction SAL_CALL
173 osl_getAsciiFunctionSymbol( oslModule Module
, const sal_Char
*pSymbol
)
175 oslGenericFunction fncAddr
= nullptr;
178 fncAddr
=reinterpret_cast<oslGenericFunction
>(GetProcAddress(static_cast<HMODULE
>(Module
), pSymbol
));
183 /*****************************************************************************/
184 /* Implementation for Windows 95, 98 and Me */
185 /*****************************************************************************/
187 /* Undefine because there is no explicit "A" definition */
193 #ifdef LPMODULEENTRY32
194 #undef LPMODULEENTRY32
197 /***************************************************************************************/
198 /* Implementation for Windows NT, 2K and XP (2K and XP could use the above method too) */
199 /***************************************************************************************/
201 #include <imagehlp.h>
203 typedef BOOL (WINAPI
*SymInitialize_PROC
)(
205 LPWSTR UserSearchPath
,
209 typedef BOOL (WINAPI
*SymCleanup_PROC
)(
213 typedef BOOL (WINAPI
*SymGetModuleInfo_PROC
)(
216 PIMAGEHLP_MODULEW ModuleInfo
219 /* 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
220 it's O.K on NT 4 ???!!!
221 BTW: We are using ANSI function because not all version of IMAGEHLP.DLL contain Unicode support
224 static bool osl_addressGetModuleURL_NT4_( void *pv
, rtl_uString
**pustrURL
)
226 bool bSuccess
= false; /* Assume failure */
228 /* IMAGEHELP.DLL has a bug that it recursively scans subdirectories of
229 the root when calling SymInitialize(), so we prefer DBGHELP.DLL
230 which exports the same symbols and is shipped with OOo */
232 HMODULE hModImageHelp
= LoadLibraryW( L
"DBGHELP.DLL" );
234 if ( !hModImageHelp
)
235 hModImageHelp
= LoadLibraryW( L
"IMAGEHLP.DLL" );
239 SymGetModuleInfo_PROC lpfnSymGetModuleInfo
;
240 SymInitialize_PROC lpfnSymInitialize
;
241 SymCleanup_PROC lpfnSymCleanup
;
243 lpfnSymInitialize
= reinterpret_cast<SymInitialize_PROC
>(GetProcAddress( hModImageHelp
, "SymInitializeW" ));
244 lpfnSymCleanup
= reinterpret_cast<SymCleanup_PROC
>(GetProcAddress( hModImageHelp
, "SymCleanup" ));
245 lpfnSymGetModuleInfo
= reinterpret_cast<SymGetModuleInfo_PROC
>(GetProcAddress( hModImageHelp
, "SymGetModuleInfoW" ));
247 if ( lpfnSymInitialize
&& lpfnSymCleanup
&& lpfnSymGetModuleInfo
)
249 IMAGEHLP_MODULEW ModuleInfo
;
250 ::osl::LongPathBuffer
< sal_Unicode
> aModuleFileName( MAX_LONG_PATH
);
251 LPWSTR lpSearchPath
= nullptr;
253 if ( GetModuleFileNameW( nullptr, o3tl::toW(aModuleFileName
), aModuleFileName
.getBufSizeInSymbols() ) )
255 wchar_t *pLastBkSlash
= wcsrchr( o3tl::toW(aModuleFileName
), L
'\\' );
259 pLastBkSlash
> o3tl::toW(aModuleFileName
)
260 && *(pLastBkSlash
- 1) != L
':'
261 && *(pLastBkSlash
- 1) != L
'\\'
265 lpSearchPath
= o3tl::toW(aModuleFileName
);
269 lpfnSymInitialize( GetCurrentProcess(), lpSearchPath
, TRUE
);
271 ZeroMemory( &ModuleInfo
, sizeof(ModuleInfo
) );
272 ModuleInfo
.SizeOfStruct
= sizeof(ModuleInfo
);
274 bSuccess
= !!lpfnSymGetModuleInfo( GetCurrentProcess(), reinterpret_cast<DWORD_PTR
>(pv
), &ModuleInfo
);
278 /* #99182 On localized (non-english) NT4 and XP (!!!) for some libraries the LoadedImageName member of ModuleInfo isn't filled. Because
279 other members ModuleName and ImageName do not contain the full path we can cast the Member
280 BaseOfImage to a HMODULE (on NT it's the same) and use GetModuleFileName to retrieve the full
281 path of the loaded image */
283 if ( ModuleInfo
.LoadedImageName
[0] || GetModuleFileNameW( reinterpret_cast<HMODULE
>(ModuleInfo
.BaseOfImage
), ModuleInfo
.LoadedImageName
, SAL_N_ELEMENTS(ModuleInfo
.LoadedImageName
) ) )
285 rtl_uString
*ustrSysPath
= nullptr;
287 rtl_uString_newFromStr( &ustrSysPath
, o3tl::toU(ModuleInfo
.LoadedImageName
) );
288 OSL_ASSERT(ustrSysPath
!= nullptr);
289 osl_getFileURLFromSystemPath( ustrSysPath
, pustrURL
);
290 rtl_uString_release( ustrSysPath
);
296 lpfnSymCleanup( GetCurrentProcess() );
299 FreeLibrary( hModImageHelp
);
305 typedef struct MODULEINFO
{
311 typedef BOOL (WINAPI
*EnumProcessModules_PROC
)(
312 HANDLE hProcess
, // handle to the process
313 HMODULE
* lphModule
, // array to receive the module handles
314 DWORD cb
, // size of the array
315 LPDWORD lpcbNeeded
// receives the number of bytes returned
318 typedef BOOL (WINAPI
*GetModuleInformation_PROC
)(
319 HANDLE hProcess
, // handle to the process
320 HMODULE hModule
, // handle to the module
321 LPMODULEINFO lpmodinfo
, // structure that receives information
322 DWORD cb
// size of the structure
325 /* This version can fail because PSAPI.DLL is not always part of NT 4 despite MSDN Library 6.0a say so */
327 static bool osl_addressGetModuleURL_NT_( void *pv
, rtl_uString
**pustrURL
)
329 bool bSuccess
= false; /* Assume failure */
330 static HMODULE hModPsapi
= nullptr;
333 hModPsapi
= LoadLibraryW( L
"PSAPI.DLL" );
337 EnumProcessModules_PROC lpfnEnumProcessModules
= reinterpret_cast<EnumProcessModules_PROC
>(GetProcAddress( hModPsapi
, "EnumProcessModules" ));
338 GetModuleInformation_PROC lpfnGetModuleInformation
= reinterpret_cast<GetModuleInformation_PROC
>(GetProcAddress( hModPsapi
, "GetModuleInformation" ));
340 if ( lpfnEnumProcessModules
&& lpfnGetModuleInformation
)
343 HMODULE
*lpModules
= nullptr;
348 lpfnEnumProcessModules( GetCurrentProcess(), nullptr, 0, &cbNeeded
);
350 lpModules
= static_cast<HMODULE
*>(_alloca( cbNeeded
));
351 lpfnEnumProcessModules( GetCurrentProcess(), lpModules
, cbNeeded
, &cbNeeded
);
353 nModules
= cbNeeded
/ sizeof(HMODULE
);
355 for ( iModule
= 0; !bSuccess
&& iModule
< nModules
; iModule
++ )
357 lpfnGetModuleInformation( GetCurrentProcess(), lpModules
[iModule
], &modinfo
, sizeof(modinfo
) );
359 if ( static_cast<BYTE
*>(pv
) >= static_cast<BYTE
*>(modinfo
.lpBaseOfDll
) && static_cast<BYTE
*>(pv
) < static_cast<BYTE
*>(modinfo
.lpBaseOfDll
) + modinfo
.SizeOfImage
)
361 ::osl::LongPathBuffer
< sal_Unicode
> aBuffer( MAX_LONG_PATH
);
362 rtl_uString
*ustrSysPath
= nullptr;
364 GetModuleFileNameW( lpModules
[iModule
], o3tl::toW(aBuffer
), aBuffer
.getBufSizeInSymbols() );
366 rtl_uString_newFromStr( &ustrSysPath
, aBuffer
);
367 osl_getFileURLFromSystemPath( ustrSysPath
, pustrURL
);
368 rtl_uString_release( ustrSysPath
);
380 sal_Bool SAL_CALL
osl_getModuleURLFromAddress( void *pv
, rtl_uString
**pustrURL
)
382 /* Use ..._NT first because ..._NT4 is much slower */
383 return osl_addressGetModuleURL_NT_( pv
, pustrURL
) || osl_addressGetModuleURL_NT4_( pv
, pustrURL
);
386 sal_Bool SAL_CALL
osl_getModuleURLFromFunctionAddress( oslGenericFunction addr
, rtl_uString
** ppLibraryUrl
)
388 /* casting a function pointer to a data pointer (void*) is
389 not allowed according to the C/C++ standards. In this case
390 it is unavoidable because we have to stay compatible we
391 cannot remove any function. */
393 #pragma warning(push)
394 #pragma warning(disable:4054)
396 return osl_getModuleURLFromAddress(reinterpret_cast<void*>(addr
), ppLibraryUrl
);
402 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */