Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / subsystems / win / basesrv / proc.c
diff --git a/subsystems/win/basesrv/proc.c b/subsystems/win/basesrv/proc.c
new file mode 100644 (file)
index 0000000..35aeec5
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS Base API Server DLL
+ * FILE:            subsystems/win/basesrv/proc.c
+ * PURPOSE:         Process and Thread Management
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include "basesrv.h"
+#include "vdm.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS ********************************************************************/
+
+/* User notification procedure to be called when a process is created */
+static BASE_PROCESS_CREATE_NOTIFY_ROUTINE UserNotifyProcessCreate = NULL;
+
+/* PUBLIC SERVER APIS *********************************************************/
+
+CSR_API(BaseSrvDebugProcess)
+{
+    /* Deprecated */
+    return STATUS_UNSUCCESSFUL;
+}
+
+CSR_API(BaseSrvRegisterThread)
+{
+    DPRINT1("%s not yet implemented\n", __FUNCTION__);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+CSR_API(BaseSrvSxsCreateActivationContext)
+{
+    DPRINT1("%s not yet implemented\n", __FUNCTION__);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+CSR_API(BaseSrvSetTermsrvAppInstallMode)
+{
+    DPRINT1("%s not yet implemented\n", __FUNCTION__);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+CSR_API(BaseSrvSetTermsrvClientTimeZone)
+{
+    DPRINT1("%s not yet implemented\n", __FUNCTION__);
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+CSR_API(BaseSrvGetTempFile)
+{
+    static UINT BaseGetTempFileUnique = 0;
+    PBASE_GET_TEMP_FILE GetTempFile = &((PBASE_API_MESSAGE)ApiMessage)->Data.GetTempFileRequest;
+
+    /* Return 16-bits ID */
+    GetTempFile->UniqueID = (++BaseGetTempFileUnique & 0xFFFF);
+
+    DPRINT("Returning: %u\n", GetTempFile->UniqueID);
+
+    return GetTempFile->UniqueID;
+}
+
+CSR_API(BaseSrvCreateProcess)
+{
+    NTSTATUS Status;
+    PBASE_CREATE_PROCESS CreateProcessRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.CreateProcessRequest;
+    HANDLE ProcessHandle, ThreadHandle;
+    PCSR_THREAD CsrThread;
+    PCSR_PROCESS Process;
+    ULONG Flags = 0, DebugFlags = 0, VdmPower = 0;
+
+    /* Get the current client thread */
+    CsrThread = CsrGetClientThread();
+    ASSERT(CsrThread != NULL);
+
+    Process = CsrThread->Process;
+
+    /* Extract the flags out of the process handle */
+    Flags = (ULONG_PTR)CreateProcessRequest->ProcessHandle & 3;
+    CreateProcessRequest->ProcessHandle = (HANDLE)((ULONG_PTR)CreateProcessRequest->ProcessHandle & ~3);
+
+    /* Some things should be done if this is a VDM process */
+    if (CreateProcessRequest->VdmBinaryType)
+    {
+        /* We need to set the VDM power later on */
+        VdmPower = 1;
+    }
+
+    /* Duplicate the process handle */
+    Status = NtDuplicateObject(Process->ProcessHandle,
+                               CreateProcessRequest->ProcessHandle,
+                               NtCurrentProcess(),
+                               &ProcessHandle,
+                               0,
+                               0,
+                               DUPLICATE_SAME_ACCESS);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to duplicate process handle: %lx\n", Status);
+        return Status;
+    }
+
+    /* Duplicate the thread handle */
+    Status = NtDuplicateObject(Process->ProcessHandle,
+                               CreateProcessRequest->ThreadHandle,
+                               NtCurrentProcess(),
+                               &ThreadHandle,
+                               0,
+                               0,
+                               DUPLICATE_SAME_ACCESS);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to duplicate thread handle: %lx\n", Status);
+        NtClose(ProcessHandle);
+        return Status;
+    }
+
+    /* If this is a VDM process, request VDM power */
+    if (VdmPower)
+    {
+        Status = NtSetInformationProcess(ProcessHandle,
+                                         ProcessWx86Information,
+                                         &VdmPower,
+                                         sizeof(VdmPower));
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to get VDM powers\n");
+            NtClose(ProcessHandle);
+            NtClose(ThreadHandle);
+            return Status;
+        }
+    }
+
+    /* Flags conversion. FIXME: More need conversion */
+    if (CreateProcessRequest->CreationFlags & CREATE_NEW_PROCESS_GROUP)
+    {
+        DebugFlags |= CsrProcessCreateNewGroup;
+    }
+    if ((Flags & 2) == 0)
+    {
+        /* We are launching a console process */
+        DebugFlags |= CsrProcessIsConsoleApp;
+    }
+
+    /* FIXME: SxS Stuff */
+
+    /* Call CSRSRV to create the CSR_PROCESS structure and the first CSR_THREAD */
+    Status = CsrCreateProcess(ProcessHandle,
+                              ThreadHandle,
+                              &CreateProcessRequest->ClientId,
+                              Process->NtSession,
+                              DebugFlags,
+                              NULL);
+    if (Status == STATUS_THREAD_IS_TERMINATING)
+    {
+        DPRINT1("Thread already dead\n");
+
+        /* Set the special reply value so we don't reply this message back */
+        *ReplyCode = CsrReplyDeadClient;
+
+        return Status;
+    }
+
+    /* Check for other failures */
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to create process/thread structures: %lx\n", Status);
+        return Status;
+    }
+
+    /* Call the user notification procedure */
+    if (UserNotifyProcessCreate)
+    {
+        UserNotifyProcessCreate(CreateProcessRequest->ClientId.UniqueProcess,
+                                Process->ClientId.UniqueThread,
+                                0,
+                                Flags);
+    }
+
+    /* Check if this is a VDM process */
+    if (CreateProcessRequest->VdmBinaryType)
+    {
+        PVDM_CONSOLE_RECORD ConsoleRecord;
+
+        if (CreateProcessRequest->VdmTask != 0)
+        {
+            /* Get the console record using the task ID */
+            Status = GetConsoleRecordBySessionId(CreateProcessRequest->VdmTask,
+                                                 &ConsoleRecord);
+        }
+        else
+        {
+            /* Get the console record using the console handle */
+            Status = BaseSrvGetConsoleRecord(CreateProcessRequest->hVDM,
+                                             &ConsoleRecord);
+        }
+
+        /* Check if it failed */
+        if (!NT_SUCCESS(Status)) return Status;
+
+        /* Store the process ID of the VDM in the console record */
+        ConsoleRecord->ProcessId = HandleToUlong(CreateProcessRequest->ClientId.UniqueProcess);
+    }
+
+    /* Return the result of this operation */
+    return Status;
+}
+
+CSR_API(BaseSrvCreateThread)
+{
+    NTSTATUS Status;
+    PBASE_CREATE_THREAD CreateThreadRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.CreateThreadRequest;
+    PCSR_THREAD CurrentThread;
+    HANDLE ThreadHandle;
+    PCSR_PROCESS CsrProcess;
+
+    /* Get the current CSR thread */
+    CurrentThread = CsrGetClientThread();
+    if (!CurrentThread)
+    {
+        DPRINT1("Server Thread TID: [%lx.%lx]\n",
+                CreateThreadRequest->ClientId.UniqueProcess,
+                CreateThreadRequest->ClientId.UniqueThread);
+        return STATUS_SUCCESS; // server-to-server
+    }
+
+    /* Get the CSR Process for this request */
+    CsrProcess = CurrentThread->Process;
+    if (CsrProcess->ClientId.UniqueProcess !=
+        CreateThreadRequest->ClientId.UniqueProcess)
+    {
+        /* This is a remote thread request -- is it within the server itself? */
+        if (CreateThreadRequest->ClientId.UniqueProcess == NtCurrentTeb()->ClientId.UniqueProcess)
+        {
+            /* Accept this without any further work */
+            return STATUS_SUCCESS;
+        }
+
+        /* Get the real CSR Process for the remote thread's process */
+        Status = CsrLockProcessByClientId(CreateThreadRequest->ClientId.UniqueProcess,
+                                          &CsrProcess);
+        if (!NT_SUCCESS(Status)) return Status;
+    }
+
+    /* Duplicate the thread handle so we can own it */
+    Status = NtDuplicateObject(CurrentThread->Process->ProcessHandle,
+                               CreateThreadRequest->ThreadHandle,
+                               NtCurrentProcess(),
+                               &ThreadHandle,
+                               0,
+                               0,
+                               DUPLICATE_SAME_ACCESS);
+    if (NT_SUCCESS(Status))
+    {
+        /* Call CSRSRV to tell it about the new thread */
+        Status = CsrCreateThread(CsrProcess,
+                                 ThreadHandle,
+                                 &CreateThreadRequest->ClientId,
+                                 TRUE);
+    }
+
+    /* Unlock the process and return */
+    if (CsrProcess != CurrentThread->Process) CsrUnlockProcess(CsrProcess);
+    return Status;
+}
+
+CSR_API(BaseSrvExitProcess)
+{
+    PCSR_THREAD CsrThread = CsrGetClientThread();
+    ASSERT(CsrThread != NULL);
+
+    /* Set the special reply value so we don't reply this message back */
+    *ReplyCode = CsrReplyDeadClient;
+
+    /* Remove the CSR_THREADs and CSR_PROCESS */
+    return CsrDestroyProcess(&CsrThread->ClientId,
+                             (NTSTATUS)((PBASE_API_MESSAGE)ApiMessage)->Data.ExitProcessRequest.uExitCode);
+}
+
+CSR_API(BaseSrvGetProcessShutdownParam)
+{
+    PBASE_GETSET_PROCESS_SHUTDOWN_PARAMS ShutdownParametersRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.ShutdownParametersRequest;
+    PCSR_THREAD CsrThread = CsrGetClientThread();
+    ASSERT(CsrThread);
+
+    ShutdownParametersRequest->ShutdownLevel = CsrThread->Process->ShutdownLevel;
+    /* Only SHUTDOWN_NORETRY flag is valid for this API. The other private flags are for CSRSRV/WINSRV only. */
+    ShutdownParametersRequest->ShutdownFlags = CsrThread->Process->ShutdownFlags & SHUTDOWN_NORETRY;
+
+    return STATUS_SUCCESS;
+}
+
+CSR_API(BaseSrvSetProcessShutdownParam)
+{
+    PBASE_GETSET_PROCESS_SHUTDOWN_PARAMS ShutdownParametersRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.ShutdownParametersRequest;
+    PCSR_THREAD CsrThread = CsrGetClientThread();
+    ASSERT(CsrThread);
+
+    /* Only SHUTDOWN_NORETRY flag is valid for this API. The other private flags are for CSRSRV/WINSRV only. */
+    if (ShutdownParametersRequest->ShutdownFlags & ~SHUTDOWN_NORETRY)
+    {
+        /* If there were other flags specified, fail the call */
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    CsrThread->Process->ShutdownLevel = ShutdownParametersRequest->ShutdownLevel;
+    /* Notice that all the possible other private flags are reinitialized here */
+    CsrThread->Process->ShutdownFlags = ShutdownParametersRequest->ShutdownFlags;
+
+    return STATUS_SUCCESS;
+}
+
+/* PUBLIC API *****************************************************************/
+
+VOID
+NTAPI
+BaseSetProcessCreateNotify(IN BASE_PROCESS_CREATE_NOTIFY_ROUTINE ProcessCreateNotifyProc)
+{
+    /* Set the user notification procedure to be called when a process is created */
+    UserNotifyProcessCreate = ProcessCreateNotifyProc;
+}
+
+/* EOF */