Skip to content

Commit 0469f75

Browse files
author
Cervantes Yu
committed
Bug 1400294 - Add 'noShell' attribute to nsIProcess to use CreateProcess() for launching a process that doesn't require shell service on Windows. r=froydnj,r=aklotz,r=dmajor
This adds an attribute 'noShell' to nsIProcess that is used to launch a process using CreateProcess() if we are sure we are launching an executable and don't require the extra work of the Windows shell service. MozReview-Commit-ID: 7p0iHCZK1uX
1 parent 9218253 commit 0469f75

File tree

5 files changed

+86
-28
lines changed

5 files changed

+86
-28
lines changed

toolkit/components/crashes/CrashService.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ function runMinidumpAnalyzer(minidumpPath) {
5050
.createInstance(Ci.nsIProcess);
5151
process.init(exe);
5252
process.startHidden = true;
53+
process.noShell = true;
54+
5355
process.runAsync(args, args.length, (subject, topic, data) => {
5456
switch (topic) {
5557
case "process-finished":

toolkit/components/telemetry/TelemetrySend.jsm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,6 +1342,7 @@ var TelemetrySendImpl = {
13421342
.createInstance(Ci.nsIProcess);
13431343
process.init(exe);
13441344
process.startHidden = true;
1345+
process.noShell = true;
13451346
process.run(/* blocking */ false, [url, pingPath], 2);
13461347
},
13471348
};

xpcom/threads/nsIProcess.idl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ interface nsIProcess : nsISupports
8181
*/
8282
attribute boolean startHidden;
8383

84+
/**
85+
* When set to true the process will be launched directly without using the
86+
* shell. This currently affects only the Windows platform.
87+
*/
88+
attribute boolean noShell;
89+
8490
/**
8591
* The process identifier of the currently running process. This will only
8692
* be available after the process has started and may not be available on

xpcom/threads/nsProcess.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class nsProcess final
6363
bool mShutdown;
6464
bool mBlocking;
6565
bool mStartHidden;
66+
bool mNoShell;
6667

6768
nsCOMPtr<nsIFile> mExecutable;
6869
nsString mTargetPath;

xpcom/threads/nsProcessCommon.cpp

Lines changed: 76 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "nsString.h"
3434
#include "nsLiteralString.h"
3535
#include "nsReadableUtils.h"
36+
#include "mozilla/UniquePtrExtensions.h"
3637
#else
3738
#ifdef XP_MACOSX
3839
#include <crt_externs.h>
@@ -72,6 +73,7 @@ nsProcess::nsProcess()
7273
, mShutdown(false)
7374
, mBlocking(false)
7475
, mStartHidden(false)
76+
, mNoShell(false)
7577
, mPid(-1)
7678
, mObserver(nullptr)
7779
, mWeakObserver(nullptr)
@@ -466,46 +468,78 @@ nsProcess::RunProcess(bool aBlocking, char** aMyArgv, nsIObserver* aObserver,
466468

467469
#if defined(PROCESSMODEL_WINAPI)
468470
BOOL retVal;
469-
wchar_t* cmdLine = nullptr;
471+
UniqueFreePtr<wchar_t> cmdLine;
470472

471473
// |aMyArgv| is null-terminated and always starts with the program path. If
472474
// the second slot is non-null then arguments are being passed.
473-
if (aMyArgv[1] && assembleCmdLine(aMyArgv + 1, &cmdLine,
474-
aArgsUTF8 ? CP_UTF8 : CP_ACP) == -1) {
475-
return NS_ERROR_FILE_EXECUTION_FAILED;
475+
if (aMyArgv[1] || mNoShell) {
476+
// Pass the executable path as argv[0] to the launched program when calling
477+
// CreateProcess().
478+
char** argv = mNoShell ? aMyArgv : aMyArgv + 1;
479+
480+
wchar_t* assembledCmdLine = nullptr;
481+
if (assembleCmdLine(argv, &assembledCmdLine,
482+
aArgsUTF8 ? CP_UTF8 : CP_ACP) == -1) {
483+
return NS_ERROR_FILE_EXECUTION_FAILED;
484+
}
485+
cmdLine.reset(assembledCmdLine);
476486
}
477487

478-
/* The SEE_MASK_NO_CONSOLE flag is important to prevent console windows
479-
* from appearing. This makes behavior the same on all platforms. The flag
480-
* will not have any effect on non-console applications.
481-
*/
482-
483488
// The program name in aMyArgv[0] is always UTF-8
484489
NS_ConvertUTF8toUTF16 wideFile(aMyArgv[0]);
485490

486-
SHELLEXECUTEINFOW sinfo;
487-
memset(&sinfo, 0, sizeof(SHELLEXECUTEINFOW));
488-
sinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
489-
sinfo.hwnd = nullptr;
490-
sinfo.lpFile = wideFile.get();
491-
sinfo.nShow = mStartHidden ? SW_HIDE : SW_SHOWNORMAL;
492-
sinfo.fMask = SEE_MASK_FLAG_DDEWAIT |
493-
SEE_MASK_NO_CONSOLE |
494-
SEE_MASK_NOCLOSEPROCESS;
491+
if (mNoShell) {
492+
STARTUPINFO startupInfo;
493+
ZeroMemory(&startupInfo, sizeof(startupInfo));
494+
startupInfo.cb = sizeof(startupInfo);
495+
startupInfo.dwFlags = STARTF_USESHOWWINDOW;
496+
startupInfo.wShowWindow = mStartHidden ? SW_HIDE : SW_SHOWNORMAL;
497+
498+
PROCESS_INFORMATION processInfo;
499+
retVal = CreateProcess(/* lpApplicationName = */ wideFile.get(),
500+
/* lpCommandLine */ cmdLine.get(),
501+
/* lpProcessAttributes = */ NULL,
502+
/* lpThreadAttributes = */ NULL,
503+
/* bInheritHandles = */ FALSE,
504+
/* dwCreationFlags = */ 0,
505+
/* lpEnvironment = */ NULL,
506+
/* lpCurrentDirectory = */ NULL,
507+
/* lpStartupInfo = */ &startupInfo,
508+
/* lpProcessInformation */ &processInfo);
509+
510+
if (!retVal) {
511+
return NS_ERROR_FILE_EXECUTION_FAILED;
512+
}
513+
514+
CloseHandle(processInfo.hThread);
495515

496-
if (cmdLine) {
497-
sinfo.lpParameters = cmdLine;
498-
}
516+
mProcess = processInfo.hProcess;
517+
} else {
518+
SHELLEXECUTEINFOW sinfo;
519+
memset(&sinfo, 0, sizeof(SHELLEXECUTEINFOW));
520+
sinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
521+
sinfo.hwnd = nullptr;
522+
sinfo.lpFile = wideFile.get();
523+
sinfo.nShow = mStartHidden ? SW_HIDE : SW_SHOWNORMAL;
524+
525+
/* The SEE_MASK_NO_CONSOLE flag is important to prevent console windows
526+
* from appearing. This makes behavior the same on all platforms. The flag
527+
* will not have any effect on non-console applications.
528+
*/
529+
sinfo.fMask = SEE_MASK_FLAG_DDEWAIT |
530+
SEE_MASK_NO_CONSOLE |
531+
SEE_MASK_NOCLOSEPROCESS;
499532

500-
retVal = ShellExecuteExW(&sinfo);
501-
if (!retVal) {
502-
return NS_ERROR_FILE_EXECUTION_FAILED;
503-
}
533+
if (cmdLine) {
534+
sinfo.lpParameters = cmdLine.get();
535+
}
504536

505-
mProcess = sinfo.hProcess;
537+
retVal = ShellExecuteExW(&sinfo);
538+
if (!retVal) {
539+
return NS_ERROR_FILE_EXECUTION_FAILED;
540+
}
506541

507-
if (cmdLine) {
508-
free(cmdLine);
542+
mProcess = sinfo.hProcess;
509543
}
510544

511545
mPid = GetProcessId(mProcess);
@@ -603,6 +637,20 @@ nsProcess::SetStartHidden(bool aStartHidden)
603637
return NS_OK;
604638
}
605639

640+
NS_IMETHODIMP
641+
nsProcess::GetNoShell(bool* aNoShell)
642+
{
643+
*aNoShell = mNoShell;
644+
return NS_OK;
645+
}
646+
647+
NS_IMETHODIMP
648+
nsProcess::SetNoShell(bool aNoShell)
649+
{
650+
mNoShell = aNoShell;
651+
return NS_OK;
652+
}
653+
606654
NS_IMETHODIMP
607655
nsProcess::GetPid(uint32_t* aPid)
608656
{

0 commit comments

Comments
 (0)