зеркало из https://github.com/mozilla/gecko-dev.git
Bug 453185: nsIProcess run fails with NS_ERROR_FILE_EXECUTION_FAILED when running an exe with a manifest that specifies requestedExecutionLevel level=requireAdministrator on Vista. r=bsmedberg
This commit is contained in:
Родитель
ea39c38934
Коммит
72f7b47ede
|
@ -134,8 +134,43 @@ function test_arguments()
|
|||
do_check_neq(process.exitValue, 255);
|
||||
}
|
||||
|
||||
var gProcess;
|
||||
|
||||
// test if we can get an exit value from an application that is
|
||||
// run non-blocking
|
||||
function test_nonblocking()
|
||||
{
|
||||
var testapp = filePrefix + "TestQuickReturn" + fileSuffix;
|
||||
|
||||
var file = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
file.initWithPath(testapp);
|
||||
|
||||
gProcess = Components.classes["@mozilla.org/process/util;1"]
|
||||
.createInstance(Components.interfaces.nsIProcess);
|
||||
gProcess.init(file);
|
||||
|
||||
gProcess.run(false, [], 0);
|
||||
|
||||
do_test_pending();
|
||||
do_timeout(100, "check_nonblocking()");
|
||||
}
|
||||
|
||||
function check_nonblocking()
|
||||
{
|
||||
if (gProcess.isRunning) {
|
||||
do_timeout(100, "check_nonblocking()");
|
||||
return;
|
||||
}
|
||||
|
||||
do_check_eq(gProcess.exitValue, 42);
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
test_kill();
|
||||
test_quick();
|
||||
test_arguments();
|
||||
if (isWindows)
|
||||
test_nonblocking();
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "prproces.h"
|
||||
#if defined(PROCESSMODEL_WINAPI)
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#endif
|
||||
|
||||
#define NS_PROCESS_CID \
|
||||
|
@ -73,7 +74,8 @@ private:
|
|||
nsCString mTargetPath;
|
||||
|
||||
#if defined(PROCESSMODEL_WINAPI)
|
||||
PROCESS_INFORMATION procInfo;
|
||||
typedef DWORD (WINAPI*GetProcessIdPtr)(HANDLE process);
|
||||
HANDLE mProcess;
|
||||
#else
|
||||
PRProcess *mProcess;
|
||||
#endif
|
||||
|
|
|
@ -55,12 +55,11 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#if defined(PROCESSMODEL_WINAPI)
|
||||
#include "prmem.h"
|
||||
#include "nsString.h"
|
||||
#include "nsLiteralString.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
|
@ -73,23 +72,17 @@ NS_IMPL_ISUPPORTS1(nsProcess, nsIProcess)
|
|||
|
||||
//Constructor
|
||||
nsProcess::nsProcess()
|
||||
: mExitValue(-1)
|
||||
: mExitValue(-1),
|
||||
mProcess(nsnull)
|
||||
{
|
||||
#if defined(PROCESSMODEL_WINAPI)
|
||||
procInfo.dwProcessId = nsnull;
|
||||
#else
|
||||
mProcess = nsnull;
|
||||
#endif
|
||||
}
|
||||
|
||||
//Destructor
|
||||
nsProcess::~nsProcess()
|
||||
{
|
||||
#if defined(PROCESSMODEL_WINAPI)
|
||||
if (procInfo.dwProcessId) {
|
||||
CloseHandle( procInfo.hProcess );
|
||||
CloseHandle( procInfo.hThread );
|
||||
}
|
||||
if (mProcess)
|
||||
CloseHandle(mProcess);
|
||||
#else
|
||||
if (mProcess)
|
||||
PR_DetachProcess(mProcess);
|
||||
|
@ -101,7 +94,7 @@ nsProcess::Init(nsIFile* executable)
|
|||
{
|
||||
//Prevent re-initializing if already attached to process
|
||||
#if defined(PROCESSMODEL_WINAPI)
|
||||
if (procInfo.dwProcessId)
|
||||
if (mProcess)
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
#else
|
||||
if (mProcess)
|
||||
|
@ -245,6 +238,7 @@ nsProcess::Run(PRBool blocking, const char **args, PRUint32 count)
|
|||
{
|
||||
NS_ENSURE_TRUE(mExecutable, NS_ERROR_NOT_INITIALIZED);
|
||||
PRStatus status = PR_SUCCESS;
|
||||
mExitValue = -1;
|
||||
|
||||
// make sure that when we allocate we have 1 greater than the
|
||||
// count since we need to null terminate the list for the argv to
|
||||
|
@ -266,41 +260,44 @@ nsProcess::Run(PRBool blocking, const char **args, PRUint32 count)
|
|||
my_argv[count+1] = NULL;
|
||||
|
||||
#if defined(PROCESSMODEL_WINAPI)
|
||||
STARTUPINFOW startupInfo;
|
||||
BOOL retVal;
|
||||
PRUnichar *cmdLine;
|
||||
|
||||
if (assembleCmdLine(my_argv, &cmdLine) == -1) {
|
||||
if (count > 0 && assembleCmdLine(my_argv + 1, &cmdLine) == -1) {
|
||||
nsMemory::Free(my_argv);
|
||||
return NS_ERROR_FILE_EXECUTION_FAILED;
|
||||
}
|
||||
|
||||
ZeroMemory(&startupInfo, sizeof(startupInfo));
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
|
||||
/* The CREATE_NO_WINDOW flag is important to prevent console
|
||||
* windows from appearing. This makes behavior the same on all
|
||||
* platforms. This won't work on win9x, however. The flag will
|
||||
* not have any effect on non-console applications.
|
||||
/* The SEE_MASK_NO_CONSOLE flag is important to prevent console windows
|
||||
* from appearing. This makes behavior the same on all platforms. The flag
|
||||
* will not have any effect on non-console applications.
|
||||
*/
|
||||
PRInt32 numChars = MultiByteToWideChar(CP_ACP, 0, my_argv[0], -1, NULL, 0);
|
||||
PRUnichar* wideFile = (PRUnichar *) PR_MALLOC(numChars * sizeof(PRUnichar));
|
||||
MultiByteToWideChar(CP_ACP, 0, my_argv[0], -1, wideFile, numChars);
|
||||
|
||||
SHELLEXECUTEINFOW sinfo;
|
||||
memset(&sinfo, 0, sizeof(SHELLEXECUTEINFOW));
|
||||
sinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
|
||||
sinfo.hwnd = NULL;
|
||||
sinfo.lpFile = wideFile;
|
||||
sinfo.nShow = SW_SHOWNORMAL;
|
||||
sinfo.fMask = SEE_MASK_FLAG_DDEWAIT |
|
||||
SEE_MASK_NO_CONSOLE |
|
||||
SEE_MASK_NOCLOSEPROCESS;
|
||||
|
||||
if (count > 0)
|
||||
sinfo.lpParameters = cmdLine;
|
||||
|
||||
retVal = ShellExecuteExW(&sinfo);
|
||||
mProcess = sinfo.hProcess;
|
||||
|
||||
PR_Free(wideFile);
|
||||
if (count > 0)
|
||||
PR_Free( cmdLine );
|
||||
|
||||
retVal = CreateProcessW(NULL,
|
||||
// const_cast<char*>(mTargetPath.get()),
|
||||
cmdLine,
|
||||
NULL, /* security attributes for the new
|
||||
* process */
|
||||
NULL, /* security attributes for the primary
|
||||
* thread in the new process */
|
||||
FALSE, /* inherit handles */
|
||||
CREATE_NO_WINDOW, /* creation flags */
|
||||
NULL, /* env */
|
||||
NULL, /* current drive and directory */
|
||||
&startupInfo,
|
||||
&procInfo
|
||||
);
|
||||
PR_Free( cmdLine );
|
||||
if (blocking) {
|
||||
|
||||
|
||||
// if success, wait for process termination. the early returns and such
|
||||
// are a bit ugly but preserving the logic of the nspr code I copied to
|
||||
// minimize our risk abit.
|
||||
|
@ -309,20 +306,19 @@ nsProcess::Run(PRBool blocking, const char **args, PRUint32 count)
|
|||
DWORD dwRetVal;
|
||||
unsigned long exitCode;
|
||||
|
||||
dwRetVal = WaitForSingleObject(procInfo.hProcess, INFINITE);
|
||||
dwRetVal = WaitForSingleObject(mProcess, INFINITE);
|
||||
if (dwRetVal == WAIT_FAILED) {
|
||||
nsMemory::Free(my_argv);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (GetExitCodeProcess(procInfo.hProcess, &exitCode) == FALSE) {
|
||||
if (GetExitCodeProcess(mProcess, &exitCode) == FALSE) {
|
||||
mExitValue = exitCode;
|
||||
nsMemory::Free(my_argv);
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mExitValue = exitCode;
|
||||
CloseHandle(procInfo.hProcess);
|
||||
CloseHandle(procInfo.hThread);
|
||||
procInfo.dwProcessId = nsnull;
|
||||
CloseHandle(mProcess);
|
||||
mProcess = NULL;
|
||||
}
|
||||
else
|
||||
status = PR_FAILURE;
|
||||
|
@ -361,15 +357,23 @@ nsProcess::Run(PRBool blocking, const char **args, PRUint32 count)
|
|||
NS_IMETHODIMP nsProcess::GetIsRunning(PRBool *aIsRunning)
|
||||
{
|
||||
#if defined(PROCESSMODEL_WINAPI)
|
||||
if (!procInfo.dwProcessId) {
|
||||
if (!mProcess) {
|
||||
*aIsRunning = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
DWORD ec = 0;
|
||||
BOOL br = GetExitCodeProcess(procInfo.hProcess, &ec);
|
||||
BOOL br = GetExitCodeProcess(mProcess, &ec);
|
||||
if (!br)
|
||||
return NS_ERROR_FAILURE;
|
||||
*aIsRunning = (ec == STILL_ACTIVE ? PR_TRUE : PR_FALSE);
|
||||
if (ec == STILL_ACTIVE) {
|
||||
*aIsRunning = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
*aIsRunning = PR_FALSE;
|
||||
mExitValue = ec;
|
||||
CloseHandle(mProcess);
|
||||
mProcess = NULL;
|
||||
}
|
||||
return NS_OK;
|
||||
#elif defined WINCE
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
@ -402,9 +406,18 @@ NS_IMETHODIMP
|
|||
nsProcess::GetPid(PRUint32 *aPid)
|
||||
{
|
||||
#if defined(PROCESSMODEL_WINAPI)
|
||||
if (!procInfo.dwProcessId)
|
||||
if (!mProcess)
|
||||
return NS_ERROR_FAILURE;
|
||||
*aPid = procInfo.dwProcessId;
|
||||
HMODULE kernelDLL = ::LoadLibraryW(L"kernel32.dll");
|
||||
if (!kernelDLL)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
GetProcessIdPtr getProcessId = (GetProcessIdPtr)GetProcAddress(kernelDLL, "GetProcessId");
|
||||
if (!getProcessId) {
|
||||
FreeLibrary(kernelDLL);
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
*aPid = getProcessId(mProcess);
|
||||
FreeLibrary(kernelDLL);
|
||||
return NS_OK;
|
||||
#elif defined WINCE
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
@ -437,15 +450,14 @@ NS_IMETHODIMP
|
|||
nsProcess::Kill()
|
||||
{
|
||||
#if defined(PROCESSMODEL_WINAPI)
|
||||
if (!procInfo.dwProcessId)
|
||||
if (!mProcess)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if ( TerminateProcess(procInfo.hProcess, NULL) == 0 )
|
||||
if ( TerminateProcess(mProcess, NULL) == 0 )
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
CloseHandle( procInfo.hProcess );
|
||||
CloseHandle( procInfo.hThread );
|
||||
procInfo.dwProcessId = nsnull;
|
||||
CloseHandle( mProcess );
|
||||
mProcess = NULL;
|
||||
#else
|
||||
if (!mProcess)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
@ -461,6 +473,20 @@ nsProcess::Kill()
|
|||
NS_IMETHODIMP
|
||||
nsProcess::GetExitValue(PRInt32 *aExitValue)
|
||||
{
|
||||
#if defined(PROCESSMODEL_WINAPI)
|
||||
if (mProcess) {
|
||||
DWORD ec = 0;
|
||||
BOOL br = GetExitCodeProcess(mProcess, &ec);
|
||||
if (!br)
|
||||
return NS_ERROR_FAILURE;
|
||||
// If we have an exit code then the process has ended, clean it up.
|
||||
if (ec != STILL_ACTIVE) {
|
||||
mExitValue = ec;
|
||||
CloseHandle(mProcess);
|
||||
mProcess = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*aExitValue = mExitValue;
|
||||
|
||||
return NS_OK;
|
||||
|
|
Загрузка…
Ссылка в новой задаче