Kaydet (Commit) 9990e98d authored tarafından Michael Stahl's avatar Michael Stahl

tdf#109241 desktop: Win32: prepend "program" dir to $PATH

The problem is that python modules (*.pyd) find DLLs in the wrong
places.

This is because sal_detail_initialize() calls SetDllDirectoryW(""),
which removes (sometimes?) the "current directory" from the DLL
search order, which is deliberately initialized to the "program"
dir by CreateProcess() calls in officewrapper.cxx.

Loading DLLs still works for LO's own DLLs since they are all
in the "program" directory, which is the same directory where
all the executables are, so it is searched first.

But CPython loads its modules with LOAD_WITH_ALTERED_SEARCH_PATH,
which doesn't search the directory of the executable but
the directory of the immediately loaded DLL i.e. the *.pyd file
instead, i.e. python-core-X.Y.Z/lib.

It would be possible to call SetDllDirectory(".../program")
instead but probably that would require patching python
since it needs to be done in the real exectuable, not in
the wrapper executable.

So overwrite the $PATH again (like was done in the days of
the office of the holy trinity) in the officewrapper.cxx and
genericloader.cxx to prepend "program" and get priority
over the rest of $PATH.

This still doesn't protect against C:/Windows/System32/LIBEAY32.DLL
since that has higher priority than $PATH but hopefully nobody
is *that* stupid.

This patch fixes soffice.exe, swriter.exe etc., and unopkg.exe.

The python.exe wrapper already prepends "program" to $PATH.

Change-Id: If03f07eba9a2c7fc6cf44f82f639b5d0b4c62e20
üst 5ec9882e
......@@ -47,7 +47,7 @@ static int GenericMain()
TCHAR szIniDirectory[MAX_PATH];
STARTUPINFO aStartupInfo;
desktop_win32::getPaths(szTargetFileName, szIniDirectory);
desktop_win32::extendLoaderEnvironment(szTargetFileName, szIniDirectory);
ZeroMemory( &aStartupInfo, sizeof(aStartupInfo) );
aStartupInfo.cb = sizeof(aStartupInfo);
......
......@@ -33,17 +33,28 @@
#include "loader.hxx"
#include <cassert>
namespace {
void fail()
{
LPWSTR buf = nullptr;
FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, nullptr,
GetLastError(), 0, reinterpret_cast< LPWSTR >(&buf), 0, nullptr);
MessageBoxW(nullptr, buf, nullptr, MB_OK | MB_ICONERROR);
LocalFree(buf);
TerminateProcess(GetCurrentProcess(), 255);
}
}
namespace desktop_win32 {
void getPaths(WCHAR * binPath, WCHAR * iniDirectory) {
void extendLoaderEnvironment(WCHAR * binPath, WCHAR * iniDirectory) {
if (!GetModuleFileNameW(nullptr, iniDirectory, MAX_PATH)) {
LPWSTR buf = nullptr;
FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, nullptr,
GetLastError(), 0, reinterpret_cast< LPWSTR >(&buf), 0, nullptr);
MessageBoxW(nullptr, buf, nullptr, MB_OK | MB_ICONERROR);
LocalFree(buf);
TerminateProcess(GetCurrentProcess(), 255);
fail();
}
WCHAR * iniDirEnd = tools::filename(iniDirectory);
WCHAR name[MAX_PATH + MY_LENGTH(L".bin")];
......@@ -65,6 +76,32 @@ void getPaths(WCHAR * binPath, WCHAR * iniDirectory) {
nameEnd[-1] = 'n';
tools::buildPath(binPath, iniDirectory, iniDirEnd, name, nameEnd - name);
*iniDirEnd = L'\0';
std::size_t const maxEnv = 32767;
WCHAR env[maxEnv];
DWORD n = GetEnvironmentVariableW(L"PATH", env, maxEnv);
if ((n >= maxEnv || n == 0) && GetLastError() != ERROR_ENVVAR_NOT_FOUND) {
fail();
}
// must be first in PATH to override other entries
assert(*(iniDirEnd - 1) == L'\\'); // hence -1 below
if (wcsncmp(env, iniDirectory, iniDirEnd - iniDirectory - 1) != 0
|| env[iniDirEnd - iniDirectory - 1] != L';')
{
WCHAR pad[MAX_PATH + maxEnv];
// hopefully std::size_t is large enough to not overflow
WCHAR * p = commandLineAppend(pad, iniDirectory, iniDirEnd - iniDirectory - 1);
if (n != 0) {
*p++ = L';';
for (DWORD i = 0; i <= n; ++i) {
*p++ = env[i];
}
} else {
*p++ = L'\0';
}
if (!SetEnvironmentVariableW(L"PATH", pad)) {
fail();
}
}
}
}
......
......@@ -68,6 +68,8 @@ inline WCHAR * commandLineAppendEncoded(WCHAR * buffer, WCHAR const * text) {
return buffer;
}
// Set the PATH environment variable in the current (loader) process, so that a
// following CreateProcess has the necessary environment:
// @param binPath
// Must point to an array of size at least MAX_PATH. Is filled with the null
// terminated full path to the "bin" file corresponding to the current
......@@ -76,7 +78,7 @@ inline WCHAR * commandLineAppendEncoded(WCHAR * buffer, WCHAR const * text) {
// Must point to an array of size at least MAX_PATH. Is filled with the null
// terminated full directory path (ending in "\") to the "ini" file
// corresponding to the current executable.
void getPaths(WCHAR * binPath, WCHAR * iniDirectory);
void extendLoaderEnvironment(WCHAR * binPath, WCHAR * iniDirectory);
}
......
......@@ -62,7 +62,7 @@ int WINAPI _tWinMain( HINSTANCE, HINSTANCE, LPTSTR, int )
TCHAR szIniDirectory[MAX_PATH];
STARTUPINFO aStartupInfo;
desktop_win32::getPaths(szTargetFileName, szIniDirectory);
desktop_win32::extendLoaderEnvironment(szTargetFileName, szIniDirectory);
ZeroMemory( &aStartupInfo, sizeof(aStartupInfo) );
aStartupInfo.cb = sizeof(aStartupInfo);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment