LibreOffice Module comphelper (master) 1
windows_process.cxx
Go to the documentation of this file.
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/. */
4
5#define WIN32_LEAN_AND_MEAN
6#include <windows.h>
7
8#include <cstring>
9#include <wchar.h>
10
12
13// Needed for CreateEnvironmentBlock
14#include <userenv.h>
15#pragma comment(lib, "userenv.lib")
16
22static int ArgStrLen(const wchar_t *s)
23{
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;
28
29 if (addDoubleQuotes)
30 {
31 i += 2; // initial and final doublequote
32 }
33
34 if (hasDoubleQuote)
35 {
36 int backslashes = 0;
37 while (*s)
38 {
39 if (*s == '\\')
40 {
41 ++backslashes;
42 }
43 else
44 {
45 if (*s == '"')
46 {
47 // Escape the doublequote and all backslashes preceding the doublequote
48 i += backslashes + 1;
49 }
50
51 backslashes = 0;
52 }
53
54 ++s;
55 }
56 }
57
58 return i;
59}
60
70static wchar_t* ArgToString(wchar_t *d, const wchar_t *s)
71{
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;
75
76 if (addDoubleQuotes)
77 {
78 *d = '"'; // initial doublequote
79 ++d;
80 }
81
82 if (hasDoubleQuote)
83 {
84 int backslashes = 0;
85 while (*s)
86 {
87 if (*s == '\\')
88 {
89 ++backslashes;
90 }
91 else
92 {
93 if (*s == '"')
94 {
95 // Escape the doublequote and all backslashes preceding the doublequote
96 for (int i = 0; i <= backslashes; ++i)
97 {
98 *d = '\\';
99 ++d;
100 }
101 }
102
103 backslashes = 0;
104 }
105
106 *d = *s;
107 ++d;
108 ++s;
109 }
110 }
111 else
112 {
113 wcscpy(d, s);
114 d += wcslen(s);
115 }
116
117 if (addDoubleQuotes)
118 {
119 *d = '"'; // final doublequote
120 ++d;
121 }
122
123 return d;
124}
125
132wchar_t*
133MakeCommandLine(int argc, wchar_t **argv)
134{
135 int i;
136 int len = 0;
137
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;
141
142 // Protect against callers that pass 0 arguments
143 if (len == 0)
144 len = 1;
145
146 wchar_t *s = static_cast<wchar_t*>(malloc(len * sizeof(wchar_t)));
147 if (!s)
148 return nullptr;
149
150 wchar_t *c = s;
151 for (i = 0; i < argc && argv[i]; ++i)
152 {
153 c = ArgToString(c, argv[i]);
154 if (i + 1 != argc)
155 {
156 *c = ' ';
157 ++c;
158 }
159 }
160
161 *c = '\0';
162
163 return s;
164}
165
166BOOL
167WinLaunchChild(const wchar_t *exePath,
168 int argc,
169 wchar_t **argv,
170 HANDLE userToken,
171 HANDLE *hProcess)
172{
173 wchar_t *cl;
174 bool ok;
175
176 cl = MakeCommandLine(argc, argv);
177 if (!cl)
178 {
179 return FALSE;
180 }
181
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);
188
189 if (userToken == nullptr)
190 {
191 ok = CreateProcessW(exePath,
192 cl,
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);
201 }
202 else
203 {
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))
208 {
209 environmentBlock = nullptr;
210 }
211
212 ok = CreateProcessAsUserW(userToken,
213 exePath,
214 cl,
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);
223
224 if (environmentBlock)
225 {
226 DestroyEnvironmentBlock(environmentBlock);
227 }
228 }
229
230 if (ok)
231 {
232 if (hProcess)
233 {
234 *hProcess = pi.hProcess; // the caller now owns the HANDLE
235 }
236 else
237 {
238 CloseHandle(pi.hProcess);
239 }
240 CloseHandle(pi.hThread);
241 }
242 else
243 {
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),
252 0,
253 nullptr);
254 wprintf(L"Error restarting: %s\n", lpMsgBuf ? lpMsgBuf : L"(null)");
255 if (lpMsgBuf)
256 HeapFree(GetProcessHeap(), 0, lpMsgBuf);
257 }
258
259 free(cl);
260
261 return ok;
262}
double d
#define TRUE
#define FALSE
int i
const wchar_t *typedef BOOL
static int ArgStrLen(const wchar_t *s)
Get the length that the string will take and takes into account the additional length if the string n...
static wchar_t * ArgToString(wchar_t *d, const wchar_t *s)
Copy string "s" to string "d", quoting the argument as appropriate and escaping doublequotes along wi...
BOOL WinLaunchChild(const wchar_t *exePath, int argc, wchar_t **argv, HANDLE userToken, HANDLE *hProcess)
Launch a child process with the specified arguments.
wchar_t * MakeCommandLine(int argc, wchar_t **argv)
Creates a command line from a list of arguments.