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
8 #ifdef nsWindowsRestart_cpp
10 "nsWindowsRestart.cpp is not a header file, and must only be included once."
12 # define nsWindowsRestart_cpp
15 #include "mozilla/CmdLineAndEnvUtils.h"
16 #include "nsUTF8Utils.h"
20 // Needed for CreateEnvironmentBlock
23 # pragma comment(lib, "userenv.lib")
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
);
43 static void FreeAllocStrings(int argc
, wchar_t** 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
) {
58 reinterpret_cast<wchar_t*>(AllocConvertUTF8toUTF16(argv
[i
]));
59 if (!argvConverted
[i
]) {
60 FreeAllocStrings(i
, argvConverted
);
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.
77 if (!::IsProcessInJob(::GetCurrentProcess(), nullptr, &inJob
)) {
81 // If there is no job, there is nothing to worry about.
86 // If we can't get the job object flags, we assume no need to break away from
88 JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info
= {};
89 if (!::QueryInformationJobObject(nullptr, JobObjectExtendedLimitInformation
,
90 &job_info
, sizeof(job_info
), nullptr)) {
94 // If JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE is not set, no need to worry about
96 if (!(job_info
.BasicLimitInformation
.LimitFlags
&
97 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
)) {
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
)) {
107 // We can and need to break away from the job.
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
);
130 BOOL
WinLaunchChild(const wchar_t* exePath
, int argc
, wchar_t** argv
,
131 HANDLE userToken
, HANDLE
* hProcess
) {
134 mozilla::UniquePtr
<wchar_t[]> cl(mozilla::MakeCommandLine(argc
, argv
));
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
153 nullptr, // inherit my environment
154 nullptr, // use my current directory
157 // Create an environment block for the process we're about to start using
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
172 if (environmentBlock
) {
173 DestroyEnvironmentBlock(environmentBlock
);
179 *hProcess
= pi
.hProcess
; // the caller now owns the HANDLE
181 CloseHandle(pi
.hProcess
);
183 CloseHandle(pi
.hThread
);
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
,
191 wprintf(L
"Error restarting: %s\n",
192 lpMsgBuf
? static_cast<const wchar_t*>(lpMsgBuf
) : L
"(null)");
193 if (lpMsgBuf
) LocalFree(lpMsgBuf
);