Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / comphelper / source / windows / windows_process.cxx
blob7588bae027e5e65cbb5fb9b506f119cae1fc75ae
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #define WIN32_LEAN_AND_MEAN
6 #include <windows.h>
8 #include <cstring>
9 #include <wchar.h>
11 #include <comphelper/windowsStart.hxx>
13 // Needed for CreateEnvironmentBlock
14 #include <userenv.h>
15 #pragma comment(lib, "userenv.lib")
17 /**
18 * Get the length that the string will take and takes into account the
19 * additional length if the string needs to be quoted and if characters need to
20 * be escaped.
22 static int ArgStrLen(const wchar_t *s)
24 int i = wcslen(s);
25 bool hasDoubleQuote = wcschr(s, L'"') != nullptr;
26 // Only add doublequotes if the string contains a space or a tab
27 bool addDoubleQuotes = wcspbrk(s, L" \t") != nullptr;
29 if (addDoubleQuotes)
31 i += 2; // initial and final doublequote
34 if (hasDoubleQuote)
36 int backslashes = 0;
37 while (*s)
39 if (*s == '\\')
41 ++backslashes;
43 else
45 if (*s == '"')
47 // Escape the doublequote and all backslashes preceding the doublequote
48 i += backslashes + 1;
51 backslashes = 0;
54 ++s;
58 return i;
61 /**
62 * Copy string "s" to string "d", quoting the argument as appropriate and
63 * escaping doublequotes along with any backslashes that immediately precede
64 * doublequotes.
65 * The CRT parses this to retrieve the original argc/argv that we meant,
66 * see STDARGV.C in the MSVC CRT sources.
68 * @return the end of the string
70 static wchar_t* ArgToString(wchar_t *d, const wchar_t *s)
72 bool hasDoubleQuote = wcschr(s, L'"') != nullptr;
73 // Only add doublequotes if the string contains a space or a tab
74 bool addDoubleQuotes = wcspbrk(s, L" \t") != nullptr;
76 if (addDoubleQuotes)
78 *d = '"'; // initial doublequote
79 ++d;
82 if (hasDoubleQuote)
84 int backslashes = 0;
85 while (*s)
87 if (*s == '\\')
89 ++backslashes;
91 else
93 if (*s == '"')
95 // Escape the doublequote and all backslashes preceding the doublequote
96 for (int i = 0; i <= backslashes; ++i)
98 *d = '\\';
99 ++d;
103 backslashes = 0;
106 *d = *s;
107 ++d;
108 ++s;
111 else
113 wcscpy(d, s);
114 d += wcslen(s);
117 if (addDoubleQuotes)
119 *d = '"'; // final doublequote
120 ++d;
123 return d;
127 * Creates a command line from a list of arguments. The returned
128 * string is allocated with "malloc" and should be "free"d.
130 * argv is UTF8
132 wchar_t*
133 MakeCommandLine(int argc, wchar_t **argv)
135 int i;
136 int len = 0;
138 // The + 1 of the last argument handles the allocation for null termination
139 for (i = 0; i < argc && argv[i]; ++i)
140 len += ArgStrLen(argv[i]) + 1;
142 // Protect against callers that pass 0 arguments
143 if (len == 0)
144 len = 1;
146 wchar_t *s = static_cast<wchar_t*>(malloc(len * sizeof(wchar_t)));
147 if (!s)
148 return nullptr;
150 wchar_t *c = s;
151 for (i = 0; i < argc && argv[i]; ++i)
153 c = ArgToString(c, argv[i]);
154 if (i + 1 != argc)
156 *c = ' ';
157 ++c;
161 *c = '\0';
163 return s;
166 BOOL
167 WinLaunchChild(const wchar_t *exePath,
168 int argc,
169 wchar_t **argv,
170 HANDLE userToken,
171 HANDLE *hProcess)
173 wchar_t *cl;
174 bool ok;
176 cl = MakeCommandLine(argc, argv);
177 if (!cl)
179 return FALSE;
182 STARTUPINFOW si;
183 std::memset(&si, 0, sizeof si);
184 si.cb = sizeof(STARTUPINFOW);
185 si.lpDesktop = const_cast<LPWSTR>(L"winsta0\\Default");
186 PROCESS_INFORMATION pi;
187 std::memset(&pi, 0, sizeof pi);
189 if (userToken == nullptr)
191 ok = CreateProcessW(exePath,
193 nullptr, // no special security attributes
194 nullptr, // no special thread attributes
195 FALSE, // don't inherit filehandles
196 0, // creation flags
197 nullptr, // inherit my environment
198 nullptr, // use my current directory
199 &si,
200 &pi);
202 else
204 // Create an environment block for the process we're about to start using
205 // the user's token.
206 LPVOID environmentBlock = nullptr;
207 if (!CreateEnvironmentBlock(&environmentBlock, userToken, TRUE))
209 environmentBlock = nullptr;
212 ok = CreateProcessAsUserW(userToken,
213 exePath,
215 nullptr, // no special security attributes
216 nullptr, // no special thread attributes
217 FALSE, // don't inherit filehandles
218 0, // creation flags
219 environmentBlock,
220 nullptr, // use my current directory
221 &si,
222 &pi);
224 if (environmentBlock)
226 DestroyEnvironmentBlock(environmentBlock);
230 if (ok)
232 if (hProcess)
234 *hProcess = pi.hProcess; // the caller now owns the HANDLE
236 else
238 CloseHandle(pi.hProcess);
240 CloseHandle(pi.hThread);
242 else
244 LPVOID lpMsgBuf = nullptr;
245 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
246 FORMAT_MESSAGE_FROM_SYSTEM |
247 FORMAT_MESSAGE_IGNORE_INSERTS,
248 nullptr,
249 GetLastError(),
250 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
251 reinterpret_cast<LPWSTR>(&lpMsgBuf),
253 nullptr);
254 wprintf(L"Error restarting: %s\n", lpMsgBuf ? lpMsgBuf : L"(null)");
255 if (lpMsgBuf)
256 HeapFree(GetProcessHeap(), 0, lpMsgBuf);
259 free(cl);
261 return ok;