From b9d709e84728270acb00c3952551f5c608260e62 Mon Sep 17 00:00:00 2001 From: Mike Kaganski Date: Sun, 8 Apr 2018 00:47:18 +0100 Subject: tdf#94265: use install directory on delay load failure This partially reverts commit 827430c8c0417396b3c1d2a049ccddb818c89646 Change-Id: Ia5d609040a3b355659e780e0606ce4bff0d22509 Reviewed-on: https://gerrit.libreoffice.org/52572 Tested-by: Jenkins Reviewed-by: Stephan Bergmann --- cli_ure/source/native/native_bootstrap.cxx | 160 +++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/cli_ure/source/native/native_bootstrap.cxx b/cli_ure/source/native/native_bootstrap.cxx index 0ec2375a1c78..f26a634c2aa1 100644 --- a/cli_ure/source/native/native_bootstrap.cxx +++ b/cli_ure/source/native/native_bootstrap.cxx @@ -22,7 +22,167 @@ #include "rtl/bootstrap.hxx" #include "com/sun/star/uno/XComponentContext.hpp" #include "cppuhelper/bootstrap.hxx" +#include #include +#define WIN32_LEAN_AND_MEAN +#include +#include + +#define INSTALL_PATH L"Software\\LibreOffice\\UNO\\InstallPath" +#define UNO_PATH L"UNO_PATH" + +namespace { + +/* Gets the installation path from the Windows Registry for the specified + registry key. + + @param hroot open handle to predefined root registry key + @param subKeyName name of the subkey to open + + @return the installation path or nullptr, if no installation was found or + if an error occurred +*/ +WCHAR* getPathFromRegistryKey( HKEY hroot, LPCWSTR subKeyName ) +{ + // open the specified registry key + HKEY hkey; + if ( RegOpenKeyExW( hroot, subKeyName, 0, KEY_READ, &hkey ) != ERROR_SUCCESS ) + return nullptr; + + struct CloseKeyGuard { + HKEY m_hkey; + ~CloseKeyGuard() { RegCloseKey( m_hkey ); } + } aCloseKeyGuard{hkey}; + + // find the type and size of the default value + DWORD type; + DWORD size; + if ( RegQueryValueExW( hkey, nullptr, nullptr, &type, nullptr, &size ) != ERROR_SUCCESS ) + return nullptr; + + // get memory to hold the default value + std::unique_ptr data(new WCHAR[size]); + + // read the default value + if ( RegQueryValueExW( hkey, nullptr, nullptr, &type, reinterpret_cast(data.get()), &size ) != ERROR_SUCCESS ) + return nullptr; + + return data.release(); +} + +/* Returns the path to the program folder of the brand layer, + for example C:/Program Files/LibreOffice/program + This path is either obtained from the environment variable UNO_PATH + or the registry item "Software\\LibreOffice\\UNO\\InstallPath" + either in HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE + The return value must be freed with delete[] +*/ +WCHAR* getInstallPath() +{ + std::unique_ptr szInstallPath; + + DWORD cChars = GetEnvironmentVariableW(UNO_PATH, nullptr, 0); + if (cChars > 0) + { + szInstallPath.reset(new WCHAR[cChars]); + cChars = GetEnvironmentVariableW(UNO_PATH, szInstallPath.get(), cChars); + // If PATH is not set then it is no error + if (cChars == 0) + return nullptr; + } + + if (! szInstallPath) + { + szInstallPath.reset(getPathFromRegistryKey( HKEY_CURRENT_USER, INSTALL_PATH )); + if (! szInstallPath) + { + // read the key's default value from HKEY_LOCAL_MACHINE + szInstallPath.reset(getPathFromRegistryKey( HKEY_LOCAL_MACHINE, INSTALL_PATH )); + } + } + return szInstallPath.release(); +} + +/* We extend the path to contain the install folder, + so that components can use osl_loadModule with arguments, such as + "reg3.dll". That is, the arguments are only the library names. +*/ +void extendPath(LPCWSTR szPath) +{ + if (!szPath) + return; + + std::unique_ptr sEnvPath; + DWORD cChars = GetEnvironmentVariableW(L"PATH", nullptr, 0); + if (cChars > 0) + { + sEnvPath.reset(new WCHAR[cChars]); + cChars = GetEnvironmentVariableW(L"PATH", sEnvPath.get(), cChars); + // If PATH is not set then it is no error + if (cChars == 0 && GetLastError() != ERROR_ENVVAR_NOT_FOUND) + return; + } + // Prepare the new PATH. Add the directory at the front. + // Note also adding ';' + std::unique_ptr sNewPath(new WCHAR[lstrlenW(sEnvPath.get()) + lstrlenW(szPath) + 2]); + lstrcpyW(sNewPath.get(), szPath); + if (lstrlenW(sEnvPath.get())) + { + lstrcatW(sNewPath.get(), L";"); + lstrcatW(sNewPath.get(), sEnvPath.get()); + } + SetEnvironmentVariableW(L"PATH", sNewPath.get()); +} + +HMODULE loadFromPath(LPCSTR sLibName) +{ + if (!sLibName) + return nullptr; + + // Convert the ansi file name to wchar_t* + int size = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, sLibName, -1, nullptr, 0); + if (size == 0) + return nullptr; + std::unique_ptr wsLibName(new WCHAR[size]); + if (!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, sLibName, -1, wsLibName.get(), size)) + return nullptr; + + std::unique_ptr szPath(getInstallPath()); + if (!szPath) + return nullptr; + + extendPath(szPath.get()); + + std::unique_ptr szFullPath(new WCHAR[lstrlenW(wsLibName.get()) + lstrlenW(szPath.get()) + 2]); + lstrcpyW(szFullPath.get(), szPath.get()); + lstrcatW(szFullPath.get(), L"\\"); + lstrcatW(szFullPath.get(), wsLibName.get()); + HMODULE handle = LoadLibraryW(szFullPath.get()); + return handle; +} + +/* Hook for delayed loading of libraries which this library is linked with. + This is a failure hook. That is, it is only called when the loading of + a library failed. It will be called when loading of cppuhelper failed. + Because we extend the PATH to the install folder while this function is + executed (see extendPath), all other libraries are found. +*/ +extern "C" FARPROC WINAPI delayLoadHook( + unsigned int dliNotify, + PDelayLoadInfo pdli + ) +{ + if (dliNotify == dliFailLoadLib) + { + HANDLE h = loadFromPath(pdli->szDll); + return reinterpret_cast(h); + } + return nullptr; +} +} + +ExternC +const PfnDliHook __pfnDliFailureHook2 = delayLoadHook; using namespace ::com::sun::star; using namespace ::com::sun::star::uno; -- cgit