process-win32.cpp revision c97989161fbe75bc14cea477a5443bbf474dd3ad
45e9809aff7304721fddb95654901b32195c9c7avboxsync/* $Id$ */
45e9809aff7304721fddb95654901b32195c9c7avboxsync/** @file
45e9809aff7304721fddb95654901b32195c9c7avboxsync * innotek Portable Runtime - Process, Win32.
45e9809aff7304721fddb95654901b32195c9c7avboxsync */
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync/*
45e9809aff7304721fddb95654901b32195c9c7avboxsync * Copyright (C) 2006-2007 innotek GmbH
45e9809aff7304721fddb95654901b32195c9c7avboxsync *
45e9809aff7304721fddb95654901b32195c9c7avboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
45e9809aff7304721fddb95654901b32195c9c7avboxsync * available from http://www.virtualbox.org. This file is free software;
45e9809aff7304721fddb95654901b32195c9c7avboxsync * you can redistribute it and/or modify it under the terms of the GNU
45e9809aff7304721fddb95654901b32195c9c7avboxsync * General Public License as published by the Free Software Foundation,
45e9809aff7304721fddb95654901b32195c9c7avboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
45e9809aff7304721fddb95654901b32195c9c7avboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
45e9809aff7304721fddb95654901b32195c9c7avboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
45e9809aff7304721fddb95654901b32195c9c7avboxsync *
45e9809aff7304721fddb95654901b32195c9c7avboxsync * If you received this file as part of a commercial VirtualBox
45e9809aff7304721fddb95654901b32195c9c7avboxsync * distribution, then only the terms of your commercial VirtualBox
45e9809aff7304721fddb95654901b32195c9c7avboxsync * license agreement apply instead of the previous paragraph.
45e9809aff7304721fddb95654901b32195c9c7avboxsync */
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync/*******************************************************************************
45e9809aff7304721fddb95654901b32195c9c7avboxsync* Header Files *
45e9809aff7304721fddb95654901b32195c9c7avboxsync*******************************************************************************/
45e9809aff7304721fddb95654901b32195c9c7avboxsync#define LOG_GROUP RTLOGGROUP_PROCESS
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync#include <Windows.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync#include <process.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync#include <errno.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync#include <iprt/process.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync#include <iprt/assert.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync#include <iprt/err.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync/*
45e9809aff7304721fddb95654901b32195c9c7avboxsync * This is from Winternl.h. It has been copied here
45e9809aff7304721fddb95654901b32195c9c7avboxsync * because the header does not define a calling convention for
45e9809aff7304721fddb95654901b32195c9c7avboxsync * its prototypes and just assumes that _stdcall is the standard
45e9809aff7304721fddb95654901b32195c9c7avboxsync * calling convention.
45e9809aff7304721fddb95654901b32195c9c7avboxsync */
45e9809aff7304721fddb95654901b32195c9c7avboxsynctypedef struct _PEB {
45e9809aff7304721fddb95654901b32195c9c7avboxsync BYTE Reserved1[2];
45e9809aff7304721fddb95654901b32195c9c7avboxsync BYTE BeingDebugged;
45e9809aff7304721fddb95654901b32195c9c7avboxsync BYTE Reserved2[229];
45e9809aff7304721fddb95654901b32195c9c7avboxsync PVOID Reserved3[59];
45e9809aff7304721fddb95654901b32195c9c7avboxsync ULONG SessionId;
45e9809aff7304721fddb95654901b32195c9c7avboxsync} PEB, *PPEB;
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsynctypedef struct _PROCESS_BASIC_INFORMATION {
45e9809aff7304721fddb95654901b32195c9c7avboxsync PVOID Reserved1;
45e9809aff7304721fddb95654901b32195c9c7avboxsync PPEB PebBaseAddress;
45e9809aff7304721fddb95654901b32195c9c7avboxsync PVOID Reserved2[2];
45e9809aff7304721fddb95654901b32195c9c7avboxsync ULONG_PTR UniqueProcessId;
45e9809aff7304721fddb95654901b32195c9c7avboxsync PVOID Reserved3;
45e9809aff7304721fddb95654901b32195c9c7avboxsync} PROCESS_BASIC_INFORMATION;
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsynctypedef enum _PROCESSINFOCLASS {
45e9809aff7304721fddb95654901b32195c9c7avboxsync ProcessBasicInformation = 0,
45e9809aff7304721fddb95654901b32195c9c7avboxsync ProcessWow64Information = 26
45e9809aff7304721fddb95654901b32195c9c7avboxsync} PROCESSINFOCLASS;
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsyncextern "C" LONG WINAPI
45e9809aff7304721fddb95654901b32195c9c7avboxsyncNtQueryInformationProcess (
45e9809aff7304721fddb95654901b32195c9c7avboxsync IN HANDLE ProcessHandle,
45e9809aff7304721fddb95654901b32195c9c7avboxsync IN PROCESSINFOCLASS ProcessInformationClass,
45e9809aff7304721fddb95654901b32195c9c7avboxsync OUT PVOID ProcessInformation,
45e9809aff7304721fddb95654901b32195c9c7avboxsync IN ULONG ProcessInformationLength,
45e9809aff7304721fddb95654901b32195c9c7avboxsync OUT PULONG ReturnLength OPTIONAL
45e9809aff7304721fddb95654901b32195c9c7avboxsync );
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync/** @todo r=michael This function currently does not work correctly if the arguments
45e9809aff7304721fddb95654901b32195c9c7avboxsync contain spaces. */
45e9809aff7304721fddb95654901b32195c9c7avboxsyncRTR3DECL(int) RTProcCreate(const char *pszExec, const char * const *papszArgs, const char * const *papszEnv, unsigned fFlags, PRTPROCESS pProcess)
45e9809aff7304721fddb95654901b32195c9c7avboxsync{
45e9809aff7304721fddb95654901b32195c9c7avboxsync /*
45e9809aff7304721fddb95654901b32195c9c7avboxsync * Validate input.
45e9809aff7304721fddb95654901b32195c9c7avboxsync */
45e9809aff7304721fddb95654901b32195c9c7avboxsync if (!pszExec || !*pszExec)
45e9809aff7304721fddb95654901b32195c9c7avboxsync {
45e9809aff7304721fddb95654901b32195c9c7avboxsync AssertMsgFailed(("no exec\n"));
45e9809aff7304721fddb95654901b32195c9c7avboxsync return VERR_INVALID_PARAMETER;
45e9809aff7304721fddb95654901b32195c9c7avboxsync }
45e9809aff7304721fddb95654901b32195c9c7avboxsync if (fFlags)
45e9809aff7304721fddb95654901b32195c9c7avboxsync {
45e9809aff7304721fddb95654901b32195c9c7avboxsync AssertMsgFailed(("invalid flags!\n"));
45e9809aff7304721fddb95654901b32195c9c7avboxsync return VERR_INVALID_PARAMETER;
45e9809aff7304721fddb95654901b32195c9c7avboxsync }
45e9809aff7304721fddb95654901b32195c9c7avboxsync /* later: path searching. */
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync /*
45e9809aff7304721fddb95654901b32195c9c7avboxsync * Spawn the child.
45e9809aff7304721fddb95654901b32195c9c7avboxsync */
45e9809aff7304721fddb95654901b32195c9c7avboxsync /** @todo utf-8 considerations! */
45e9809aff7304721fddb95654901b32195c9c7avboxsync HANDLE hProcess = (HANDLE)_spawnve(_P_NOWAITO, pszExec, papszArgs, papszEnv);
45e9809aff7304721fddb95654901b32195c9c7avboxsync if (hProcess != 0 && hProcess != INVALID_HANDLE_VALUE)
45e9809aff7304721fddb95654901b32195c9c7avboxsync {
45e9809aff7304721fddb95654901b32195c9c7avboxsync if (pProcess)
45e9809aff7304721fddb95654901b32195c9c7avboxsync {
45e9809aff7304721fddb95654901b32195c9c7avboxsync /*
45e9809aff7304721fddb95654901b32195c9c7avboxsync * GetProcessId requires XP SP1 or later
45e9809aff7304721fddb95654901b32195c9c7avboxsync */
45e9809aff7304721fddb95654901b32195c9c7avboxsync#ifdef __WIN64__
45e9809aff7304721fddb95654901b32195c9c7avboxsync *pProcess = GetProcessId(hProcess);
45e9809aff7304721fddb95654901b32195c9c7avboxsync#else /* !__WIN64__ */
45e9809aff7304721fddb95654901b32195c9c7avboxsync static bool fInitialized = false;
45e9809aff7304721fddb95654901b32195c9c7avboxsync static DWORD (WINAPI *pfnGetProcessId)(HANDLE Thread) = NULL;
45e9809aff7304721fddb95654901b32195c9c7avboxsync if (!fInitialized)
45e9809aff7304721fddb95654901b32195c9c7avboxsync {
45e9809aff7304721fddb95654901b32195c9c7avboxsync HMODULE hmodKernel32 = GetModuleHandle("KERNEL32.DLL");
45e9809aff7304721fddb95654901b32195c9c7avboxsync if (hmodKernel32)
45e9809aff7304721fddb95654901b32195c9c7avboxsync pfnGetProcessId = (DWORD (WINAPI*)(HANDLE))GetProcAddress(hmodKernel32, "GetProcessId");
45e9809aff7304721fddb95654901b32195c9c7avboxsync fInitialized = true;
45e9809aff7304721fddb95654901b32195c9c7avboxsync }
45e9809aff7304721fddb95654901b32195c9c7avboxsync if (pfnGetProcessId)
45e9809aff7304721fddb95654901b32195c9c7avboxsync {
45e9809aff7304721fddb95654901b32195c9c7avboxsync *pProcess = pfnGetProcessId(hProcess);
45e9809aff7304721fddb95654901b32195c9c7avboxsync if (!*pProcess)
45e9809aff7304721fddb95654901b32195c9c7avboxsync {
45e9809aff7304721fddb95654901b32195c9c7avboxsync int rc = RTErrConvertFromWin32(GetLastError());
45e9809aff7304721fddb95654901b32195c9c7avboxsync AssertMsgFailed(("failed to get pid from hProcess=%#x rc=%Vrc\n", hProcess, rc));
45e9809aff7304721fddb95654901b32195c9c7avboxsync return rc;
45e9809aff7304721fddb95654901b32195c9c7avboxsync }
45e9809aff7304721fddb95654901b32195c9c7avboxsync }
45e9809aff7304721fddb95654901b32195c9c7avboxsync else
45e9809aff7304721fddb95654901b32195c9c7avboxsync {
45e9809aff7304721fddb95654901b32195c9c7avboxsync /*
45e9809aff7304721fddb95654901b32195c9c7avboxsync * Fall back to the NT api for older versions.
45e9809aff7304721fddb95654901b32195c9c7avboxsync */
45e9809aff7304721fddb95654901b32195c9c7avboxsync PROCESS_BASIC_INFORMATION ProcInfo = {0};
45e9809aff7304721fddb95654901b32195c9c7avboxsync ULONG Status = NtQueryInformationProcess(hProcess, ProcessBasicInformation,
45e9809aff7304721fddb95654901b32195c9c7avboxsync &ProcInfo, sizeof(ProcInfo), NULL);
45e9809aff7304721fddb95654901b32195c9c7avboxsync if (Status != 0)
45e9809aff7304721fddb95654901b32195c9c7avboxsync {
45e9809aff7304721fddb95654901b32195c9c7avboxsync int rc = ERROR_INTERNAL_ERROR; /* (we don't have a valid conversion here, but this shouldn't happen anyway.) */
45e9809aff7304721fddb95654901b32195c9c7avboxsync AssertMsgFailed(("failed to get pid from hProcess=%#x rc=%Vrc Status=%#x\n", hProcess, rc, Status));
45e9809aff7304721fddb95654901b32195c9c7avboxsync return rc;
45e9809aff7304721fddb95654901b32195c9c7avboxsync }
45e9809aff7304721fddb95654901b32195c9c7avboxsync *pProcess = ProcInfo.UniqueProcessId;
45e9809aff7304721fddb95654901b32195c9c7avboxsync }
45e9809aff7304721fddb95654901b32195c9c7avboxsync#endif /* !__WIN64__ */
45e9809aff7304721fddb95654901b32195c9c7avboxsync }
45e9809aff7304721fddb95654901b32195c9c7avboxsync return VINF_SUCCESS;
45e9809aff7304721fddb95654901b32195c9c7avboxsync }
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync int rc = RTErrConvertFromErrno(errno);
45e9809aff7304721fddb95654901b32195c9c7avboxsync AssertMsgFailed(("spawn/exec failed rc=%Vrc\n", rc)); /* this migth be annoying... */
45e9809aff7304721fddb95654901b32195c9c7avboxsync return rc;
45e9809aff7304721fddb95654901b32195c9c7avboxsync}
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsyncRTR3DECL(int) RTProcWait(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus)
{
AssertReturn(!(fFlags & ~(RTPROCWAIT_FLAGS_BLOCK | RTPROCWAIT_FLAGS_NOBLOCK)), VERR_INVALID_PARAMETER);
/*
* Open the process.
*/
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, Process);
if (hProcess != NULL)
{
/*
* Wait for it to terminate.
*/
DWORD Millies = fFlags == RTPROCWAIT_FLAGS_BLOCK ? INFINITE : 0;
DWORD WaitRc = WaitForSingleObjectEx(hProcess, Millies, TRUE);
while (WaitRc == WAIT_IO_COMPLETION)
WaitRc = WaitForSingleObjectEx(hProcess, Millies, TRUE);
switch (WaitRc)
{
/*
* It has terminated.
*/
case WAIT_OBJECT_0:
{
DWORD dwExitCode;
if (GetExitCodeProcess(hProcess, &dwExitCode))
{
if (pProcStatus)
{
pProcStatus->enmReason = RTPROCEXITREASON_NORMAL;
pProcStatus->iStatus = (int)dwExitCode;
}
return VINF_SUCCESS;
}
break;
}
/*
* It hasn't terminated just yet.
*/
case WAIT_TIMEOUT:
return VERR_PROCESS_RUNNING;
/*
* Something went wrong...
*/
case WAIT_FAILED:
break;
case WAIT_ABANDONED:
AssertFailed();
return VERR_GENERAL_FAILURE;
default:
AssertMsgFailed(("WaitRc=%RU32\n", WaitRc));
return VERR_GENERAL_FAILURE;
}
}
DWORD dwErr = GetLastError();
return RTErrConvertFromWin32(dwErr);
}
RTR3DECL(int) RTProcTerminate(RTPROCESS Process)
{
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, Process);
if (hProcess != NULL)
{
BOOL fRc = TerminateProcess(hProcess, 127);
CloseHandle(hProcess);
if (fRc)
return VINF_SUCCESS;
}
DWORD dwErr = GetLastError();
return RTErrConvertFromWin32(dwErr);
}
RTR3DECL(uint64_t) RTProcGetAffinityMask(void)
{
DWORD_PTR dwProcessAffinityMask = 0xffffffff;
DWORD_PTR dwSystemAffinityMask;
BOOL fRc = GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask);
Assert(fRc);
return dwProcessAffinityMask;
}
RTR3DECL(char *) RTProcGetExecutableName(char *pszExecName, size_t cchExecName)
{
HMODULE hExe = GetModuleHandle(NULL);
if (GetModuleFileName(hExe, pszExecName, cchExecName))
return pszExecName;
return NULL;
}