1
0
Fork 0
libreoffice/comphelper/source/windows/windows_process.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

262 lines
6.6 KiB
C++

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <cstring>
#include <wchar.h>
#include <comphelper/windowsStart.hxx>
// Needed for CreateEnvironmentBlock
#include <userenv.h>
#pragma comment(lib, "userenv.lib")
/**
* Get the length that the string will take and takes into account the
* additional length if the string needs to be quoted and if characters need to
* be escaped.
*/
static int ArgStrLen(const wchar_t *s)
{
int i = wcslen(s);
bool hasDoubleQuote = wcschr(s, L'"') != nullptr;
// Only add doublequotes if the string contains a space or a tab
bool addDoubleQuotes = wcspbrk(s, L" \t") != nullptr;
if (addDoubleQuotes)
{
i += 2; // initial and final doublequote
}
if (hasDoubleQuote)
{
int backslashes = 0;
while (*s)
{
if (*s == '\\')
{
++backslashes;
}
else
{
if (*s == '"')
{
// Escape the doublequote and all backslashes preceding the doublequote
i += backslashes + 1;
}
backslashes = 0;
}
++s;
}
}
return i;
}
/**
* Copy string "s" to string "d", quoting the argument as appropriate and
* escaping doublequotes along with any backslashes that immediately precede
* doublequotes.
* The CRT parses this to retrieve the original argc/argv that we meant,
* see STDARGV.C in the MSVC CRT sources.
*
* @return the end of the string
*/
static wchar_t* ArgToString(wchar_t *d, const wchar_t *s)
{
bool hasDoubleQuote = wcschr(s, L'"') != nullptr;
// Only add doublequotes if the string contains a space or a tab
bool addDoubleQuotes = wcspbrk(s, L" \t") != nullptr;
if (addDoubleQuotes)
{
*d = '"'; // initial doublequote
++d;
}
if (hasDoubleQuote)
{
int backslashes = 0;
while (*s)
{
if (*s == '\\')
{
++backslashes;
}
else
{
if (*s == '"')
{
// Escape the doublequote and all backslashes preceding the doublequote
for (int i = 0; i <= backslashes; ++i)
{
*d = '\\';
++d;
}
}
backslashes = 0;
}
*d = *s;
++d;
++s;
}
}
else
{
wcscpy(d, s);
d += wcslen(s);
}
if (addDoubleQuotes)
{
*d = '"'; // final doublequote
++d;
}
return d;
}
/**
* Creates a command line from a list of arguments. The returned
* string is allocated with "malloc" and should be "free"d.
*
* argv is UTF8
*/
wchar_t*
MakeCommandLine(int argc, wchar_t **argv)
{
int i;
int len = 0;
// The + 1 of the last argument handles the allocation for null termination
for (i = 0; i < argc && argv[i]; ++i)
len += ArgStrLen(argv[i]) + 1;
// Protect against callers that pass 0 arguments
if (len == 0)
len = 1;
wchar_t *s = static_cast<wchar_t*>(malloc(len * sizeof(wchar_t)));
if (!s)
return nullptr;
wchar_t *c = s;
for (i = 0; i < argc && argv[i]; ++i)
{
c = ArgToString(c, argv[i]);
if (i + 1 != argc)
{
*c = ' ';
++c;
}
}
*c = '\0';
return s;
}
BOOL
WinLaunchChild(const wchar_t *exePath,
int argc,
wchar_t **argv,
HANDLE userToken,
HANDLE *hProcess)
{
wchar_t *cl;
bool ok;
cl = MakeCommandLine(argc, argv);
if (!cl)
{
return FALSE;
}
STARTUPINFOW si;
std::memset(&si, 0, sizeof si);
si.cb = sizeof(STARTUPINFOW);
si.lpDesktop = const_cast<LPWSTR>(L"winsta0\\Default");
PROCESS_INFORMATION pi;
std::memset(&pi, 0, sizeof pi);
if (userToken == nullptr)
{
ok = CreateProcessW(exePath,
cl,
nullptr, // no special security attributes
nullptr, // no special thread attributes
FALSE, // don't inherit filehandles
0, // creation flags
nullptr, // inherit my environment
nullptr, // use my current directory
&si,
&pi);
}
else
{
// Create an environment block for the process we're about to start using
// the user's token.
LPVOID environmentBlock = nullptr;
if (!CreateEnvironmentBlock(&environmentBlock, userToken, TRUE))
{
environmentBlock = nullptr;
}
ok = CreateProcessAsUserW(userToken,
exePath,
cl,
nullptr, // no special security attributes
nullptr, // no special thread attributes
FALSE, // don't inherit filehandles
0, // creation flags
environmentBlock,
nullptr, // use my current directory
&si,
&pi);
if (environmentBlock)
{
DestroyEnvironmentBlock(environmentBlock);
}
}
if (ok)
{
if (hProcess)
{
*hProcess = pi.hProcess; // the caller now owns the HANDLE
}
else
{
CloseHandle(pi.hProcess);
}
CloseHandle(pi.hThread);
}
else
{
LPWSTR lpMsgBuf = nullptr;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&lpMsgBuf),
0,
nullptr);
wprintf(L"Error restarting: %s\n", lpMsgBuf ? lpMsgBuf : L"(null)");
if (lpMsgBuf)
HeapFree(GetProcessHeap(), 0, lpMsgBuf);
}
free(cl);
return ok;
}