Bug 1888590 - Mark some subtests on trusted-types-event-handlers.html as failing...
[gecko.git] / toolkit / xre / nsWindowsRestart.cpp
blob928702e28121bf1d0b11ef9083e9d86c70e95691
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 // This file is not build directly. Instead, it is included in multiple
6 // shared objects.
8 #ifdef nsWindowsRestart_cpp
9 # error \
10 "nsWindowsRestart.cpp is not a header file, and must only be included once."
11 #else
12 # define nsWindowsRestart_cpp
13 #endif
15 #include "mozilla/CmdLineAndEnvUtils.h"
16 #include "nsUTF8Utils.h"
18 #include <shellapi.h>
20 // Needed for CreateEnvironmentBlock
21 #include <userenv.h>
22 #ifndef __MINGW32__
23 # pragma comment(lib, "userenv.lib")
24 #endif
26 /**
27 * Convert UTF8 to UTF16 without using the normal XPCOM goop, which we
28 * can't link to updater.exe.
30 static char16_t* AllocConvertUTF8toUTF16(const char* arg) {
31 // UTF16 can't be longer in units than UTF8
32 size_t len = strlen(arg);
33 char16_t* s = new char16_t[(len + 1) * sizeof(char16_t)];
34 if (!s) return nullptr;
36 size_t dstLen = ::MultiByteToWideChar(CP_UTF8, 0, arg, len,
37 reinterpret_cast<wchar_t*>(s), len);
38 s[dstLen] = 0;
40 return s;
43 static void FreeAllocStrings(int argc, wchar_t** argv) {
44 while (argc) {
45 --argc;
46 delete[] argv[argc];
49 delete[] argv;
52 static wchar_t** AllocConvertUTF8toUTF16Strings(int argc, char** argv) {
53 wchar_t** argvConverted = new wchar_t*[argc];
54 if (!argvConverted) return nullptr;
56 for (int i = 0; i < argc; ++i) {
57 argvConverted[i] =
58 reinterpret_cast<wchar_t*>(AllocConvertUTF8toUTF16(argv[i]));
59 if (!argvConverted[i]) {
60 FreeAllocStrings(i, argvConverted);
61 return nullptr;
64 return argvConverted;
67 /**
68 * Return true if we are in a job with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE and
69 * we can break away from it.
70 * CreateProcess fails if we try to break away from a job but it's not allowed.
71 * So if we cannot determine the result due to a failure, we assume we don't
72 * need to break away and this returns false.
74 static bool NeedToBreakAwayFromJob() {
75 // If we can't determine if we are in a job, we assume we're not in a job.
76 BOOL inJob = FALSE;
77 if (!::IsProcessInJob(::GetCurrentProcess(), nullptr, &inJob)) {
78 return false;
81 // If there is no job, there is nothing to worry about.
82 if (!inJob) {
83 return false;
86 // If we can't get the job object flags, we assume no need to break away from
87 // it.
88 JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = {};
89 if (!::QueryInformationJobObject(nullptr, JobObjectExtendedLimitInformation,
90 &job_info, sizeof(job_info), nullptr)) {
91 return false;
94 // If JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE is not set, no need to worry about
95 // the job.
96 if (!(job_info.BasicLimitInformation.LimitFlags &
97 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE)) {
98 return false;
101 // If we can't break away from the current job, there is nothing we can do.
102 if (!(job_info.BasicLimitInformation.LimitFlags &
103 JOB_OBJECT_LIMIT_BREAKAWAY_OK)) {
104 return false;
107 // We can and need to break away from the job.
108 return true;
112 * Launch a child process with the specified arguments.
113 * @note argv[0] is ignored
114 * @note The form of this function that takes char **argv expects UTF-8
117 BOOL WinLaunchChild(const wchar_t* exePath, int argc, wchar_t** argv,
118 HANDLE userToken, HANDLE* hProcess);
120 BOOL WinLaunchChild(const wchar_t* exePath, int argc, char** argv,
121 HANDLE userToken, HANDLE* hProcess) {
122 wchar_t** argvConverted = AllocConvertUTF8toUTF16Strings(argc, argv);
123 if (!argvConverted) return FALSE;
125 BOOL ok = WinLaunchChild(exePath, argc, argvConverted, userToken, hProcess);
126 FreeAllocStrings(argc, argvConverted);
127 return ok;
130 BOOL WinLaunchChild(const wchar_t* exePath, int argc, wchar_t** argv,
131 HANDLE userToken, HANDLE* hProcess) {
132 BOOL ok;
134 mozilla::UniquePtr<wchar_t[]> cl(mozilla::MakeCommandLine(argc, argv));
135 if (!cl) {
136 return FALSE;
139 DWORD creationFlags =
140 NeedToBreakAwayFromJob() ? CREATE_BREAKAWAY_FROM_JOB : 0;
142 STARTUPINFOW si = {0};
143 si.cb = sizeof(STARTUPINFOW);
144 si.lpDesktop = const_cast<LPWSTR>(L"winsta0\\Default");
145 PROCESS_INFORMATION pi = {0};
147 if (userToken == nullptr) {
148 ok = CreateProcessW(exePath, cl.get(),
149 nullptr, // no special security attributes
150 nullptr, // no special thread attributes
151 FALSE, // don't inherit filehandles
152 creationFlags,
153 nullptr, // inherit my environment
154 nullptr, // use my current directory
155 &si, &pi);
156 } else {
157 // Create an environment block for the process we're about to start using
158 // the user's token.
159 LPVOID environmentBlock = nullptr;
160 if (!CreateEnvironmentBlock(&environmentBlock, userToken, TRUE)) {
161 environmentBlock = nullptr;
164 ok = CreateProcessAsUserW(userToken, exePath, cl.get(),
165 nullptr, // no special security attributes
166 nullptr, // no special thread attributes
167 FALSE, // don't inherit filehandles
168 creationFlags, environmentBlock,
169 nullptr, // use my current directory
170 &si, &pi);
172 if (environmentBlock) {
173 DestroyEnvironmentBlock(environmentBlock);
177 if (ok) {
178 if (hProcess) {
179 *hProcess = pi.hProcess; // the caller now owns the HANDLE
180 } else {
181 CloseHandle(pi.hProcess);
183 CloseHandle(pi.hThread);
184 } else {
185 LPVOID lpMsgBuf = nullptr;
186 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
187 FORMAT_MESSAGE_IGNORE_INSERTS,
188 nullptr, GetLastError(),
189 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf,
190 0, nullptr);
191 wprintf(L"Error restarting: %s\n",
192 lpMsgBuf ? static_cast<const wchar_t*>(lpMsgBuf) : L"(null)");
193 if (lpMsgBuf) LocalFree(lpMsgBuf);
196 return ok;