Here is all the deprecated code: the old CSR as well as the new one which wasn't included; the ReactOS-specific win32csr and the csr module of win32k.
svn path=/trunk/; revision=58771
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: Interface to csrss
+ * FILE: subsys/win32k/ntuser/csr.c
+ * PROGRAMER: Ge van Geldorp (ge@gse.nl)
+ */
+
+#include <win32k.h>
+
+static HANDLE WindowsApiPort = NULL;
+PEPROCESS CsrProcess = NULL;
+
+NTSTATUS FASTCALL
+CsrInit(void)
+{
+ NTSTATUS Status;
+ UNICODE_STRING PortName;
+ ULONG ConnectInfoLength;
+ SECURITY_QUALITY_OF_SERVICE Qos;
+
+ RtlInitUnicodeString(&PortName, L"\\Windows\\ApiPort");
+ ConnectInfoLength = 0;
+ Qos.Length = sizeof(Qos);
+ Qos.ImpersonationLevel = SecurityDelegation;
+ Qos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
+ Qos.EffectiveOnly = FALSE;
+
+ Status = ZwConnectPort(&WindowsApiPort,
+ &PortName,
+ &Qos,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &ConnectInfoLength);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ CsrProcess = PsGetCurrentProcess();
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS FASTCALL
+co_CsrNotify(PCSR_API_MESSAGE Request)
+{
+ NTSTATUS Status;
+ PEPROCESS OldProcess;
+
+ if (NULL == CsrProcess)
+ {
+ return STATUS_INVALID_PORT_HANDLE;
+ }
+
+ Request->Header.u2.ZeroInit = 0;
+ Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
+ Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
+
+ /* Switch to the process in which the WindowsApiPort handle is valid */
+ OldProcess = PsGetCurrentProcess();
+ if (CsrProcess != OldProcess)
+ {
+ KeAttachProcess(&CsrProcess->Pcb);
+ }
+
+ UserLeaveCo();
+
+ Status = ZwRequestWaitReplyPort(WindowsApiPort,
+ &Request->Header,
+ &Request->Header);
+
+ UserEnterCo();
+
+ if (CsrProcess != OldProcess)
+ {
+ KeDetachProcess();
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ Status = Request->Status;
+ }
+
+ return Status;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: Interface to csrss
+ * FILE: subsys/win32k/include/csr.h
+ * PROGRAMER: Ge van Geldorp (ge@gse.nl)
+ */
+
+#pragma once
+
+extern PEPROCESS CsrProcess;
+
+NTSTATUS FASTCALL CsrInit(void);
+NTSTATUS FASTCALL co_CsrNotify(PCSR_API_MESSAGE Request);
+NTSTATUS FASTCALL CsrCloseHandle(HANDLE Handle);
+NTSTATUS WINAPI CsrInsertObject(HANDLE ObjectHandle,
+ ACCESS_MASK DesiredAccess,
+ PHANDLE Handle);
+
+/* EOF */
--- /dev/null
+
+include_directories(
+ include
+ ${REACTOS_SOURCE_DIR}/include/reactos/subsys
+ ${REACTOS_SOURCE_DIR}/include/reactos/drivers)
+
+add_executable(csrss2 main.c csr.rc)
+
+set_module_type(csrss2 nativecui)
+target_link_libraries(csrss2 nt)
+add_importlibs(csrss2 ntdll csrsrv2)
+add_dependencies(csrss2 psdk bugcodes)
+add_cd_file(TARGET csrss2 DESTINATION reactos/system32 FOR all)
+
+add_subdirectory(csrsrv)
+
--- /dev/null
+#define REACTOS_STR_FILE_DESCRIPTION "Client/Server Runtime Process\0"
+#define REACTOS_STR_INTERNAL_NAME "csrss\0"
+#define REACTOS_STR_ORIGINAL_FILENAME "csrss.exe\0"
+#include <reactos/version.rc>
--- /dev/null
+
+include_directories(${REACTOS_SOURCE_DIR}/subsystems/win32/csrss/include)
+include_directories(${REACTOS_SOURCE_DIR}/include/reactos/subsys)
+
+spec2def(csrsrv2.dll csrsrv2.spec ADD_IMPORTLIB)
+
+list(APPEND SOURCE
+ api.c
+ init.c
+ process.c
+ server.c
+ session.c
+ thread.c
+ wait.c
+ csrsrv.rc
+ ${CMAKE_CURRENT_BINARY_DIR}/csrsrv2.def)
+
+add_library(csrsrv2 SHARED ${SOURCE})
+
+target_link_libraries(csrsrv2 ${PSEH_LIB} smlib)
+
+set_module_type(csrsrv2 nativedll)
+
+add_importlibs(csrsrv2 ntdll)
+
+add_pch(csrsrv2 srv.h)
+
+add_dependencies(csrsrv2 psdk bugcodes)
+add_cd_file(TARGET csrsrv2 DESTINATION reactos/system32 FOR all)
+
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CSR Sub System
+ * FILE: subsys/csr/csrsrv/api.c
+ * PURPOSE: CSR Server DLL API LPC Implementation
+ * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "srv.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* DATA **********************************************************************/
+BOOLEAN (*CsrClientThreadSetup)(VOID) = NULL;
+ULONG CsrMaxApiRequestThreads;
+UNICODE_STRING CsrSbApiPortName;
+UNICODE_STRING CsrApiPortName;
+HANDLE CsrSbApiPort;
+HANDLE CsrApiPort;
+PCSR_THREAD CsrSbApiRequestThreadPtr;
+volatile LONG CsrpStaticThreadCount;
+volatile LONG CsrpDynamicThreadTotal;
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+/*++
+ * @name CsrpCheckRequestThreads
+ *
+ * The CsrpCheckRequestThreads routine checks if there are no more threads
+ * to handle CSR API Requests, and creates a new thread if possible, to
+ * avoid starvation.
+ *
+ * @param None.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * if a new thread couldn't be created.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrpCheckRequestThreads(VOID)
+{
+ HANDLE hThread;
+ CLIENT_ID ClientId;
+ NTSTATUS Status;
+
+ /* Decrease the count, and see if we're out */
+ if (!(_InterlockedDecrement(&CsrpStaticThreadCount)))
+ {
+ /* Check if we've still got space for a Dynamic Thread */
+ if (CsrpDynamicThreadTotal < CsrMaxApiRequestThreads)
+ {
+ /* Create a new dynamic thread */
+ Status = RtlCreateUserThread(NtCurrentProcess(),
+ NULL,
+ TRUE,
+ 0,
+ 0,
+ 0,
+ (PVOID)CsrApiRequestThread,
+ NULL,
+ &hThread,
+ &ClientId);
+ /* Check success */
+ if (NT_SUCCESS(Status))
+ {
+ /* Increase the thread counts */
+ _InterlockedIncrement(&CsrpStaticThreadCount);
+ _InterlockedIncrement(&CsrpDynamicThreadTotal);
+
+ /* Add a new server thread */
+ if (CsrAddStaticServerThread(hThread,
+ &ClientId,
+ CsrThreadIsServerThread))
+ {
+ /* Activate it */
+ NtResumeThread(hThread,NULL);
+ }
+ else
+ {
+ /* Failed to create a new static thread */
+ _InterlockedDecrement(&CsrpStaticThreadCount);
+ _InterlockedDecrement(&CsrpDynamicThreadTotal);
+
+ /* Terminate it */
+ NtTerminateThread(hThread,0);
+ NtClose(hThread);
+
+ /* Return */
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+ }
+ }
+
+ /* Success */
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrSbApiPortInitialize
+ *
+ * The CsrSbApiPortInitialize routine initializes the LPC Port used for
+ * communications with the Session Manager (SM) and initializes the static
+ * thread that will handle connection requests and APIs.
+ *
+ * @param None
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSbApiPortInitialize(VOID)
+{
+ ULONG Size;
+ PSECURITY_DESCRIPTOR PortSd;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ NTSTATUS Status;
+ HANDLE hRequestThread;
+ CLIENT_ID ClientId;
+
+ /* Calculate how much space we'll need for the Port Name */
+ Size = CsrDirectoryName.Length + sizeof(SB_PORT_NAME) + sizeof(WCHAR);
+
+ /* Create the buffer for it */
+ CsrSbApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
+ if (!CsrSbApiPortName.Buffer) return STATUS_NO_MEMORY;
+
+ /* Setup the rest of the empty string */
+ CsrSbApiPortName.Length = 0;
+ CsrSbApiPortName.MaximumLength = (USHORT)Size;
+
+ /* Now append the full port name */
+ RtlAppendUnicodeStringToString(&CsrSbApiPortName, &CsrDirectoryName);
+ RtlAppendUnicodeToString(&CsrSbApiPortName, UNICODE_PATH_SEP);
+ RtlAppendUnicodeToString(&CsrSbApiPortName, SB_PORT_NAME);
+ if (CsrDebug & 2) DPRINT1("CSRSS: Creating %wZ port and associated thread\n", &CsrSbApiPortName);
+
+ /* Create Security Descriptor for this Port */
+ Status = CsrCreateLocalSystemSD(&PortSd);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Initialize the Attributes */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &CsrSbApiPortName,
+ 0,
+ NULL,
+ PortSd);
+
+ /* Create the Port Object */
+ Status = NtCreatePort(&CsrSbApiPort,
+ &ObjectAttributes,
+ sizeof(SB_CONNECTION_INFO),
+ sizeof(SB_API_MSG),
+ 32 * sizeof(SB_API_MSG));
+ if (PortSd) RtlFreeHeap(CsrHeap, 0, PortSd);
+
+ if (NT_SUCCESS(Status))
+ {
+ /* Create the Thread to handle the API Requests */
+ Status = RtlCreateUserThread(NtCurrentProcess(),
+ NULL,
+ TRUE,
+ 0,
+ 0,
+ 0,
+ (PVOID)CsrSbApiRequestThread,
+ NULL,
+ &hRequestThread,
+ &ClientId);
+ if (NT_SUCCESS(Status))
+ {
+ /* Add it as a Static Server Thread */
+ CsrSbApiRequestThreadPtr = CsrAddStaticServerThread(hRequestThread,
+ &ClientId,
+ 0);
+
+ /* Activate it */
+ Status = NtResumeThread(hRequestThread, NULL);
+ }
+ }
+
+ return Status;
+}
+
+/*++
+ * @name CsrApiPortInitialize
+ *
+ * The CsrApiPortInitialize routine initializes the LPC Port used for
+ * communications with the Client/Server Runtime (CSR) and initializes the
+ * static thread that will handle connection requests and APIs.
+ *
+ * @param None
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrApiPortInitialize(VOID)
+{
+ ULONG Size;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ NTSTATUS Status;
+ HANDLE hRequestEvent, hThread;
+ CLIENT_ID ClientId;
+ PLIST_ENTRY ListHead, NextEntry;
+ PCSR_THREAD ServerThread;
+
+ /* Calculate how much space we'll need for the Port Name */
+ Size = CsrDirectoryName.Length + sizeof(CSR_PORT_NAME) + sizeof(WCHAR);
+
+ /* Create the buffer for it */
+ CsrApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
+ if (!CsrApiPortName.Buffer) return STATUS_NO_MEMORY;
+
+ /* Setup the rest of the empty string */
+ CsrApiPortName.Length = 0;
+ CsrApiPortName.MaximumLength = (USHORT)Size;
+ RtlAppendUnicodeStringToString(&CsrApiPortName, &CsrDirectoryName);
+ RtlAppendUnicodeToString(&CsrApiPortName, UNICODE_PATH_SEP);
+ RtlAppendUnicodeToString(&CsrApiPortName, CSR_PORT_NAME);
+ if (CsrDebug & 1)
+ {
+ DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName);
+ DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
+ sizeof(CSR_CONNECTION_INFO), sizeof(CSR_API_MESSAGE));
+ }
+
+ /* FIXME: Create a Security Descriptor */
+
+ /* Initialize the Attributes */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &CsrApiPortName,
+ 0,
+ NULL,
+ NULL /* FIXME*/);
+
+ /* Create the Port Object */
+ Status = NtCreatePort(&CsrApiPort,
+ &ObjectAttributes,
+ sizeof(CSR_CONNECTION_INFO),
+ sizeof(CSR_API_MESSAGE),
+ 16 * PAGE_SIZE);
+ if (NT_SUCCESS(Status))
+ {
+ /* Create the event the Port Thread will use */
+ Status = NtCreateEvent(&hRequestEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE);
+ if (NT_SUCCESS(Status))
+ {
+ /* Create the Request Thread */
+ Status = RtlCreateUserThread(NtCurrentProcess(),
+ NULL,
+ TRUE,
+ 0,
+ 0,
+ 0,
+ (PVOID)CsrApiRequestThread,
+ (PVOID)hRequestEvent,
+ &hThread,
+ &ClientId);
+ if (NT_SUCCESS(Status))
+ {
+ /* Add this as a static thread to CSRSRV */
+ CsrAddStaticServerThread(hThread, &ClientId, CsrThreadIsServerThread);
+
+ /* Get the Thread List Pointers */
+ ListHead = &CsrRootProcess->ThreadList;
+ NextEntry = ListHead->Flink;
+
+ /* Start looping the list */
+ while (NextEntry != ListHead)
+ {
+ /* Get the Thread */
+ ServerThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
+
+ /* Start it up */
+ Status = NtResumeThread(ServerThread->ThreadHandle, NULL);
+
+ /* Is this a Server Thread? */
+ if (ServerThread->Flags & CsrThreadIsServerThread)
+ {
+ /* If so, then wait for it to initialize */
+ Status = NtWaitForSingleObject(hRequestEvent, FALSE, NULL);
+ ASSERT(NT_SUCCESS(Status));
+ }
+
+ /* Next thread */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* We don't need this anymore */
+ NtClose(hRequestEvent);
+ }
+ }
+ }
+
+ /* Return */
+ return Status;
+}
+
+/*++
+ * @name CsrApiRequestThread
+ *
+ * The CsrApiRequestThread routine handles incoming messages or connection
+ * requests on the CSR API LPC Port.
+ *
+ * @param Parameter
+ * System-default user-defined parameter. Unused.
+ *
+ * @return The thread exit code, if the thread is terminated.
+ *
+ * @remarks Before listening on the port, the routine will first attempt
+ * to connect to the user subsystem.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrApiRequestThread(IN PVOID Parameter)
+{
+ PTEB Teb = NtCurrentTeb();
+ LARGE_INTEGER TimeOut;
+ PCSR_THREAD CurrentThread, CsrThread;
+ NTSTATUS Status;
+ PCSR_API_MESSAGE ReplyMsg;
+ CSR_API_MESSAGE ReceiveMsg;
+ PCSR_PROCESS CsrProcess;
+ PHARDERROR_MSG HardErrorMsg;
+ PVOID PortContext;
+ PCSR_SERVER_DLL ServerDll;
+ PCLIENT_DIED_MSG ClientDiedMsg;
+ PDBGKM_MSG DebugMessage;
+ ULONG ServerId, ApiId, Reply, MessageType, i;
+ HANDLE ReplyPort;
+
+ /* Setup LPC loop port and message */
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+
+ /* Connect to user32 */
+ while (!CsrConnectToUser())
+ {
+ /* Set up the timeout for the connect (30 seconds) */
+ TimeOut.QuadPart = -30 * 1000 * 1000 * 10;
+
+ /* Keep trying until we get a response */
+ Teb->Win32ClientInfo[0] = 0;
+ NtDelayExecution(FALSE, &TimeOut);
+ }
+
+ /* Get our thread */
+ CurrentThread = Teb->CsrClientThread;
+
+ /* If we got an event... */
+ if (Parameter)
+ {
+ /* Set it, to let stuff waiting on us load */
+ Status = NtSetEvent((HANDLE)Parameter, NULL);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Increase the Thread Counts */
+ _InterlockedIncrement(&CsrpStaticThreadCount);
+ _InterlockedIncrement(&CsrpDynamicThreadTotal);
+ }
+
+ /* Now start the loop */
+ while (TRUE)
+ {
+ /* Make sure the real CID is set */
+ Teb->RealClientId = Teb->ClientId;
+
+ /* Debug check */
+ if (Teb->CountOfOwnedCriticalSections)
+ {
+ DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
+ Teb->CountOfOwnedCriticalSections);
+ DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
+ &ReceiveMsg, ReplyMsg);
+ DbgBreakPoint();
+ }
+
+ /* Wait for a message to come through */
+ Status = NtReplyWaitReceivePort(ReplyPort,
+ &PortContext,
+ &ReplyMsg->Header,
+ &ReceiveMsg.Header);
+
+ /* Check if we didn't get success */
+ if (Status != STATUS_SUCCESS)
+ {
+ /* Was it a failure or another success code? */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Check for specific status cases */
+ if ((Status != STATUS_INVALID_CID) &&
+ (Status != STATUS_UNSUCCESSFUL) &&
+ ((Status == STATUS_INVALID_HANDLE) || (ReplyPort == CsrApiPort)))
+ {
+ /* Notify the debugger */
+ DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status);
+ DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort, CsrApiPort);
+ }
+
+ /* We failed big time, so start out fresh */
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+ continue;
+ }
+ else
+ {
+ /* A bizare "success" code, just try again */
+ DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status);
+ continue;
+ }
+ }
+
+ /* Use whatever Client ID we got */
+ Teb->RealClientId = ReceiveMsg.Header.ClientId;
+
+ /* Get the Message Type */
+ MessageType = ReceiveMsg.Header.u2.s2.Type;
+
+ /* Handle connection requests */
+ if (MessageType == LPC_CONNECTION_REQUEST)
+ {
+ /* Handle the Connection Request */
+ CsrApiHandleConnectionRequest(&ReceiveMsg);
+ ReplyPort = CsrApiPort;
+ ReplyMsg = NULL;
+ continue;
+ }
+
+ /* It's some other kind of request. Get the lock for the lookup */
+ CsrAcquireProcessLock();
+
+ /* Now do the lookup to get the CSR_THREAD */
+ CsrThread = CsrLocateThreadByClientId(&CsrProcess,
+ &ReceiveMsg.Header.ClientId);
+
+ /* Did we find a thread? */
+ if (!CsrThread)
+ {
+ /* This wasn't a CSR Thread, release lock */
+ CsrReleaseProcessLock();
+
+ /* If this was an exception, handle it */
+ if (MessageType == LPC_EXCEPTION)
+ {
+ ReplyMsg = &ReceiveMsg;
+ ReplyPort = CsrApiPort;
+ ReplyMsg->Status = DBG_CONTINUE;
+ }
+ else if (MessageType == LPC_PORT_CLOSED ||
+ MessageType == LPC_CLIENT_DIED)
+ {
+ /* The Client or Port are gone, loop again */
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+ }
+ else if (MessageType == LPC_ERROR_EVENT)
+ {
+ /* If it's a hard error, handle this too */
+ HardErrorMsg = (PHARDERROR_MSG)&ReceiveMsg;
+
+ /* Default it to unhandled */
+ HardErrorMsg->Response = ResponseNotHandled;
+
+ /* Check if there are free api threads */
+ CsrpCheckRequestThreads();
+ if (CsrpStaticThreadCount)
+ {
+ /* Loop every Server DLL */
+ for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+ {
+ /* Get the Server DLL */
+ ServerDll = CsrLoadedServerDll[i];
+
+ /* Check if it's valid and if it has a Hard Error Callback */
+ if ((ServerDll) && (ServerDll->HardErrorCallback))
+ {
+ /* Call it */
+ ServerDll->HardErrorCallback(NULL, HardErrorMsg);
+
+ /* If it's handled, get out of here */
+ if (HardErrorMsg->Response != ResponseNotHandled) break;
+ }
+ }
+ }
+
+ /* Increase the thread count */
+ _InterlockedIncrement(&CsrpStaticThreadCount);
+
+ /* If the response was 0xFFFFFFFF, we'll ignore it */
+ if (HardErrorMsg->Response == 0xFFFFFFFF)
+ {
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+ }
+ else
+ {
+ ReplyMsg = &ReceiveMsg;
+ }
+ }
+ else if (MessageType == LPC_REQUEST)
+ {
+ /* This is an API Message coming from a non-CSR Thread */
+ ReplyMsg = &ReceiveMsg;
+ ReplyPort = CsrApiPort;
+ ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
+ }
+ else if (MessageType == LPC_DATAGRAM)
+ {
+ /* This is an API call, get the Server ID */
+ ServerId = CSR_SERVER_ID_FROM_OPCODE(ReceiveMsg.Opcode);
+
+ /* Make sure that the ID is within limits, and the Server DLL loaded */
+ ServerDll = NULL;
+ if ((ServerId >= CSR_SERVER_DLL_MAX) ||
+ (!(ServerDll = CsrLoadedServerDll[ServerId])))
+ {
+ /* We are beyond the Maximum Server ID */
+ DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
+ ServerId, ServerDll);
+ DbgBreakPoint();
+ ReplyPort = CsrApiPort;
+ ReplyMsg = NULL;
+ continue;
+ }
+
+ /* Get the API ID */
+ ApiId = CSR_API_ID_FROM_OPCODE(ReceiveMsg.Opcode);
+
+ /* Normalize it with our Base ID */
+ ApiId -= ServerDll->ApiBase;
+
+ /* Make sure that the ID is within limits, and the entry exists */
+ if (ApiId >= ServerDll->HighestApiSupported)
+ {
+ /* We are beyond the Maximum API ID, or it doesn't exist */
+ DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
+ CSR_API_ID_FROM_OPCODE(ReceiveMsg.Opcode),
+ &ServerDll->Name);
+ ReplyPort = CsrApiPort;
+ ReplyMsg = NULL;
+ continue;
+ }
+
+ if (CsrDebug & 2)
+ {
+ DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
+ Teb->ClientId.UniqueThread,
+ ReceiveMsg.Header.ClientId.UniqueProcess,
+ ReceiveMsg.Header.ClientId.UniqueThread,
+ ServerDll->NameTable[ApiId],
+ NULL);
+ }
+
+ /* Assume success */
+ ReceiveMsg.Status = STATUS_SUCCESS;
+
+ /* Validation complete, start SEH */
+ _SEH2_TRY
+ {
+ /* Make sure we have enough threads */
+ CsrpCheckRequestThreads();
+
+ /* Call the API and get the result */
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+ ServerDll->DispatchTable[ApiId](&ReceiveMsg, &Reply);
+
+ /* Increase the static thread count */
+ _InterlockedIncrement(&CsrpStaticThreadCount);
+ }
+ _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
+ {
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+ }
+ _SEH2_END;
+ }
+ else
+ {
+ /* Some other ignored message type */
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+ }
+
+ /* Keep going */
+ continue;
+ }
+
+ /* We have a valid thread, was this an LPC Request? */
+ if (MessageType != LPC_REQUEST)
+ {
+ /* It's not an API, check if the client died */
+ if (MessageType == LPC_CLIENT_DIED)
+ {
+ /* Get the information and check if it matches our thread */
+ ClientDiedMsg = (PCLIENT_DIED_MSG)&ReceiveMsg;
+ if (ClientDiedMsg->CreateTime.QuadPart == CsrThread->CreateTime.QuadPart)
+ {
+ /* Reference the thread */
+ CsrLockedReferenceThread(CsrThread);
+
+ /* Destroy the thread in the API Message */
+ CsrDestroyThread(&ReceiveMsg.Header.ClientId);
+
+ /* Check if the thread was actually ourselves */
+ if (CsrProcess->ThreadCount == 1)
+ {
+ /* Kill the process manually here */
+ CsrDestroyProcess(&CsrThread->ClientId, 0);
+ }
+
+ /* Remove our extra reference */
+ CsrLockedDereferenceThread(CsrThread);
+ }
+
+ /* Release the lock and keep looping */
+ CsrReleaseProcessLock();
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+ continue;
+ }
+
+ /* Reference the thread and release the lock */
+ CsrLockedReferenceThread(CsrThread);
+ CsrReleaseProcessLock();
+
+ /* Check if this was an exception */
+ if (MessageType == LPC_EXCEPTION)
+ {
+ /* Kill the process */
+ NtTerminateProcess(CsrProcess->ProcessHandle, STATUS_ABANDONED);
+
+ /* Destroy it from CSR */
+ CsrDestroyProcess(&ReceiveMsg.Header.ClientId, STATUS_ABANDONED);
+
+ /* Return a Debug Message */
+ DebugMessage = (PDBGKM_MSG)&ReceiveMsg;
+ DebugMessage->ReturnedStatus = DBG_CONTINUE;
+ ReplyMsg = &ReceiveMsg;
+ ReplyPort = CsrApiPort;
+
+ /* Remove our extra reference */
+ CsrDereferenceThread(CsrThread);
+ }
+ else if (MessageType == LPC_ERROR_EVENT)
+ {
+ /* If it's a hard error, handle this too */
+ HardErrorMsg = (PHARDERROR_MSG)&ReceiveMsg;
+
+ /* Default it to unhandled */
+ HardErrorMsg->Response = ResponseNotHandled;
+
+ /* Check if there are free api threads */
+ CsrpCheckRequestThreads();
+ if (CsrpStaticThreadCount)
+ {
+ /* Loop every Server DLL */
+ for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+ {
+ /* Get the Server DLL */
+ ServerDll = CsrLoadedServerDll[i];
+
+ /* Check if it's valid and if it has a Hard Error Callback */
+ if ((ServerDll) && (ServerDll->HardErrorCallback))
+ {
+ /* Call it */
+ ServerDll->HardErrorCallback(CsrThread, HardErrorMsg);
+
+ /* If it's handled, get out of here */
+ if (HardErrorMsg->Response != ResponseNotHandled) break;
+ }
+ }
+ }
+
+ /* Increase the thread count */
+ _InterlockedIncrement(&CsrpStaticThreadCount);
+
+ /* If the response was 0xFFFFFFFF, we'll ignore it */
+ if (HardErrorMsg->Response == 0xFFFFFFFF)
+ {
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+ }
+ else
+ {
+ CsrDereferenceThread(CsrThread);
+ ReplyMsg = &ReceiveMsg;
+ ReplyPort = CsrApiPort;
+ }
+ }
+ else
+ {
+ /* Something else */
+ CsrDereferenceThread(CsrThread);
+ ReplyMsg = NULL;
+ }
+
+ /* Keep looping */
+ continue;
+ }
+
+ /* We got an API Request */
+ CsrLockedReferenceThread(CsrThread);
+ CsrReleaseProcessLock();
+
+ /* This is an API call, get the Server ID */
+ ServerId = CSR_SERVER_ID_FROM_OPCODE(ReceiveMsg.Opcode);
+
+ /* Make sure that the ID is within limits, and the Server DLL loaded */
+ ServerDll = NULL;
+ if ((ServerId >= CSR_SERVER_DLL_MAX) ||
+ (!(ServerDll = CsrLoadedServerDll[ServerId])))
+ {
+ /* We are beyond the Maximum Server ID */
+ DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
+ ServerId, ServerDll);
+ DbgBreakPoint();
+
+ ReplyPort = CsrApiPort;
+ ReplyMsg = &ReceiveMsg;
+ ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
+ CsrDereferenceThread(CsrThread);
+ continue;
+ }
+
+ /* Get the API ID */
+ ApiId = CSR_API_ID_FROM_OPCODE(ReceiveMsg.Opcode);
+
+ /* Normalize it with our Base ID */
+ ApiId -= ServerDll->ApiBase;
+
+ /* Make sure that the ID is within limits, and the entry exists */
+ if (ApiId >= ServerDll->HighestApiSupported)
+ {
+ /* We are beyond the Maximum API ID, or it doesn't exist */
+ DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
+ CSR_API_ID_FROM_OPCODE(ReceiveMsg.Opcode),
+ &ServerDll->Name);
+
+ ReplyPort = CsrApiPort;
+ ReplyMsg = &ReceiveMsg;
+ ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
+ CsrDereferenceThread(CsrThread);
+ continue;
+ }
+
+ if (CsrDebug & 2)
+ {
+ DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
+ Teb->ClientId.UniqueThread,
+ ReceiveMsg.Header.ClientId.UniqueProcess,
+ ReceiveMsg.Header.ClientId.UniqueThread,
+ ServerDll->NameTable[ApiId],
+ CsrThread);
+ }
+
+ /* Assume success */
+ ReplyMsg = &ReceiveMsg;
+ ReceiveMsg.Status = STATUS_SUCCESS;
+
+ /* Now we reply to a particular client */
+ ReplyPort = CsrThread->Process->ClientPort;
+
+ /* Check if there's a capture buffer */
+ if (ReceiveMsg.CsrCaptureData)
+ {
+ /* Capture the arguments */
+ if (!CsrCaptureArguments(CsrThread, &ReceiveMsg))
+ {
+ /* Ignore this message if we failed to get the arguments */
+ CsrDereferenceThread(CsrThread);
+ continue;
+ }
+ }
+
+ /* Validation complete, start SEH */
+ _SEH2_TRY
+ {
+ /* Make sure we have enough threads */
+ CsrpCheckRequestThreads();
+
+ Teb->CsrClientThread = CsrThread;
+
+ /* Call the API and get the result */
+ Reply = 0;
+ ServerDll->DispatchTable[ApiId](&ReceiveMsg, &Reply);
+
+ /* Increase the static thread count */
+ _InterlockedIncrement(&CsrpStaticThreadCount);
+
+ Teb->CsrClientThread = CurrentThread;
+
+ if (Reply == 3)
+ {
+ ReplyMsg = NULL;
+ if (ReceiveMsg.CsrCaptureData)
+ {
+ CsrReleaseCapturedArguments(&ReceiveMsg);
+ }
+ CsrDereferenceThread(CsrThread);
+ ReplyPort = CsrApiPort;
+ }
+ else if (Reply == 2)
+ {
+ NtReplyPort(ReplyPort, &ReplyMsg->Header);
+ ReplyPort = CsrApiPort;
+ ReplyMsg = NULL;
+ CsrDereferenceThread(CsrThread);
+ }
+ else if (Reply == 1)
+ {
+ ReplyPort = CsrApiPort;
+ ReplyMsg = NULL;
+ }
+ else
+ {
+ if (ReceiveMsg.CsrCaptureData)
+ {
+ CsrReleaseCapturedArguments(&ReceiveMsg);
+ }
+ CsrDereferenceThread(CsrThread);
+ }
+ }
+ _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
+ {
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+ }
+ _SEH2_END;
+ }
+
+ /* We're out of the loop for some reason, terminate! */
+ NtTerminateThread(NtCurrentThread(), Status);
+ return Status;
+}
+
+/*++
+ * @name CsrApiHandleConnectionRequest
+ *
+ * The CsrApiHandleConnectionRequest routine handles and accepts a new
+ * connection request to the CSR API LPC Port.
+ *
+ * @param ApiMessage
+ * Pointer to the incoming CSR API Message which contains the
+ * connection request.
+ *
+ * @return STATUS_SUCCESS in case of success, or status code which caused
+ * the routine to error.
+ *
+ * @remarks This routine is responsible for attaching the Shared Section to
+ * new clients connecting to CSR.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrApiHandleConnectionRequest(IN PCSR_API_MESSAGE ApiMessage)
+{
+ PCSR_THREAD CsrThread = NULL;
+ PCSR_PROCESS CsrProcess = NULL;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PCSR_CONNECTION_INFO ConnectInfo = &ApiMessage->ConnectionInfo;
+ BOOLEAN AllowConnection = FALSE;
+ REMOTE_PORT_VIEW RemotePortView;
+ HANDLE hPort;
+
+ /* Acquire the Process Lock */
+ CsrAcquireProcessLock();
+
+ /* Lookup the CSR Thread */
+ CsrThread = CsrLocateThreadByClientId(NULL, &ApiMessage->Header.ClientId);
+
+ /* Check if we have a thread */
+ if (CsrThread)
+ {
+ /* Get the Process */
+ CsrProcess = CsrThread->Process;
+
+ /* Make sure we have a Process as well */
+ if (CsrProcess)
+ {
+ /* Reference the Process */
+ CsrLockedReferenceProcess(CsrThread->Process);
+
+ /* Release the lock */
+ CsrReleaseProcessLock();
+
+ /* Duplicate the Object Directory */
+ Status = NtDuplicateObject(NtCurrentProcess(),
+ CsrObjectDirectory,
+ CsrProcess->ProcessHandle,
+ &ConnectInfo->ObjectDirectory,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS |
+ DUPLICATE_SAME_ATTRIBUTES);
+
+ /* Acquire the lock */
+ CsrAcquireProcessLock();
+
+ /* Check for success */
+ if (NT_SUCCESS(Status))
+ {
+ /* Attach the Shared Section */
+ Status = CsrSrvAttachSharedSection(CsrProcess, ConnectInfo);
+
+ /* Check how this went */
+ if (NT_SUCCESS(Status)) AllowConnection = TRUE;
+ }
+
+ /* Dereference the project */
+ CsrLockedDereferenceProcess(CsrProcess);
+ }
+ }
+
+ /* Release the lock */
+ CsrReleaseProcessLock();
+
+ /* Setup the Port View Structure */
+ RemotePortView.Length = sizeof(REMOTE_PORT_VIEW);
+ RemotePortView.ViewSize = 0;
+ RemotePortView.ViewBase = NULL;
+
+ /* Save the Process ID */
+ ConnectInfo->ProcessId = NtCurrentTeb()->ClientId.UniqueProcess;
+
+ /* Accept the Connection */
+ Status = NtAcceptConnectPort(&hPort,
+ AllowConnection ? UlongToPtr(CsrProcess->SequenceNumber) : 0,
+ &ApiMessage->Header,
+ AllowConnection,
+ NULL,
+ &RemotePortView);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status);
+ }
+ else if (AllowConnection)
+ {
+ if (CsrDebug & 2)
+ {
+ DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
+ ApiMessage->Header.ClientId.UniqueProcess,
+ ApiMessage->Header.ClientId.UniqueThread,
+ RemotePortView.ViewBase,
+ RemotePortView.ViewSize);
+ }
+
+ /* Set some Port Data in the Process */
+ CsrProcess->ClientPort = hPort;
+ CsrProcess->ClientViewBase = (ULONG_PTR)RemotePortView.ViewBase;
+ CsrProcess->ClientViewBounds = (ULONG_PTR)((ULONG_PTR)RemotePortView.ViewBase +
+ (ULONG_PTR)RemotePortView.ViewSize);
+
+ /* Complete the connection */
+ Status = NtCompleteConnectPort(hPort);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status);
+ }
+ }
+ else
+ {
+ DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
+ ApiMessage->Header.ClientId.UniqueProcess,
+ ApiMessage->Header.ClientId.UniqueThread);
+ }
+
+ /* Return status to caller */
+ return Status;
+}
+
+/*++
+ * @name CsrSbApiRequestThread
+ *
+ * The CsrSbApiRequestThread routine handles incoming messages or connection
+ * requests on the SM API LPC Port.
+ *
+ * @param Parameter
+ * System-default user-defined parameter. Unused.
+ *
+ * @return The thread exit code, if the thread is terminated.
+ *
+ * @remarks Before listening on the port, the routine will first attempt
+ * to connect to the user subsystem.
+ *
+ *--*/
+VOID
+NTAPI
+CsrSbApiRequestThread(IN PVOID Parameter)
+{
+ NTSTATUS Status;
+ SB_API_MSG ReceiveMsg;
+ PSB_API_MSG ReplyMsg = NULL;
+ PVOID PortContext;
+ ULONG MessageType;
+
+ /* Start the loop */
+ while (TRUE)
+ {
+ /* Wait for a message to come in */
+ Status = NtReplyWaitReceivePort(CsrSbApiPort,
+ &PortContext,
+ &ReplyMsg->h,
+ &ReceiveMsg.h);
+
+ /* Check if we didn't get success */
+ if (Status != STATUS_SUCCESS)
+ {
+ /* If we only got a warning, keep going */
+ if (NT_SUCCESS(Status)) continue;
+
+ /* We failed big time, so start out fresh */
+ ReplyMsg = NULL;
+ DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status);
+ continue;
+ }
+
+ /* Save the message type */
+ MessageType = ReceiveMsg.h.u2.s2.Type;
+
+ /* Check if this is a connection request */
+ if (MessageType == LPC_CONNECTION_REQUEST)
+ {
+ /* Handle connection request */
+ CsrSbApiHandleConnectionRequest(&ReceiveMsg);
+
+ /* Start over */
+ ReplyMsg = NULL;
+ continue;
+ }
+
+ /* Check if the port died */
+ if (MessageType == LPC_PORT_CLOSED)
+ {
+ /* Close the handle if we have one */
+ if (PortContext) NtClose((HANDLE)PortContext);
+
+ /* Client died, start over */
+ ReplyMsg = NULL;
+ continue;
+ }
+ else if (MessageType == LPC_CLIENT_DIED)
+ {
+ /* Client died, start over */
+ ReplyMsg = NULL;
+ continue;
+ }
+
+ /*
+ * It's an API Message, check if it's within limits. If it's not, the
+ * NT Behaviour is to set this to the Maximum API.
+ */
+ if (ReceiveMsg.ApiNumber > SbpMaxApiNumber)
+ {
+ ReceiveMsg.ApiNumber = SbpMaxApiNumber;
+ DPRINT1("CSRSS: %lx is invalid Sb ApiNumber\n", ReceiveMsg.ApiNumber);
+ }
+
+ /* Reuse the message */
+ ReplyMsg = &ReceiveMsg;
+
+ /* Make sure that the message is supported */
+ if (ReceiveMsg.ApiNumber < SbpMaxApiNumber)
+ {
+ /* Call the API */
+ if (!CsrServerSbApiDispatch[ReceiveMsg.ApiNumber](&ReceiveMsg))
+ {
+ /* It failed, so return nothing */
+ ReplyMsg = NULL;
+ }
+ }
+ else
+ {
+ /* We don't support this API Number */
+ ReplyMsg->ReturnValue = STATUS_NOT_IMPLEMENTED;
+ }
+ }
+}
+
+/*++
+ * @name CsrSbApiHandleConnectionRequest
+ *
+ * The CsrSbApiHandleConnectionRequest routine handles and accepts a new
+ * connection request to the SM API LPC Port.
+ *
+ * @param ApiMessage
+ * Pointer to the incoming CSR API Message which contains the
+ * connection request.
+ *
+ * @return STATUS_SUCCESS in case of success, or status code which caused
+ * the routine to error.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSbApiHandleConnectionRequest(IN PSB_API_MSG Message)
+{
+ NTSTATUS Status;
+ REMOTE_PORT_VIEW RemotePortView;
+ HANDLE hPort;
+
+ /* Set the Port View Structure Length */
+ RemotePortView.Length = sizeof(REMOTE_PORT_VIEW);
+
+ /* Accept the connection */
+ Status = NtAcceptConnectPort(&hPort,
+ NULL,
+ (PPORT_MESSAGE)Message,
+ TRUE,
+ NULL,
+ &RemotePortView);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: Sb Accept Connection failed %lx\n", Status);
+ return Status;
+ }
+
+ /* Complete the Connection */
+ Status = NtCompleteConnectPort(hPort);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: Sb Complete Connection failed %lx\n",Status);
+ }
+
+ /* Return status */
+ return Status;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*++
+ * @name CsrCallServerFromServer
+ * @implemented NT4
+ *
+ * The CsrCallServerFromServer routine calls a CSR API from within a server.
+ * It avoids using LPC messages since the request isn't coming from a client.
+ *
+ * @param ReceiveMsg
+ * Pointer to the CSR API Message to send to the server.
+ *
+ * @param ReplyMsg
+ * Pointer to the CSR API Message to receive from the server.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_ILLEGAL_FUNCTION
+ * if the opcode is invalid, or STATUS_ACCESS_VIOLATION if there
+ * was a problem executing the API.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrCallServerFromServer(PCSR_API_MESSAGE ReceiveMsg,
+ PCSR_API_MESSAGE ReplyMsg)
+{
+ ULONG ServerId;
+ PCSR_SERVER_DLL ServerDll;
+ ULONG ApiId;
+ ULONG Reply;
+ NTSTATUS Status;
+
+ /* Get the Server ID */
+ ServerId = CSR_SERVER_ID_FROM_OPCODE(ReceiveMsg->Opcode);
+
+ /* Make sure that the ID is within limits, and the Server DLL loaded */
+ if ((ServerId >= CSR_SERVER_DLL_MAX) ||
+ (!(ServerDll = CsrLoadedServerDll[ServerId])))
+ {
+ /* We are beyond the Maximum Server ID */
+ DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n", ServerId, ServerDll);
+ ReplyMsg->Status = (ULONG)STATUS_ILLEGAL_FUNCTION;
+ return STATUS_ILLEGAL_FUNCTION;
+ }
+ else
+ {
+ /* Get the API ID */
+ ApiId = CSR_API_ID_FROM_OPCODE(ReceiveMsg->Opcode);
+
+ /* Normalize it with our Base ID */
+ ApiId -= ServerDll->ApiBase;
+
+ /* Make sure that the ID is within limits, and the entry exists */
+ if ((ApiId >= ServerDll->HighestApiSupported) ||
+ ((ServerDll->ValidTable) && !(ServerDll->ValidTable[ApiId])))
+ {
+ /* We are beyond the Maximum API ID, or it doesn't exist */
+ DPRINT1("CSRSS: %lx (%s) is invalid ApiTableIndex for %Z or is an "
+ "invalid API to call from the server.\n",
+ ServerDll->ValidTable[ApiId],
+ ((ServerDll->NameTable) && (ServerDll->NameTable[ApiId])) ?
+ ServerDll->NameTable[ApiId] : "*** UNKNOWN ***", &ServerDll->Name);
+ DbgBreakPoint();
+ ReplyMsg->Status = (ULONG)STATUS_ILLEGAL_FUNCTION;
+ return STATUS_ILLEGAL_FUNCTION;
+ }
+ }
+
+ if (CsrDebug & 2)
+ {
+ DPRINT1("CSRSS: %s Api Request received from server process\n",
+ ServerDll->NameTable[ApiId]);
+ }
+
+ /* Validation complete, start SEH */
+ _SEH2_TRY
+ {
+ /* Call the API and get the result */
+ Status = ServerDll->DispatchTable[ApiId](ReceiveMsg, &Reply);
+
+ /* Return the result, no matter what it is */
+ ReplyMsg->Status = Status;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* If we got an exception, return access violation */
+ ReplyMsg->Status = STATUS_ACCESS_VIOLATION;
+ }
+ _SEH2_END;
+
+ /* Return success */
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrConnectToUser
+ * @implemented NT4
+ *
+ * The CsrConnectToUser connects to the User subsystem.
+ *
+ * @param None
+ *
+ * @return A pointer to the CSR Thread
+ *
+ * @remarks None.
+ *
+ *--*/
+PCSR_THREAD
+NTAPI
+CsrConnectToUser(VOID)
+{
+ NTSTATUS Status;
+ ANSI_STRING DllName;
+ UNICODE_STRING TempName;
+ HANDLE hUser32;
+ STRING StartupName;
+ PTEB Teb = NtCurrentTeb();
+ PCSR_THREAD CsrThread;
+ BOOLEAN Connected;
+
+ /* Check if we didn't already find it */
+ if (!CsrClientThreadSetup)
+ {
+ /* Get the DLL Handle for user32.dll */
+ RtlInitAnsiString(&DllName, "user32");
+ RtlAnsiStringToUnicodeString(&TempName, &DllName, TRUE);
+ Status = LdrGetDllHandle(NULL,
+ NULL,
+ &TempName,
+ &hUser32);
+ RtlFreeUnicodeString(&TempName);
+
+ /* If we got teh handle, get the Client Thread Startup Entrypoint */
+ if (NT_SUCCESS(Status))
+ {
+ RtlInitAnsiString(&StartupName,"ClientThreadSetup");
+ Status = LdrGetProcedureAddress(hUser32,
+ &StartupName,
+ 0,
+ (PVOID)&CsrClientThreadSetup);
+ }
+ }
+
+ /* Connect to user32 */
+ _SEH2_TRY
+ {
+ Connected = CsrClientThreadSetup();
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Connected = FALSE;
+ } _SEH2_END;
+
+ if (!Connected)
+ {
+ DPRINT1("CSRSS: CsrConnectToUser failed\n");
+ return NULL;
+ }
+
+ /* Save pointer to this thread in TEB */
+ CsrAcquireProcessLock();
+ CsrThread = CsrLocateThreadInProcess(NULL, &Teb->ClientId);
+ CsrReleaseProcessLock();
+ if (CsrThread) Teb->CsrClientThread = CsrThread;
+
+ /* Return it */
+ return CsrThread;
+}
+
+/*++
+ * @name CsrQueryApiPort
+ * @implemented NT4
+ *
+ * The CsrQueryApiPort routine returns a handle to the CSR API LPC port.
+ *
+ * @param None.
+ *
+ * @return A handle to the port.
+ *
+ * @remarks None.
+ *
+ *--*/
+HANDLE
+NTAPI
+CsrQueryApiPort(VOID)
+{
+ DPRINT("CSRSRV: %s called\n", __FUNCTION__);
+ return CsrApiPort;
+}
+
+/*++
+ * @name CsrCaptureArguments
+ * @implemented NT5.1
+ *
+ * The CsrCaptureArguments routine validates a CSR Capture Buffer and
+ * re-captures it into a server CSR Capture Buffer.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread performing the validation.
+ *
+ * @param ApiMessage
+ * Pointer to the CSR API Message containing the Capture Buffer
+ * that needs to be validated.
+ *
+ * @return TRUE if validation succeeded, FALSE otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrCaptureArguments(IN PCSR_THREAD CsrThread,
+ IN PCSR_API_MESSAGE ApiMessage)
+{
+ PCSR_CAPTURE_BUFFER LocalCaptureBuffer = NULL, RemoteCaptureBuffer = NULL;
+ ULONG LocalLength = 0, PointerCount = 0;
+ SIZE_T BufferDistance = 0;
+ ULONG_PTR **PointerOffsets = NULL, *CurrentPointer = NULL;
+
+ /* Use SEH to make sure this is valid */
+ _SEH2_TRY
+ {
+ /* Get the buffer we got from whoever called NTDLL */
+ LocalCaptureBuffer = ApiMessage->CsrCaptureData;
+ LocalLength = LocalCaptureBuffer->Size;
+
+ /* Now check if the buffer is inside our mapped section */
+ if (((ULONG_PTR)LocalCaptureBuffer < CsrThread->Process->ClientViewBase) ||
+ (((ULONG_PTR)LocalCaptureBuffer + LocalLength) >= CsrThread->Process->ClientViewBounds))
+ {
+ /* Return failure */
+ DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView\n");
+ ApiMessage->Status = STATUS_INVALID_PARAMETER;
+ _SEH2_YIELD(return FALSE);
+ }
+
+ /* Check if the Length is valid */
+ if (((LocalCaptureBuffer->PointerCount * 4 + sizeof(CSR_CAPTURE_BUFFER)) >
+ LocalLength) ||(LocalLength > MAXWORD))
+ {
+ /* Return failure */
+ DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", LocalCaptureBuffer);
+ DbgBreakPoint();
+ ApiMessage->Status = STATUS_INVALID_PARAMETER;
+ _SEH2_YIELD(return FALSE);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Return failure */
+ ApiMessage->Status = STATUS_INVALID_PARAMETER;
+ _SEH2_YIELD(return FALSE);
+ } _SEH2_END;
+
+ /* We validated the incoming buffer, now allocate the remote one */
+ RemoteCaptureBuffer = RtlAllocateHeap(CsrHeap, 0, LocalLength);
+ if (!RemoteCaptureBuffer)
+ {
+ /* We're out of memory */
+ ApiMessage->Status = STATUS_NO_MEMORY;
+ return FALSE;
+ }
+
+ /* Copy the client's buffer */
+ RtlMoveMemory(RemoteCaptureBuffer, LocalCaptureBuffer, LocalLength);
+
+ /* Copy the length */
+ RemoteCaptureBuffer->Size = LocalLength;
+
+ /* Calculate the difference between our buffer and the client's */
+ BufferDistance = (ULONG_PTR)RemoteCaptureBuffer - (ULONG_PTR)LocalCaptureBuffer;
+
+ /* Save the pointer count and offset pointer */
+ PointerCount = RemoteCaptureBuffer->PointerCount;
+ PointerOffsets = (ULONG_PTR**)(RemoteCaptureBuffer + 1);
+
+ /* Start the loop */
+ while (PointerCount)
+ {
+ /* Get the current pointer */
+ if ((CurrentPointer = *PointerOffsets++))
+ {
+ /* Add it to the CSR Message structure */
+ CurrentPointer += (ULONG_PTR)ApiMessage;
+
+ /* Validate the bounds of the current pointer */
+ if ((*CurrentPointer >= CsrThread->Process->ClientViewBase) &&
+ (*CurrentPointer < CsrThread->Process->ClientViewBounds))
+ {
+ /* Modify the pointer to take into account its new position */
+ *CurrentPointer += BufferDistance;
+ }
+ else
+ {
+ /* Invalid pointer, fail */
+ DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n");
+ DbgBreakPoint();
+ ApiMessage->Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ /* Move to the next Pointer */
+ PointerCount--;
+ }
+
+ /* Check if we got success */
+ if (ApiMessage->Status != STATUS_SUCCESS)
+ {
+ /* Failure. Free the buffer and return*/
+ RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer);
+ return FALSE;
+ }
+ else
+ {
+ /* Success, save the previous buffer */
+ RemoteCaptureBuffer->PreviousCaptureBuffer = LocalCaptureBuffer;
+ ApiMessage->CsrCaptureData = RemoteCaptureBuffer;
+ }
+
+ /* Success */
+ return TRUE;
+}
+
+/*++
+ * @name CsrReleaseCapturedArguments
+ * @implemented NT5.1
+ *
+ * The CsrReleaseCapturedArguments routine releases a Capture Buffer
+ * that was previously captured with CsrCaptureArguments.
+ *
+ * @param ApiMessage
+ * Pointer to the CSR API Message containing the Capture Buffer
+ * that needs to be released.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage)
+{
+ PCSR_CAPTURE_BUFFER RemoteCaptureBuffer, LocalCaptureBuffer;
+ SIZE_T BufferDistance;
+ ULONG PointerCount;
+ ULONG_PTR **PointerOffsets, *CurrentPointer;
+
+ /* Get the capture buffers */
+ RemoteCaptureBuffer = ApiMessage->CsrCaptureData;
+ LocalCaptureBuffer = RemoteCaptureBuffer->PreviousCaptureBuffer;
+
+ /* Free the previous one */
+ RemoteCaptureBuffer->PreviousCaptureBuffer = NULL;
+
+ /* Find out the difference between the two buffers */
+ BufferDistance = (ULONG_PTR)LocalCaptureBuffer - (ULONG_PTR)RemoteCaptureBuffer;
+
+ /* Save the pointer count and offset pointer */
+ PointerCount = RemoteCaptureBuffer->PointerCount;
+ PointerOffsets = (ULONG_PTR**)(RemoteCaptureBuffer + 1);
+
+ /* Start the loop */
+ while (PointerCount)
+ {
+ /* Get the current pointer */
+ CurrentPointer = *PointerOffsets++;
+ if (CurrentPointer)
+ {
+ /* Add it to the CSR Message structure */
+ CurrentPointer += (ULONG_PTR)ApiMessage;
+
+ /* Modify the pointer to take into account its new position */
+ *CurrentPointer += BufferDistance;
+ }
+
+ /* Move to the next Pointer */
+ PointerCount--;
+ }
+
+ /* Copy the data back */
+ RtlMoveMemory(LocalCaptureBuffer, RemoteCaptureBuffer, RemoteCaptureBuffer->Size);
+
+ /* Free our allocated buffer */
+ RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer);
+}
+
+/*++
+ * @name CsrValidateMessageBuffer
+ * @implemented NT5.1
+ *
+ * The CsrValidateMessageBuffer routine validates a captured message buffer
+ * present in the CSR Api Message
+ *
+ * @param ApiMessage
+ * Pointer to the CSR API Message containing the CSR Capture Buffer.
+ *
+ * @param Buffer
+ * Pointer to the message buffer to validate.
+ *
+ * @param ArgumentSize
+ * Size of the message to check.
+ *
+ * @param ArgumentCount
+ * Number of messages to check.
+ *
+ * @return TRUE if validation suceeded, FALSE otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage,
+ IN PVOID *Buffer,
+ IN ULONG ArgumentSize,
+ IN ULONG ArgumentCount)
+{
+ PCSR_CAPTURE_BUFFER CaptureBuffer = ApiMessage->CsrCaptureData;
+ SIZE_T BufferDistance;
+ ULONG PointerCount, i;
+ ULONG_PTR **PointerOffsets, *CurrentPointer;
+
+ /* Make sure there are some arguments */
+ if (!ArgumentCount) return FALSE;
+
+ /* Check if didn't get a buffer and there aren't any arguments to check */
+ if (!(*Buffer) && (!(ArgumentCount * ArgumentSize))) return TRUE;
+
+ /* Check if we have no capture buffer */
+ if (!CaptureBuffer)
+ {
+ /* In this case, check only the Process ID */
+ if (NtCurrentTeb()->ClientId.UniqueProcess ==
+ ApiMessage->Header.ClientId.UniqueProcess)
+ {
+ /* There is a match, validation succeeded */
+ return TRUE;
+ }
+ }
+ else
+ {
+ /* Make sure that there is still space left in the buffer */
+ if ((CaptureBuffer->Size - (ULONG_PTR)*Buffer + (ULONG_PTR)CaptureBuffer) <
+ (ArgumentCount * ArgumentSize))
+ {
+ /* Find out the difference between the two buffers */
+ BufferDistance = (ULONG_PTR)Buffer - (ULONG_PTR)ApiMessage;
+
+ /* Save the pointer count */
+ PointerCount = CaptureBuffer->PointerCount;
+ PointerOffsets = (ULONG_PTR**)(CaptureBuffer + 1);
+
+ /* Start the loop */
+ for (i = 0; i < PointerCount; i++)
+ {
+ /* Get the current pointer */
+ CurrentPointer = *PointerOffsets++;
+
+ /* Check if its' equal to the difference */
+ if (*CurrentPointer == BufferDistance) return TRUE;
+ }
+ }
+ }
+
+ /* Failure */
+ DbgPrint("CSRSRV: Bad message buffer %p\n", ApiMessage);
+ DbgBreakPoint();
+ return FALSE;
+}
+
+/*++
+ * @name CsrValidateMessageString
+ * @implemented NT5.1
+ *
+ * The CsrValidateMessageString validates a captured Wide-Character String
+ * present in a CSR API Message.
+ *
+ * @param ApiMessage
+ * Pointer to the CSR API Message containing the CSR Capture Buffer.
+ *
+ * @param MessageString
+ * Pointer to the buffer containing the string to validate.
+ *
+ * @return TRUE if validation suceeded, FALSE otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage,
+ IN LPWSTR *MessageString)
+{
+ DPRINT1("CSRSRV: %s called\n", __FUNCTION__);
+ return FALSE;
+}
+
+/* EOF */
--- /dev/null
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "ReactOS CSR Core Server\0"
+#define REACTOS_STR_INTERNAL_NAME "csrsrv\0"
+#define REACTOS_STR_ORIGINAL_FILENAME "csrsrv.dll\0"
+#include <reactos/version.rc>
--- /dev/null
+@ stdcall CsrAddStaticServerThread(ptr ptr long)
+@ stdcall CsrCallServerFromServer(ptr ptr)
+@ stdcall CsrConnectToUser()
+@ stdcall CsrCreateProcess(ptr ptr ptr ptr long ptr)
+@ stdcall CsrCreateRemoteThread(ptr ptr)
+@ stdcall CsrCreateThread(ptr ptr ptr long)
+@ stdcall CsrCreateWait(ptr ptr ptr ptr ptr ptr)
+@ stdcall CsrDebugProcess(ptr)
+@ stdcall CsrDebugProcessStop(ptr)
+@ stdcall CsrDereferenceProcess(ptr)
+@ stdcall CsrDereferenceThread(ptr)
+@ stdcall CsrDereferenceWait(ptr)
+@ stdcall CsrDestroyProcess(ptr long)
+@ stdcall CsrDestroyThread(ptr)
+@ stdcall CsrExecServerThread(ptr long)
+@ stdcall CsrGetProcessLuid(ptr ptr)
+@ stdcall CsrImpersonateClient(ptr)
+@ stdcall CsrLockProcessByClientId(ptr ptr)
+@ stdcall CsrLockThreadByClientId(ptr ptr)
+@ stdcall CsrMoveSatisfiedWait(ptr ptr)
+@ stdcall CsrNotifyWait(ptr long ptr ptr)
+@ stdcall CsrPopulateDosDevices()
+@ stdcall CsrQueryApiPort()
+@ stdcall CsrReferenceThread(ptr)
+@ stdcall CsrRevertToSelf()
+@ stdcall CsrServerInitialization(long ptr)
+@ stdcall CsrSetBackgroundPriority(ptr)
+@ stdcall CsrSetCallingSpooler(long)
+@ stdcall CsrSetForegroundPriority(ptr)
+@ stdcall CsrShutdownProcesses(ptr long)
+@ stdcall CsrUnhandledExceptionFilter(ptr)
+@ stdcall CsrUnlockProcess(ptr)
+@ stdcall CsrUnlockThread(ptr)
+@ stdcall CsrValidateMessageBuffer(ptr ptr long long)
+@ stdcall CsrValidateMessageString(ptr ptr)
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CSR Sub System
+ * FILE: subsys/csr/csrsrv/init.c
+ * PURPOSE: CSR Server DLL Initialization
+ * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "srv.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* DATA **********************************************************************/
+
+HANDLE CsrObjectDirectory;
+ULONG SessionId;
+BOOLEAN CsrProfileControl;
+UNICODE_STRING CsrDirectoryName;
+HANDLE CsrHeap;
+HANDLE BNOLinksDirectory;
+HANDLE SessionObjectDirectory;
+HANDLE DosDevicesDirectory;
+HANDLE CsrInitializationEvent;
+SYSTEM_BASIC_INFORMATION CsrNtSysInfo;
+ULONG CsrDebug;
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+/*++
+ * @name CsrParseServerCommandLine
+ *
+ * The CsrParseServerCommandLine routine parses the CSRSS command-line in the
+ * registry and performs operations for each entry found.
+ *
+ * @param ArgumentCount
+ * Number of arguments on the command line.
+ *
+ * @param Arguments
+ * Array of arguments.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+FASTCALL
+CsrParseServerCommandLine(IN ULONG ArgumentCount,
+ IN PCHAR Arguments[])
+{
+ NTSTATUS Status;
+ PCHAR ParameterName = NULL, ParameterValue = NULL, EntryPoint, ServerString;
+ ULONG i, DllIndex;
+ ANSI_STRING AnsiString;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+
+ /* Set the Defaults */
+ CsrTotalPerProcessDataLength = 0;
+ CsrObjectDirectory = 0;
+ CsrMaxApiRequestThreads = 16;
+
+ /* Save our Session ID, and create a Directory for it */
+ SessionId = NtCurrentPeb()->SessionId;
+ Status = CsrCreateSessionObjectDirectory(SessionId);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: CsrCreateSessionObjectDirectory failed (%lx)\n",
+ Status);
+
+ /* It's not fatal if the session ID isn't zero */
+ if (SessionId) return Status;
+ ASSERT(NT_SUCCESS(Status));
+ }
+
+ /* Loop through every argument */
+ for (i = 1; i < ArgumentCount; i++)
+ {
+ /* Split Name and Value */
+ ParameterName = Arguments[i];
+ ParameterValue = NULL;
+ ParameterValue = strchr(ParameterName, '=');
+ if (ParameterValue) *ParameterValue++ = ANSI_NULL;
+ DPRINT1("Name=%s, Value=%s\n", ParameterName, ParameterValue);
+
+ /* Check for Object Directory */
+ if (!_stricmp(ParameterName, "ObjectDirectory"))
+ {
+ /* Check if a session ID is specified */
+ if (SessionId)
+ {
+ DPRINT1("Sessions not yet implemented\n");
+ ASSERT(SessionId);
+ }
+
+ /* Initialize the directory name */
+ RtlInitAnsiString(&AnsiString, ParameterValue);
+ Status = RtlAnsiStringToUnicodeString(&CsrDirectoryName,
+ &AnsiString,
+ TRUE);
+ ASSERT(NT_SUCCESS(Status) || SessionId != 0);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Create it */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &CsrDirectoryName,
+ OBJ_OPENIF | OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
+ NULL,
+ NULL);
+ Status = NtCreateDirectoryObject(&CsrObjectDirectory,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Secure it */
+ Status = CsrSetDirectorySecurity(CsrObjectDirectory);
+ if (!NT_SUCCESS(Status)) return Status;
+ }
+ else if (!_stricmp(ParameterName, "SubSystemType"))
+ {
+ /* Ignored */
+ }
+ else if (!_stricmp(ParameterName, "MaxRequestThreads"))
+ {
+ Status = RtlCharToInteger(ParameterValue,
+ 0,
+ &CsrMaxApiRequestThreads);
+ }
+ else if (!_stricmp(ParameterName, "RequestThreads"))
+ {
+ /* Ignored */
+ Status = STATUS_SUCCESS;
+ }
+ else if (!_stricmp(ParameterName, "ProfileControl"))
+ {
+ /* Ignored */
+ }
+ else if (!_stricmp(ParameterName, "SharedSection"))
+ {
+ /* Craete the Section */
+ Status = CsrSrvCreateSharedSection(ParameterValue);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: *** Invalid syntax for %s=%s (Status == %X)\n",
+ ParameterName, ParameterValue, Status);
+ return Status;
+ }
+
+ /* Load us */
+ Status = CsrLoadServerDll("CSRSS", NULL, CSR_SRV_SERVER);
+ }
+ else if (!_stricmp(ParameterName, "ServerDLL"))
+ {
+ /* Loop the command line */
+ EntryPoint = NULL;
+ Status = STATUS_INVALID_PARAMETER;
+ ServerString = ParameterValue;
+ while (*ServerString)
+ {
+ /* Check for the Entry Point */
+ if ((*ServerString == ':') && (!EntryPoint))
+ {
+ /* Found it. Add a nullchar and save it */
+ *ServerString++ = ANSI_NULL;
+ EntryPoint = ServerString;
+ }
+
+ /* Check for the Dll Index */
+ if (*ServerString++ == ',') break;
+ }
+
+ /* Did we find something to load? */
+ if (!*ServerString)
+ {
+ DPRINT1("CSRSS: *** Invalid syntax for ServerDll=%s (Status == %X)\n",
+ ParameterValue, Status);
+ return Status;
+ }
+
+ /* Convert it to a ULONG */
+ Status = RtlCharToInteger(ServerString, 10, &DllIndex);
+
+ /* Add a null char if it was valid */
+ if (NT_SUCCESS(Status)) ServerString[-1] = ANSI_NULL;
+
+ /* Load it */
+ if (CsrDebug & 1) DPRINT1("CSRSS: Loading ServerDll=%s:%s\n", ParameterValue, EntryPoint);
+ Status = CsrLoadServerDll(ParameterValue, EntryPoint, DllIndex);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: *** Failed loading ServerDll=%s (Status == 0x%x)\n",
+ ParameterValue, Status);
+ return Status;
+ }
+ }
+ else if (!_stricmp(ParameterName, "Windows"))
+ {
+ /* Ignored */
+ }
+ else
+ {
+ /* Invalid parameter on the command line */
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ /* Return status */
+ return Status;
+}
+
+/*++
+ * @name CsrCreateLocalSystemSD
+ *
+ * The CsrCreateLocalSystemSD routine creates a Security Descriptor for
+ * the local account with PORT_ALL_ACCESS.
+ *
+ * @param LocalSystemSd
+ * Pointer to a pointer to the security descriptor to create.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrCreateLocalSystemSD(OUT PSECURITY_DESCRIPTOR *LocalSystemSd)
+{
+ SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
+ PSID SystemSid;
+ ULONG Length;
+ PSECURITY_DESCRIPTOR SystemSd;
+ PACL Dacl;
+ NTSTATUS Status;
+
+ /* Initialize the System SID */
+ RtlAllocateAndInitializeSid(&NtSidAuthority, 1,
+ SECURITY_LOCAL_SYSTEM_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &SystemSid);
+
+ /* Get the length of the SID */
+ Length = RtlLengthSid(SystemSid) + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
+
+ /* Allocate a buffer for the Security Descriptor, with SID and DACL */
+ SystemSd = RtlAllocateHeap(CsrHeap, 0, SECURITY_DESCRIPTOR_MIN_LENGTH + Length);
+
+ /* Set the pointer to the DACL */
+ Dacl = (PACL)((ULONG_PTR)SystemSd + SECURITY_DESCRIPTOR_MIN_LENGTH);
+
+ /* Now create the SD itself */
+ Status = RtlCreateSecurityDescriptor(SystemSd, SECURITY_DESCRIPTOR_REVISION);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ RtlFreeHeap(CsrHeap, 0, SystemSd);
+ return Status;
+ }
+
+ /* Create the DACL for it*/
+ RtlCreateAcl(Dacl, Length, ACL_REVISION2);
+
+ /* Create the ACE */
+ Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, PORT_ALL_ACCESS, SystemSid);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ RtlFreeHeap(CsrHeap, 0, SystemSd);
+ return Status;
+ }
+
+ /* Clear the DACL in the SD */
+ Status = RtlSetDaclSecurityDescriptor(SystemSd, TRUE, Dacl, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ RtlFreeHeap(CsrHeap, 0, SystemSd);
+ return Status;
+ }
+
+ /* Free the SID and return*/
+ RtlFreeSid(SystemSid);
+ *LocalSystemSd = SystemSd;
+ return Status;
+}
+
+/*++
+ * @name GetDosDevicesProtection
+ *
+ * The GetDosDevicesProtection creates a security descriptor for the DOS Devices
+ * Object Directory.
+ *
+ * @param DosDevicesSd
+ * Pointer to the Security Descriptor to return.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks Depending on the DOS Devices Protection Mode (set in the registry),
+ * regular users may or may not have full access to the directory.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+GetDosDevicesProtection(OUT PSECURITY_DESCRIPTOR DosDevicesSd)
+{
+ SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
+ SID_IDENTIFIER_AUTHORITY CreatorAuthority = {SECURITY_CREATOR_SID_AUTHORITY};
+ SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
+ PSID WorldSid, CreatorSid, AdminSid, SystemSid;
+ UCHAR KeyValueBuffer[0x40];
+ PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
+ UNICODE_STRING KeyName;
+ ULONG ProtectionMode = 0;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PACL Dacl;
+ PACCESS_ALLOWED_ACE Ace;
+ HANDLE hKey;
+ NTSTATUS Status;
+ ULONG ResultLength, SidLength, AclLength;
+
+ /* Create the SD */
+ Status = RtlCreateSecurityDescriptor(DosDevicesSd, SECURITY_DESCRIPTOR_REVISION);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Initialize the System SID */
+ Status = RtlAllocateAndInitializeSid(&NtSidAuthority, 1,
+ SECURITY_LOCAL_SYSTEM_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &SystemSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Initialize the World SID */
+ Status = RtlAllocateAndInitializeSid(&WorldAuthority, 1,
+ SECURITY_WORLD_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &WorldSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Initialize the Admin SID */
+ Status = RtlAllocateAndInitializeSid(&NtSidAuthority, 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &AdminSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Initialize the Creator SID */
+ Status = RtlAllocateAndInitializeSid(&CreatorAuthority, 1,
+ SECURITY_CREATOR_OWNER_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &CreatorSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Open the Session Manager Key */
+ RtlInitUnicodeString(&KeyName, SM_REG_KEY);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
+ if (NT_SUCCESS(Status))
+ {
+ /* Read the key value */
+ RtlInitUnicodeString(&KeyName, L"ProtectionMode");
+ Status = NtQueryValueKey(hKey,
+ &KeyName,
+ KeyValuePartialInformation,
+ KeyValueBuffer,
+ sizeof(KeyValueBuffer),
+ &ResultLength);
+
+ /* Make sure it's what we expect it to be */
+ KeyValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
+ if ((NT_SUCCESS(Status)) && (KeyValuePartialInfo->Type == REG_DWORD) &&
+ (*(PULONG)KeyValuePartialInfo->Data))
+ {
+ /* Save the Protection Mode */
+ ProtectionMode = *(PULONG)KeyValuePartialInfo->Data;
+ }
+
+ /* Close the handle */
+ NtClose(hKey);
+ }
+
+ /* Check the Protection Mode */
+ if (ProtectionMode & 3)
+ {
+ /* Calculate SID Lengths */
+ SidLength = RtlLengthSid(CreatorSid) + RtlLengthSid(SystemSid) +
+ RtlLengthSid(AdminSid);
+ AclLength = sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) + SidLength;
+
+ /* Allocate memory for the DACL */
+ Dacl = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, AclLength);
+ ASSERT(Dacl != NULL);
+
+ /* Build the ACL and add 3 ACEs */
+ Status = RtlCreateAcl(Dacl, AclLength, ACL_REVISION2);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, SystemSid);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, AdminSid);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, CreatorSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Edit the ACEs to make them inheritable */
+ Status = RtlGetAce(Dacl, 0, (PVOID*)&Ace);
+ ASSERT(NT_SUCCESS(Status));
+ Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
+ Status = RtlGetAce(Dacl, 1, (PVOID*)&Ace);
+ ASSERT(NT_SUCCESS(Status));
+ Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
+ Status = RtlGetAce(Dacl, 2, (PVOID*)&Ace);
+ ASSERT(NT_SUCCESS(Status));
+ Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
+
+ /* Set this DACL with the SD */
+ Status = RtlSetDaclSecurityDescriptor(DosDevicesSd, TRUE, Dacl, FALSE);
+ ASSERT(NT_SUCCESS(Status));
+ goto Quickie;
+ }
+ else
+ {
+ /* Calculate SID Lengths */
+ SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(SystemSid);
+ AclLength = sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) + SidLength;
+
+ /* Allocate memory for the DACL */
+ Dacl = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, AclLength);
+ ASSERT(Dacl != NULL);
+
+ /* Build the ACL and add 3 ACEs */
+ Status = RtlCreateAcl(Dacl, AclLength, ACL_REVISION2);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE, WorldSid);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, SystemSid);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, WorldSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Edit the last ACE to make it inheritable */
+ Status = RtlGetAce(Dacl, 2, (PVOID*)&Ace);
+ ASSERT(NT_SUCCESS(Status));
+ Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
+
+ /* Set this DACL with the SD */
+ Status = RtlSetDaclSecurityDescriptor(DosDevicesSd, TRUE, Dacl, FALSE);
+ ASSERT(NT_SUCCESS(Status));
+ goto Quickie;
+ }
+
+/* FIXME: failure cases! Fail: */
+ /* Free the memory */
+ RtlFreeHeap(CsrHeap, 0, Dacl);
+
+/* FIXME: semi-failure cases! Quickie: */
+Quickie:
+ /* Free the SIDs */
+ RtlFreeSid(SystemSid);
+ RtlFreeSid(WorldSid);
+ RtlFreeSid(AdminSid);
+ RtlFreeSid(CreatorSid);
+
+ /* Return */
+ return Status;
+}
+
+/*++
+ * @name FreeDosDevicesProtection
+ *
+ * The FreeDosDevicesProtection frees the security descriptor that was created
+ * by GetDosDevicesProtection
+ *
+ * @param DosDevicesSd
+ * Pointer to the security descriptor to free.
+
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+FreeDosDevicesProtection(IN PSECURITY_DESCRIPTOR DosDevicesSd)
+{
+ PACL Dacl;
+ BOOLEAN Present, Default;
+ NTSTATUS Status;
+
+ /* Get the DACL corresponding to this SD */
+ Status = RtlGetDaclSecurityDescriptor(DosDevicesSd, &Present, &Dacl, &Default);
+ ASSERT(NT_SUCCESS(Status));
+ ASSERT(Present);
+ ASSERT(Dacl != NULL);
+
+ /* Free it */
+ if ((NT_SUCCESS(Status)) && (Dacl)) RtlFreeHeap(CsrHeap, 0, Dacl);
+}
+
+/*++
+ * @name CsrCreateSessionObjectDirectory
+ *
+ * The CsrCreateSessionObjectDirectory routine creates the BaseNamedObjects,
+ * Session and Dos Devices directories for the specified session.
+ *
+ * @param Session
+ * Session ID for which to create the directories.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrCreateSessionObjectDirectory(IN ULONG Session)
+{
+ WCHAR SessionBuffer[512], BnoBuffer[512];
+ UNICODE_STRING SessionString, BnoString;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE BnoHandle;
+ SECURITY_DESCRIPTOR DosDevicesSd;
+ NTSTATUS Status;
+
+ /* Generate the Session BNOLINKS Directory name */
+ swprintf(SessionBuffer, L"%ws\\BNOLINKS", SESSION_ROOT);
+ RtlInitUnicodeString(&SessionString, SessionBuffer);
+
+ /* Create it */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &SessionString,
+ OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtCreateDirectoryObject(&BNOLinksDirectory,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: NtCreateDirectoryObject failed in "
+ "CsrCreateSessionObjectDirectory - status = %lx\n", Status);
+ return Status;
+ }
+
+ /* Now add the Session ID */
+ swprintf(SessionBuffer, L"%ld", Session);
+ RtlInitUnicodeString(&SessionString, SessionBuffer);
+
+ /* Check if this is the first Session */
+ if (Session)
+ {
+ /* Not the first, so the name will be slighly more complex */
+ swprintf(BnoBuffer, L"%ws\\%ld\\BaseNamedObjects", SESSION_ROOT, Session);
+ RtlInitUnicodeString(&BnoString, BnoBuffer);
+ }
+ else
+ {
+ /* Use the direct name */
+ RtlInitUnicodeString(&BnoString, L"\\BaseNamedObjects");
+ }
+
+ /* Create the symlink */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &SessionString,
+ OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
+ BNOLinksDirectory,
+ NULL);
+ Status = NtCreateSymbolicLinkObject(&BnoHandle,
+ SYMBOLIC_LINK_ALL_ACCESS,
+ &ObjectAttributes,
+ &BnoString);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: NtCreateSymbolicLinkObject failed in "
+ "CsrCreateSessionObjectDirectory - status = %lx\n", Status);
+ return Status;
+ }
+
+ /* Create the \DosDevices Security Descriptor */
+ Status = GetDosDevicesProtection(&DosDevicesSd);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Now create a directory for this session */
+ swprintf(SessionBuffer, L"%ws\\%ld", SESSION_ROOT, Session);
+ RtlInitUnicodeString(&SessionString, SessionBuffer);
+
+ /* Create the directory */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &SessionString,
+ OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
+ 0,
+ &DosDevicesSd);
+ Status = NtCreateDirectoryObject(&SessionObjectDirectory,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: NtCreateDirectoryObject failed in "
+ "CsrCreateSessionObjectDirectory - status = %lx\n", Status);
+ FreeDosDevicesProtection(&DosDevicesSd);
+ return Status;
+ }
+
+ /* Next, create a directory for this session's DOS Devices */
+ RtlInitUnicodeString(&SessionString, L"DosDevices");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &SessionString,
+ OBJ_CASE_INSENSITIVE,
+ SessionObjectDirectory,
+ &DosDevicesSd);
+ Status = NtCreateDirectoryObject(&DosDevicesDirectory,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: NtCreateDirectoryObject failed in "
+ "CsrCreateSessionObjectDirectory - status = %lx\n", Status);
+ }
+
+ /* Release the Security Descriptor */
+ FreeDosDevicesProtection(&DosDevicesSd);
+
+ /* Return */
+ return Status;
+}
+
+/*++
+ * @name CsrSetProcessSecurity
+ *
+ * The CsrSetProcessSecurity routine protects access to the CSRSS process
+ * from unauthorized tampering.
+ *
+ * @param None.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSetProcessSecurity(VOID)
+{
+ NTSTATUS Status;
+ HANDLE hToken, hProcess = NtCurrentProcess();
+ ULONG ReturnLength, Length;
+ PTOKEN_USER TokenInfo = NULL;
+ PSECURITY_DESCRIPTOR ProcSd = NULL;
+ PACL Dacl;
+ PSID UserSid;
+
+ /* Open our token */
+ Status = NtOpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
+ if (!NT_SUCCESS(Status)) goto Quickie;
+
+ /* Get the Token User Length */
+ NtQueryInformationToken(hToken, TokenUser, NULL, 0, &Length);
+
+ /* Allocate space for it */
+ TokenInfo = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, Length);
+ if (!TokenInfo)
+ {
+ Status = STATUS_NO_MEMORY;
+ goto Quickie;
+ }
+
+ /* Now query the data */
+ Status = NtQueryInformationToken(hToken, TokenUser, TokenInfo, Length, &Length);
+ NtClose(hToken);
+ if (!NT_SUCCESS(Status)) goto Quickie;
+
+ /* Now check the SID Length */
+ UserSid = TokenInfo->User.Sid;
+ ReturnLength = RtlLengthSid(UserSid) + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
+
+ /* Allocate a buffer for the Security Descriptor, with SID and DACL */
+ ProcSd = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, SECURITY_DESCRIPTOR_MIN_LENGTH + Length);
+ if (!ProcSd)
+ {
+ Status = STATUS_NO_MEMORY;
+ goto Quickie;
+ }
+
+ /* Set the pointer to the DACL */
+ Dacl = (PACL)((ULONG_PTR)ProcSd + SECURITY_DESCRIPTOR_MIN_LENGTH);
+
+ /* Now create the SD itself */
+ Status = RtlCreateSecurityDescriptor(ProcSd, SECURITY_DESCRIPTOR_REVISION);
+ if (!NT_SUCCESS(Status)) goto Quickie;
+
+ /* Create the DACL for it*/
+ RtlCreateAcl(Dacl, Length, ACL_REVISION2);
+
+ /* Create the ACE */
+ Status = RtlAddAccessAllowedAce(Dacl,
+ ACL_REVISION,
+ PROCESS_VM_READ | PROCESS_VM_WRITE |
+ PROCESS_VM_OPERATION | PROCESS_DUP_HANDLE |
+ PROCESS_TERMINATE | PROCESS_SUSPEND_RESUME |
+ PROCESS_QUERY_INFORMATION | READ_CONTROL,
+ UserSid);
+ if (!NT_SUCCESS(Status)) goto Quickie;
+
+ /* Clear the DACL in the SD */
+ Status = RtlSetDaclSecurityDescriptor(ProcSd, TRUE, Dacl, FALSE);
+ if (!NT_SUCCESS(Status)) goto Quickie;
+
+ /* Write the SD into the Process */
+ Status = NtSetSecurityObject(hProcess, DACL_SECURITY_INFORMATION, ProcSd);
+
+ /* Free the memory and return */
+Quickie:
+ if (ProcSd) RtlFreeHeap(CsrHeap, 0, ProcSd);
+ RtlFreeHeap(CsrHeap, 0, TokenInfo);
+ return Status;
+}
+
+/*++
+ * @name CsrSetDirectorySecurity
+ *
+ * The CsrSetDirectorySecurity routine sets the security descriptor for the
+ * specified Object Directory.
+ *
+ * @param ObjectDirectory
+ * Handle fo the Object Directory to protect.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSetDirectorySecurity(IN HANDLE ObjectDirectory)
+{
+ /* FIXME: Implement */
+ return STATUS_SUCCESS;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*++
+ * @name CsrServerInitialization
+ * @implemented NT4
+ *
+ * The CsrServerInitialization routine is the native (not Server) entrypoint
+ * of this Server DLL. It serves as the entrypoint for csrss.
+ *
+ * @param ArgumentCount
+ * Number of arguments on the command line.
+ *
+ * @param Arguments
+ * Array of arguments from the command line.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrServerInitialization(IN ULONG ArgumentCount,
+ IN PCHAR Arguments[])
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG i = 0;
+ PVOID ProcessData;
+ PCSR_SERVER_DLL ServerDll;
+ DPRINT("CSRSRV: %s called\n", __FUNCTION__);
+
+ /* Create the Init Event */
+ Status = NtCreateEvent(&CsrInitializationEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: NtCreateEvent failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Cache System Basic Information so we don't always request it */
+ Status = NtQuerySystemInformation(SystemBasicInformation,
+ &CsrNtSysInfo,
+ sizeof(SYSTEM_BASIC_INFORMATION),
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: NtQuerySystemInformation failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Save our Heap */
+ CsrHeap = RtlGetProcessHeap();
+
+ /* Set our Security Descriptor to protect the process */
+ Status = CsrSetProcessSecurity();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: CsrSetProcessSecurity failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Set up Session Support */
+ Status = CsrInitializeNtSessionList();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: CsrInitializeSessions failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Set up Process Support */
+ Status = CsrInitializeProcessStructure();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: CsrInitializeProcessStructure failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Parse the command line */
+ Status = CsrParseServerCommandLine(ArgumentCount, Arguments);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: CsrParseServerCommandLine failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* All Server DLLs are now loaded, allocate a heap for the Root Process */
+ ProcessData = RtlAllocateHeap(CsrHeap,
+ HEAP_ZERO_MEMORY,
+ CsrTotalPerProcessDataLength);
+ if (!ProcessData)
+ {
+ DPRINT1("CSRSRV:%s: RtlAllocateHeap failed (Status=%08lx)\n",
+ __FUNCTION__, STATUS_NO_MEMORY);
+ return STATUS_NO_MEMORY;
+ }
+
+ /*
+ * Our Root Process was never officially initalized, so write the data
+ * for each Server DLL manually.
+ */
+ for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+ {
+ /* Get the current Server */
+ ServerDll = CsrLoadedServerDll[i];
+
+ /* Is it loaded, and does it have per process data? */
+ if ((ServerDll) && (ServerDll->SizeOfProcessData))
+ {
+ /* It does, give it part of our allocated heap */
+ CsrRootProcess->ServerData[i] = ProcessData;
+
+ /* Move to the next heap position */
+ ProcessData = (PVOID)((ULONG_PTR)ProcessData +
+ ServerDll->SizeOfProcessData);
+ }
+ else
+ {
+ /* Nothing for this Server DLL */
+ CsrRootProcess->ServerData[i] = NULL;
+ }
+ }
+
+ /* Now initialize the Root Process manually as well */
+ for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+ {
+ /* Get the current Server */
+ ServerDll = CsrLoadedServerDll[i];
+
+ /* Is it loaded, and does it a callback for new processes? */
+ if ((ServerDll) && (ServerDll->NewProcessCallback))
+ {
+ /* Call the callback */
+ ServerDll->NewProcessCallback(NULL, CsrRootProcess);
+ }
+ }
+
+ /* Now initialize our API Port */
+ Status = CsrApiPortInitialize();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: CsrApiPortInitialize failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Initialize the API Port for SM communication */
+ Status = CsrSbApiPortInitialize();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: CsrSbApiPortInitialize failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* We're all set! Connect to SM! */
+ Status = SmConnectToSm(&CsrSbApiPortName,
+ CsrSbApiPort,
+ IMAGE_SUBSYSTEM_WINDOWS_GUI,
+ &CsrSmApiPort);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: SmConnectToSm failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Finito! Signal the event */
+ Status = NtSetEvent(CsrInitializationEvent, NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: NtSetEvent failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Close the event handle now */
+ NtClose(CsrInitializationEvent);
+
+ /* Have us handle Hard Errors */
+ Status = NtSetDefaultHardErrorPort(CsrApiPort);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: NtSetDefaultHardErrorPort failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Return status */
+ return Status;
+}
+
+/*++
+ * @name CsrPopulateDosDevices
+ * @unimplemented NT5.1
+ *
+ * The CsrPopulateDosDevices routine uses the DOS Device Map from the Kernel
+ * to populate the Dos Devices Object Directory for the session.
+ *
+ * @param None.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrPopulateDosDevices(VOID)
+{
+ DPRINT1("Deprecated API\n");
+ return;
+}
+
+BOOL
+NTAPI
+DllMain(IN HANDLE hDll,
+ IN DWORD dwReason,
+ IN LPVOID lpReserved)
+{
+ /* We don't do much */
+ UNREFERENCED_PARAMETER(hDll);
+ UNREFERENCED_PARAMETER(dwReason);
+ UNREFERENCED_PARAMETER(lpReserved);
+ return TRUE;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CSR Sub System
+ * FILE: subsys/csr/csrsrv/process.c
+ * PURPOSE: CSR Server DLL Process Implementation
+ * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "srv.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* DATA **********************************************************************/
+
+PCSR_PROCESS CsrRootProcess = NULL;
+RTL_CRITICAL_SECTION CsrProcessLock;
+ULONG CsrProcessSequenceCount = 5;
+ULONG CsrTotalPerProcessDataLength;
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+/*++
+ * @name ProtectHandle
+ * @implemented NT5.2
+ *
+ * The ProtectHandle routine protects an object handle against closure.
+ *
+ * @return TRUE or FALSE.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+ProtectHandle(IN HANDLE ObjectHandle)
+{
+ NTSTATUS Status;
+ OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo;
+
+ /* Query current state */
+ Status = NtQueryObject(ObjectHandle,
+ ObjectHandleFlagInformation,
+ &HandleInfo,
+ sizeof(HandleInfo),
+ NULL);
+ if (NT_SUCCESS(Status))
+ {
+ /* Enable protect from close */
+ HandleInfo.ProtectFromClose = TRUE;
+ Status = NtSetInformationObject(ObjectHandle,
+ ObjectHandleFlagInformation,
+ &HandleInfo,
+ sizeof(HandleInfo));
+ if (NT_SUCCESS(Status)) return TRUE;
+ }
+
+ /* We failed to or set the state */
+ return FALSE;
+}
+
+/*++
+ * @name UnProtectHandle
+ * @implemented NT5.2
+ *
+ * The UnProtectHandle routine unprotects an object handle against closure.
+ *
+ * @return TRUE or FALSE.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+UnProtectHandle(IN HANDLE ObjectHandle)
+{
+ NTSTATUS Status;
+ OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo;
+
+ /* Query current state */
+ Status = NtQueryObject(ObjectHandle,
+ ObjectHandleFlagInformation,
+ &HandleInfo,
+ sizeof(HandleInfo),
+ NULL);
+ if (NT_SUCCESS(Status))
+ {
+ /* Disable protect from close */
+ HandleInfo.ProtectFromClose = FALSE;
+ Status = NtSetInformationObject(ObjectHandle,
+ ObjectHandleFlagInformation,
+ &HandleInfo,
+ sizeof(HandleInfo));
+ if (NT_SUCCESS(Status)) return TRUE;
+ }
+
+ /* We failed to or set the state */
+ return FALSE;
+}
+
+/*++
+ * @name CsrAllocateProcess
+ * @implemented NT4
+ *
+ * The CsrAllocateProcess routine allocates a new CSR Process object.
+ *
+ * @return Pointer to the newly allocated CSR Process.
+ *
+ * @remarks None.
+ *
+ *--*/
+PCSR_PROCESS
+NTAPI
+CsrAllocateProcess(VOID)
+{
+ PCSR_PROCESS CsrProcess;
+ ULONG TotalSize;
+
+ /* Calculate the amount of memory this should take */
+ TotalSize = sizeof(CSR_PROCESS) +
+ (CSR_SERVER_DLL_MAX * sizeof(PVOID)) +
+ CsrTotalPerProcessDataLength;
+
+ /* Allocate a Process */
+ CsrProcess = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, TotalSize);
+ if (!CsrProcess) return NULL;
+
+ /* Handle the Sequence Number and protect against overflow */
+ CsrProcess->SequenceNumber = CsrProcessSequenceCount++;
+ if (CsrProcessSequenceCount < 5) CsrProcessSequenceCount = 5;
+
+ /* Increase the reference count */
+ CsrProcess->ReferenceCount++;
+
+ /* Initialize the Thread List */
+ InitializeListHead(&CsrProcess->ThreadList);
+
+ /* Return the Process */
+ return CsrProcess;
+}
+
+/*++
+ * @name CsrServerInitialization
+ * @implemented NT4
+ *
+ * The CsrInitializeProcessStructure routine sets up support for CSR Processes
+ * and CSR Threads.
+ *
+ * @param None.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrInitializeProcessStructure(VOID)
+{
+ NTSTATUS Status;
+ ULONG i;
+
+ /* Initialize the Lock */
+ Status = RtlInitializeCriticalSection(&CsrProcessLock);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Set up the Root Process */
+ CsrRootProcess = CsrAllocateProcess();
+ if (!CsrRootProcess) return STATUS_NO_MEMORY;
+
+ /* Set up the minimal information for it */
+ InitializeListHead(&CsrRootProcess->ListLink);
+ CsrRootProcess->ProcessHandle = (HANDLE)-1;
+ CsrRootProcess->ClientId = NtCurrentTeb()->ClientId;
+
+ /* Initialize the Thread Hash List */
+ for (i = 0; i < 256; i++) InitializeListHead(&CsrThreadHashTable[i]);
+
+ /* Initialize the Wait Lock */
+ return RtlInitializeCriticalSection(&CsrWaitListsLock);
+}
+
+/*++
+ * @name CsrDeallocateProcess
+ *
+ * The CsrDeallocateProcess frees the memory associated with a CSR Process.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process to be freed.
+ *
+ * @return None.
+ *
+ * @remarks Do not call this routine. It is reserved for the internal
+ * thread management routines when a CSR Process has been cleanly
+ * dereferenced and killed.
+ *
+ *--*/
+VOID
+NTAPI
+CsrDeallocateProcess(IN PCSR_PROCESS CsrProcess)
+{
+ /* Free the process object from the heap */
+ RtlFreeHeap(CsrHeap, 0, CsrProcess);
+}
+
+/*++
+ * @name CsrInsertProcess
+ *
+ * The CsrInsertProcess routine inserts a CSR Process into the Process List
+ * and notifies Server DLLs of the creation of a new CSR Process.
+ *
+ * @param Parent
+ * Optional pointer to the CSR Process creating this CSR Process.
+ *
+ * @param CurrentProcess
+ * Optional pointer to the current CSR Process.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process which is to be inserted.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrInsertProcess(IN PCSR_PROCESS Parent OPTIONAL,
+ IN PCSR_PROCESS CurrentProcess OPTIONAL,
+ IN PCSR_PROCESS CsrProcess)
+{
+ PCSR_SERVER_DLL ServerDll;
+ ULONG i;
+ ASSERT(ProcessStructureListLocked());
+
+ /* Set the parent */
+ CsrProcess->Parent = Parent;
+
+ /* Insert it into the Root List */
+ InsertTailList(&CsrRootProcess->ListLink, &CsrProcess->ListLink);
+
+ /* Notify the Server DLLs */
+ for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+ {
+ /* Get the current Server DLL */
+ ServerDll = CsrLoadedServerDll[i];
+
+ /* Make sure it's valid and that it has callback */
+ if ((ServerDll) && (ServerDll->NewProcessCallback))
+ {
+ ServerDll->NewProcessCallback(CurrentProcess, CsrProcess);
+ }
+ }
+}
+
+/*++
+ * @name CsrLockedDereferenceProcess
+ *
+ * The CsrLockedDereferenceProcess dereferences a CSR Process while the
+ * Process Lock is already being held.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process to be dereferenced.
+ *
+ * @return None.
+ *
+ * @remarks This routine will return with the Process Lock held.
+ *
+ *--*/
+VOID
+NTAPI
+CsrLockedDereferenceProcess(PCSR_PROCESS CsrProcess)
+{
+ LONG LockCount;
+
+ /* Decrease reference count */
+ LockCount = --CsrProcess->ReferenceCount;
+ ASSERT(LockCount >= 0);
+ if (!LockCount)
+ {
+ /* Call the generic cleanup code */
+ CsrProcessRefcountZero(CsrProcess);
+ CsrAcquireProcessLock();
+ }
+}
+
+/*++
+ * @name CsrLockedReferenceProcess
+ *
+ * The CsrLockedReferenceProcess refences a CSR Process while the
+ * Process Lock is already being held.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process to be referenced.
+ *
+ * @return None.
+ *
+ * @remarks This routine will return with the Process Lock held.
+ *
+ *--*/
+VOID
+NTAPI
+CsrLockedReferenceProcess(IN PCSR_PROCESS CsrProcess)
+{
+ /* Increment the reference count */
+ ++CsrProcess->ReferenceCount;
+}
+
+/*++
+ * @name CsrRemoveProcess
+ *
+ * The CsrRemoveProcess function undoes a CsrInsertProcess operation and
+ * removes the CSR Process from the Process List and notifies Server DLLs
+ * of this removal.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process to remove.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrRemoveProcess(IN PCSR_PROCESS CsrProcess)
+{
+ PCSR_SERVER_DLL ServerDll;
+ ULONG i;
+ ASSERT(ProcessStructureListLocked());
+
+ /* Remove us from the Process List */
+ RemoveEntryList(&CsrProcess->ListLink);
+
+ /* Release the lock */
+ CsrReleaseProcessLock();
+
+ /* Loop every Server DLL */
+ for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+ {
+ /* Get the Server DLL */
+ ServerDll = CsrLoadedServerDll[i];
+
+ /* Check if it's valid and if it has a Disconnect Callback */
+ if ((ServerDll) && (ServerDll->DisconnectCallback))
+ {
+ /* Call it */
+ ServerDll->DisconnectCallback(CsrProcess);
+ }
+ }
+}
+
+/*++
+ * @name CsrProcessRefcountZero
+ *
+ * The CsrProcessRefcountZero routine is executed when a CSR Process has lost
+ * all its active references. It removes and de-allocates the CSR Process.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process that is to be deleted.
+ *
+ * @return None.
+ *
+ * @remarks Do not call this routine. It is reserved for the internal
+ * thread management routines when a CSR Process has lost all
+ * its references.
+ *
+ * This routine is called with the Process Lock held.
+ *
+ *--*/
+VOID
+NTAPI
+CsrProcessRefcountZero(IN PCSR_PROCESS CsrProcess)
+{
+ /* Remove the Process from the list */
+ CsrRemoveProcess(CsrProcess);
+
+ /* Check if there's a session */
+ if (CsrProcess->NtSession)
+ {
+ /* Dereference the Session */
+ CsrDereferenceNtSession(CsrProcess->NtSession, 0);
+ }
+
+ /* Close the Client Port if there is one */
+ if (CsrProcess->ClientPort) NtClose(CsrProcess->ClientPort);
+
+ /* Close the process handle */
+ NtClose(CsrProcess->ProcessHandle);
+
+ /* Free the Proces Object */
+ CsrDeallocateProcess(CsrProcess);
+}
+
+/*++
+ * @name CsrpSetToNormalPriority
+ *
+ * The CsrpSetToNormalPriority routine sets the current NT Process'
+ * priority to the normal priority for CSR Processes.
+ *
+ * @param None.
+ *
+ * @return None.
+ *
+ * @remarks The "Normal" Priority corresponds to the Normal Forground
+ * Priority (9) plus a boost of 4.
+ *
+ *--*/
+VOID
+NTAPI
+CsrpSetToNormalPriority(VOID)
+{
+ KPRIORITY BasePriority = (8 + 1) + 4;
+
+ /* Set the Priority */
+ NtSetInformationProcess(NtCurrentProcess(),
+ ProcessBasePriority,
+ &BasePriority,
+ sizeof(KPRIORITY));
+}
+
+/*++
+ * @name CsrpSetToShutdownPriority
+ *
+ * The CsrpSetToShutdownPriority routine sets the current NT Process'
+ * priority to the boosted priority for CSR Processes doing shutdown.
+ * Additonally, it acquires the Shutdown Privilege required for shutdown.
+ *
+ * @param None.
+ *
+ * @return None.
+ *
+ * @remarks The "Shutdown" Priority corresponds to the Normal Forground
+ * Priority (9) plus a boost of 6.
+ *
+ *--*/
+VOID
+NTAPI
+CsrpSetToShutdownPriority(VOID)
+{
+ KPRIORITY SetBasePriority = (8 + 1) + 6;
+ BOOLEAN Old;
+
+ /* Get the shutdown privilege */
+ if (NT_SUCCESS(RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
+ TRUE,
+ FALSE,
+ &Old)))
+ {
+ /* Set the Priority */
+ NtSetInformationProcess(NtCurrentProcess(),
+ ProcessBasePriority,
+ &SetBasePriority,
+ sizeof(KPRIORITY));
+ }
+}
+
+/*++
+ * @name FindProcessForShutdown
+ *
+ * The FindProcessForShutdown routine returns a CSR Process which is ready
+ * to be shutdown, and sets the appropriate shutdown flags for it.
+ *
+ * @param CallerLuid
+ * Pointer to the LUID of the CSR Process calling this routine.
+ *
+ * @return Pointer to a CSR Process which is ready to be shutdown.
+ *
+ * @remarks None.
+ *
+ *--*/
+PCSR_PROCESS
+NTAPI
+FindProcessForShutdown(IN PLUID CallerLuid)
+{
+ PLIST_ENTRY NextEntry;
+ LUID ProcessLuid;
+ NTSTATUS Status;
+ LUID SystemLuid = SYSTEM_LUID;
+ PCSR_PROCESS CsrProcess;
+ PCSR_THREAD CsrThread;
+ PCSR_PROCESS ReturnCsrProcess = NULL;
+ ULONG Level = 0;
+
+ /* Set the List Pointers */
+ NextEntry = CsrRootProcess->ListLink.Flink;
+ while (NextEntry != &CsrRootProcess->ListLink)
+ {
+ /* Get the process */
+ CsrProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink);
+
+ /* Move to the next entry */
+ NextEntry = NextEntry->Flink;
+
+ /* Skip this process if it's already been processed*/
+ if (CsrProcess->Flags & CsrProcessSkipShutdown) continue;
+
+ /* Get the LUID of this Process */
+ Status = CsrGetProcessLuid(CsrProcess->ProcessHandle, &ProcessLuid);
+
+ /* Check if we didn't get access to the LUID */
+ if (Status == STATUS_ACCESS_DENIED)
+ {
+ /* Check if we have any threads */
+ if (CsrProcess->ThreadCount)
+ {
+ /* Impersonate one of the threads and retry */
+ CsrThread = CONTAINING_RECORD(CsrProcess->ThreadList.Flink,
+ CSR_THREAD,
+ Link);
+ CsrImpersonateClient(CsrThread);
+ Status = CsrGetProcessLuid(NULL, &ProcessLuid);
+ CsrRevertToSelf();
+ }
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ /* We didn't have access, so skip it */
+ CsrProcess->Flags |= CsrProcessSkipShutdown;
+ continue;
+ }
+
+ /* Check if this is the System LUID */
+ if (RtlEqualLuid(&ProcessLuid, &SystemLuid))
+ {
+ /* Mark this process */
+ CsrProcess->ShutdownFlags |= CsrShutdownSystem;
+ }
+ else if (!RtlEqualLuid(&ProcessLuid, CallerLuid))
+ {
+ /* Our LUID doesn't match with the caller's */
+ CsrProcess->ShutdownFlags |= CsrShutdownOther;
+ }
+
+ /* Check if we're past the previous level */
+ if ((CsrProcess->ShutdownLevel > Level) || !(ReturnCsrProcess))
+ {
+ /* Update the level */
+ Level = CsrProcess->ShutdownLevel;
+
+ /* Set the final process */
+ ReturnCsrProcess = CsrProcess;
+ }
+ }
+
+ /* Check if we found a process */
+ if (ReturnCsrProcess)
+ {
+ /* Skip this one next time */
+ ReturnCsrProcess->Flags |= CsrProcessSkipShutdown;
+ }
+
+ return ReturnCsrProcess;
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+/*++
+ * @name CsrCreateProcess
+ * @implemented NT4
+ *
+ * Do nothing for 500ms.
+ *
+ * @param ArgumentCount
+ * Description of the parameter. Wrapped to more lines on ~70th
+ * column.
+ *
+ * @param Arguments
+ * Description of the parameter. Wrapped to more lines on ~70th
+ * column.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrCreateProcess(IN HANDLE hProcess,
+ IN HANDLE hThread,
+ IN PCLIENT_ID ClientId,
+ IN PCSR_NT_SESSION NtSession,
+ IN ULONG Flags,
+ IN PCLIENT_ID DebugCid)
+{
+ PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
+ CLIENT_ID CurrentCid;
+ PCSR_PROCESS CurrentProcess;
+ PVOID ProcessData;
+ ULONG i;
+ PCSR_PROCESS CsrProcess;
+ NTSTATUS Status;
+ PCSR_THREAD CsrThread;
+ KERNEL_USER_TIMES KernelTimes;
+
+ /* Get the current CID and lock Processes */
+ CurrentCid = CurrentThread->ClientId;
+ CsrAcquireProcessLock();
+
+ /* Get the current CSR Thread */
+ CurrentThread = CsrLocateThreadByClientId(&CurrentProcess, &CurrentCid);
+ if (!CurrentThread)
+ {
+ /* We've failed to locate the thread */
+ CsrReleaseProcessLock();
+ return STATUS_THREAD_IS_TERMINATING;
+ }
+
+ /* Allocate a new Process Object */
+ CsrProcess = CsrAllocateProcess();
+ if (!CsrProcess)
+ {
+ /* Couldn't allocate Process */
+ CsrReleaseProcessLock();
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Inherit the Process Data */
+ CurrentProcess = CurrentThread->Process;
+ ProcessData = &CurrentProcess->ServerData[CSR_SERVER_DLL_MAX];
+ for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+ {
+ /* Check if the DLL is Loaded and has Per Process Data */
+ if (CsrLoadedServerDll[i] && CsrLoadedServerDll[i]->SizeOfProcessData)
+ {
+ /* Set the pointer */
+ CsrProcess->ServerData[i] = ProcessData;
+
+ /* Copy the Data */
+ RtlMoveMemory(ProcessData,
+ CurrentProcess->ServerData[i],
+ CsrLoadedServerDll[i]->SizeOfProcessData);
+
+ /* Update next data pointer */
+ ProcessData = (PVOID)((ULONG_PTR)ProcessData +
+ CsrLoadedServerDll[i]->SizeOfProcessData);
+ }
+ else
+ {
+ /* No data for this Server */
+ CsrProcess->ServerData[i] = NULL;
+ }
+ }
+
+ /* Set the Exception port to us */
+ Status = NtSetInformationProcess(hProcess,
+ ProcessExceptionPort,
+ &CsrApiPort,
+ sizeof(HANDLE));
+ if (!NT_SUCCESS(Status))
+ {
+ /* Failed */
+ CsrDeallocateProcess(CsrProcess);
+ CsrReleaseProcessLock();
+ return STATUS_NO_MEMORY;
+ }
+
+ /* If Check if CreateProcess got CREATE_NEW_PROCESS_GROUP */
+ if (!(Flags & CsrProcessCreateNewGroup))
+ {
+ /* Create new data */
+ CsrProcess->ProcessGroupId = HandleToUlong(ClientId->UniqueProcess);
+ CsrProcess->ProcessGroupSequence = CsrProcess->SequenceNumber;
+ }
+ else
+ {
+ /* Copy it from the current process */
+ CsrProcess->ProcessGroupId = CurrentProcess->ProcessGroupId;
+ CsrProcess->ProcessGroupSequence = CurrentProcess->ProcessGroupSequence;
+ }
+
+ /* Check if this is a console process */
+ if (Flags & CsrProcessIsConsoleApp) CsrProcess->Flags |= CsrProcessIsConsoleApp;
+
+ /* Mask out non-debug flags */
+ Flags &= ~(CsrProcessIsConsoleApp | CsrProcessCreateNewGroup | CsrProcessPriorityFlags);
+
+ /* Check if every process will be debugged */
+ if (!(Flags) && (CurrentProcess->DebugFlags & CsrDebugProcessChildren))
+ {
+ /* Pass it on to the current process */
+ CsrProcess->DebugFlags = CsrDebugProcessChildren;
+ CsrProcess->DebugCid = CurrentProcess->DebugCid;
+ }
+
+ /* Check if Debugging was used on this process */
+ if ((Flags & (CsrDebugOnlyThisProcess | CsrDebugProcessChildren)) && (DebugCid))
+ {
+ /* Save the debug flag used */
+ CsrProcess->DebugFlags = Flags;
+
+ /* Save the CID */
+ CsrProcess->DebugCid = *DebugCid;
+ }
+
+ /* Check if we debugging is enabled */
+ if (CsrProcess->DebugFlags)
+ {
+ /* Set the Debug Port to us */
+ Status = NtSetInformationProcess(hProcess,
+ ProcessDebugPort,
+ &CsrApiPort,
+ sizeof(HANDLE));
+ ASSERT(NT_SUCCESS(Status));
+ if (!NT_SUCCESS(Status))
+ {
+ /* Failed */
+ CsrDeallocateProcess(CsrProcess);
+ CsrReleaseProcessLock();
+ return STATUS_NO_MEMORY;
+ }
+ }
+
+ /* Get the Thread Create Time */
+ Status = NtQueryInformationThread(hThread,
+ ThreadTimes,
+ (PVOID)&KernelTimes,
+ sizeof(KernelTimes),
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Failed */
+ CsrDeallocateProcess(CsrProcess);
+ CsrReleaseProcessLock();
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Allocate a CSR Thread Structure */
+ CsrThread = CsrAllocateThread(CsrProcess);
+ if (!CsrThread)
+ {
+ /* Failed */
+ CsrDeallocateProcess(CsrProcess);
+ CsrReleaseProcessLock();
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Save the data we have */
+ CsrThread->CreateTime = KernelTimes.CreateTime;
+ CsrThread->ClientId = *ClientId;
+ CsrThread->ThreadHandle = hThread;
+ ProtectHandle(hThread);
+ CsrThread->Flags = 0;
+
+ /* Insert the Thread into the Process */
+ CsrInsertThread(CsrProcess, CsrThread);
+
+ /* Reference the session */
+ CsrReferenceNtSession(NtSession);
+ CsrProcess->NtSession = NtSession;
+
+ /* Setup Process Data */
+ CsrProcess->ClientId = *ClientId;
+ CsrProcess->ProcessHandle = hProcess;
+ CsrProcess->ShutdownLevel = 0x280;
+
+ /* Set the Priority to Background */
+ CsrSetBackgroundPriority(CsrProcess);
+
+ /* Insert the Process */
+ CsrInsertProcess(NULL, CurrentProcess, CsrProcess);
+
+ /* Release lock and return */
+ CsrReleaseProcessLock();
+ return Status;
+}
+
+/*++
+ * @name CsrDebugProcess
+ * @implemented NT4
+ *
+ * The CsrDebugProcess routine is deprecated in NT 5.1 and higher. It is
+ * exported only for compatibility with older CSR Server DLLs.
+ *
+ * @param CsrProcess
+ * Deprecated.
+ *
+ * @return Deprecated
+ *
+ * @remarks Deprecated.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrDebugProcess(IN PCSR_PROCESS CsrProcess)
+{
+ /* CSR does not handle debugging anymore */
+ DPRINT("CSRSRV: %s(%08lx) called\n", __FUNCTION__, CsrProcess);
+ return STATUS_UNSUCCESSFUL;
+}
+
+/*++
+ * @name CsrServerInitialization
+ * @implemented NT4
+ *
+ * The CsrDebugProcessStop routine is deprecated in NT 5.1 and higher. It is
+ * exported only for compatibility with older CSR Server DLLs.
+ *
+ * @param CsrProcess
+ * Deprecated.
+ *
+ * @return Deprecated
+ *
+ * @remarks Deprecated.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrDebugProcessStop(IN PCSR_PROCESS CsrProcess)
+{
+ /* CSR does not handle debugging anymore */
+ DPRINT("CSRSRV: %s(%08lx) called\n", __FUNCTION__, CsrProcess);
+ return STATUS_UNSUCCESSFUL;
+}
+
+/*++
+ * @name CsrDereferenceProcess
+ * @implemented NT4
+ *
+ * The CsrDereferenceProcess routine removes a reference from a CSR Process.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Process to dereference.
+ *
+ * @return None.
+ *
+ * @remarks If the reference count has reached zero (ie: the CSR Process has
+ * no more active references), it will be deleted.
+ *
+ *--*/
+VOID
+NTAPI
+CsrDereferenceProcess(IN PCSR_PROCESS CsrProcess)
+{
+ LONG LockCount;
+
+ /* Acquire process lock */
+ CsrAcquireProcessLock();
+
+ /* Decrease reference count */
+ LockCount = --CsrProcess->ReferenceCount;
+ ASSERT(LockCount >= 0);
+ if (!LockCount)
+ {
+ /* Call the generic cleanup code */
+ CsrProcessRefcountZero(CsrProcess);
+ }
+ else
+ {
+ /* Just release the lock */
+ CsrReleaseProcessLock();
+ }
+}
+
+/*++
+ * @name CsrDestroyProcess
+ * @implemented NT4
+ *
+ * The CsrDestroyProcess routine destroys the CSR Process corresponding to
+ * a given Client ID.
+ *
+ * @param Cid
+ * Pointer to the Client ID Structure corresponding to the CSR
+ * Process which is about to be destroyed.
+ *
+ * @param ExitStatus
+ * Unused.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING
+ * if the CSR Process is already terminating.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrDestroyProcess(IN PCLIENT_ID Cid,
+ IN NTSTATUS ExitStatus)
+{
+ PCSR_THREAD CsrThread;
+ PCSR_PROCESS CsrProcess;
+ CLIENT_ID ClientId = *Cid;
+ PLIST_ENTRY NextEntry;
+
+ /* Acquire lock */
+ CsrAcquireProcessLock();
+
+ /* Find the thread */
+ CsrThread = CsrLocateThreadByClientId(&CsrProcess, &ClientId);
+
+ /* Make sure we got one back, and that it's not already gone */
+ if (!(CsrThread) || (CsrProcess->Flags & CsrProcessTerminating))
+ {
+ /* Release the lock and return failure */
+ CsrReleaseProcessLock();
+ return STATUS_THREAD_IS_TERMINATING;
+ }
+
+ /* Set the terminated flag */
+ CsrProcess->Flags |= CsrProcessTerminating;
+
+ /* Get the List Pointers */
+ NextEntry = CsrProcess->ThreadList.Flink;
+ while (NextEntry != &CsrProcess->ThreadList)
+ {
+ /* Get the current thread entry */
+ CsrThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
+
+ /* Make sure the thread isn't already dead */
+ if (CsrThread->Flags & CsrThreadTerminated)
+ {
+ NextEntry = NextEntry->Flink;
+ continue;
+ }
+
+ /* Set the Terminated flag */
+ CsrThread->Flags |= CsrThreadTerminated;
+
+ /* Acquire the Wait Lock */
+ CsrAcquireWaitLock();
+
+ /* Do we have an active wait block? */
+ if (CsrThread->WaitBlock)
+ {
+ /* Notify waiters of termination */
+ CsrNotifyWaitBlock(CsrThread->WaitBlock,
+ NULL,
+ NULL,
+ NULL,
+ CsrProcessTerminating,
+ TRUE);
+ }
+
+ /* Release the Wait Lock */
+ CsrReleaseWaitLock();
+
+ /* Dereference the thread */
+ CsrLockedDereferenceThread(CsrThread);
+ NextEntry = CsrProcess->ThreadList.Flink;
+ }
+
+ /* Release the Process Lock and return success */
+ CsrReleaseProcessLock();
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrGetProcessLuid
+ * @implemented NT4
+ *
+ * Do nothing for 500ms.
+ *
+ * @param hProcess
+ * Optional handle to the process whose LUID should be returned.
+ *
+ * @param Luid
+ * Pointer to a LUID Pointer which will receive the CSR Process' LUID
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks If hProcess is not supplied, then the current thread's token will
+ * be used. If that too is missing, then the current process' token
+ * will be used.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrGetProcessLuid(HANDLE hProcess OPTIONAL,
+ PLUID Luid)
+{
+ HANDLE hToken = NULL;
+ NTSTATUS Status;
+ ULONG Length;
+ PTOKEN_STATISTICS TokenStats;
+
+ /* Check if we have a handle to a CSR Process */
+ if (!hProcess)
+ {
+ /* We don't, so try opening the Thread's Token */
+ Status = NtOpenThreadToken(NtCurrentThread(),
+ TOKEN_QUERY,
+ FALSE,
+ &hToken);
+
+ /* Check for success */
+ if (!NT_SUCCESS(Status))
+ {
+ /* If we got some other failure, then return and quit */
+ if (Status != STATUS_NO_TOKEN) return Status;
+
+ /* We don't have a Thread Token, use a Process Token */
+ hProcess = NtCurrentProcess();
+ hToken = NULL;
+ }
+ }
+
+ /* Check if we have a token by now */
+ if (!hToken)
+ {
+ /* No token yet, so open the Process Token */
+ Status = NtOpenProcessToken(hProcess,
+ TOKEN_QUERY,
+ &hToken);
+ if (!NT_SUCCESS(Status)) return Status;
+ }
+
+ /* Now get the size we'll need for the Token Information */
+ Status = NtQueryInformationToken(hToken,
+ TokenStatistics,
+ NULL,
+ 0,
+ &Length);
+
+ /* Allocate memory for the Token Info */
+ TokenStats = RtlAllocateHeap(CsrHeap, 0, Length);
+ if (!TokenStats)
+ {
+ /* Fail and close the token */
+ NtClose(hToken);
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Now query the information */
+ Status = NtQueryInformationToken(hToken,
+ TokenStatistics,
+ TokenStats,
+ Length,
+ &Length);
+
+ /* Close the handle */
+ NtClose(hToken);
+
+ /* Check for success to return the LUID */
+ if (NT_SUCCESS(Status)) *Luid = TokenStats->AuthenticationId;
+
+ /* Free the query information */
+ RtlFreeHeap(CsrHeap, 0, TokenStats);
+
+ /* Return the Status */
+ return Status;
+}
+
+/*++
+ * @name CsrLockProcessByClientId
+ * @implemented NT4
+ *
+ * The CsrLockProcessByClientId routine locks the CSR Process corresponding
+ * to the given Process ID and optionally returns it.
+ *
+ * @param Pid
+ * Process ID corresponding to the CSR Process which will be locked.
+ *
+ * @param CsrProcess
+ * Optional pointer to a CSR Process pointer which will hold the
+ * CSR Process corresponding to the given Process ID.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks Locking a CSR Process is defined as acquiring an extra
+ * reference to it and returning with the Process Lock held.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrLockProcessByClientId(IN HANDLE Pid,
+ OUT PCSR_PROCESS *CsrProcess)
+{
+ PLIST_ENTRY NextEntry;
+ PCSR_PROCESS CurrentProcess = NULL;
+ NTSTATUS Status;
+
+ /* Acquire the lock */
+ CsrAcquireProcessLock();
+
+ /* Assume failure */
+ ASSERT(CsrProcess != NULL);
+ *CsrProcess = NULL;
+
+ /* Setup the List Pointers */
+ NextEntry = &CsrRootProcess->ListLink;
+ do
+ {
+ /* Get the Process */
+ CurrentProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink);
+
+ /* Check for PID Match */
+ if (CurrentProcess->ClientId.UniqueProcess == Pid)
+ {
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ /* Next entry */
+ NextEntry = NextEntry->Flink;
+ } while (NextEntry != &CsrRootProcess->ListLink);
+
+ /* Check if we didn't find it in the list */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Nothing found, release the lock */
+ CsrReleaseProcessLock();
+ }
+ else
+ {
+ /* Lock the found process and return it */
+ CsrLockedReferenceProcess(CurrentProcess);
+ *CsrProcess = CurrentProcess;
+ }
+
+ /* Return the result */
+ return Status;
+}
+
+/*++
+ * @name CsrSetForegroundPriority
+ * @implemented NT4
+ *
+ * The CsrSetForegroundPriority routine sets the priority for the given CSR
+ * Process as a Foreground priority.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process whose priority will be modified.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrSetForegroundPriority(IN PCSR_PROCESS CsrProcess)
+{
+ PROCESS_PRIORITY_CLASS PriorityClass;
+
+ /* Set the Foreground bit on */
+ PriorityClass.Foreground = TRUE;
+
+ /* Set the new Priority */
+ NtSetInformationProcess(CsrProcess->ProcessHandle,
+ ProcessPriorityClass,
+ &PriorityClass,
+ sizeof(PriorityClass));
+}
+
+/*++
+ * @name CsrSetBackgroundPriority
+ * @implemented NT4
+ *
+ * The CsrSetBackgroundPriority routine sets the priority for the given CSR
+ * Process as a Background priority.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process whose priority will be modified.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrSetBackgroundPriority(IN PCSR_PROCESS CsrProcess)
+{
+ PROCESS_PRIORITY_CLASS PriorityClass;
+
+ /* Set the Foreground bit off */
+ PriorityClass.Foreground = FALSE;
+
+ /* Set the new Priority */
+ NtSetInformationProcess(CsrProcess->ProcessHandle,
+ ProcessPriorityClass,
+ &PriorityClass,
+ sizeof(PriorityClass));
+}
+
+/*++
+ * @name CsrShutdownProcesses
+ * @implemented NT4
+ *
+ * The CsrShutdownProcesses routine shuts down every CSR Process possible
+ * and calls each Server DLL's shutdown notification.
+ *
+ * @param CallerLuid
+ * Pointer to the LUID of the CSR Process that is ordering the
+ * shutdown.
+ *
+ * @param Flags
+ * Flags to send to the shutdown notification routine.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrShutdownProcesses(IN PLUID CallerLuid,
+ IN ULONG Flags)
+{
+ PLIST_ENTRY NextEntry;
+ PCSR_PROCESS CsrProcess;
+ NTSTATUS Status;
+ BOOLEAN FirstTry;
+ ULONG i;
+ PCSR_SERVER_DLL ServerDll;
+ ULONG Result = 0; /* Intentionally invalid enumeratee to silence compiler warning */
+
+ /* Acquire process lock */
+ CsrAcquireProcessLock();
+
+ /* Add shutdown flag */
+ CsrRootProcess->ShutdownFlags |= CsrShutdownSystem;
+
+ /* Get the list pointers */
+ NextEntry = CsrRootProcess->ListLink.Flink;
+ while (NextEntry != &CsrRootProcess->ListLink)
+ {
+ /* Get the Process */
+ CsrProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink);
+
+ /* Remove the skip flag, set shutdown flags to 0*/
+ CsrProcess->Flags &= ~CsrProcessSkipShutdown;
+ CsrProcess->ShutdownFlags = 0;
+
+ /* Move to the next */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* Set shudown Priority */
+ CsrpSetToShutdownPriority();
+
+ /* Start looping */
+ while (TRUE)
+ {
+ /* Find the next process to shutdown */
+ CsrProcess = FindProcessForShutdown(CallerLuid);
+ if (!CsrProcess) break;
+
+ /* Increase reference to process */
+ CsrProcess->ReferenceCount++;
+
+ FirstTry = TRUE;
+ while (TRUE)
+ {
+ /* Loop all the servers */
+ for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+ {
+ /* Get the current server */
+ ServerDll = CsrLoadedServerDll[i];
+ if ((ServerDll) && (ServerDll->ShutdownProcessCallback))
+ {
+ /* Release the lock, make the callback, and acquire it back */
+ CsrReleaseProcessLock();
+ Result = ServerDll->ShutdownProcessCallback(CsrProcess,
+ Flags,
+ FirstTry);
+ CsrAcquireProcessLock();
+
+ /* Check the result */
+ if (Result == CsrShutdownCsrProcess)
+ {
+ /* The callback unlocked the process */
+ break;
+ }
+ else if (Result == CsrShutdownCancelled)
+ {
+ /* Check if this was a forced shutdown */
+ if (Flags & EWX_FORCE)
+ {
+ DPRINT1("Process %x cancelled forced shutdown (Dll = %d)\n",
+ CsrProcess->ClientId.UniqueProcess, i);
+ DbgBreakPoint();
+ }
+
+ /* Shutdown was cancelled, unlock and exit */
+ CsrReleaseProcessLock();
+ Status = STATUS_CANCELLED;
+ goto Quickie;
+ }
+ }
+ }
+
+ /* No matches during the first try, so loop again */
+ if ((FirstTry) && (Result == CsrShutdownNonCsrProcess))
+ {
+ FirstTry = FALSE;
+ continue;
+ }
+
+ /* Second try, break out */
+ break;
+ }
+
+ /* We've reached the final loop here, so dereference */
+ if (i == CSR_SERVER_DLL_MAX) CsrLockedDereferenceProcess(CsrProcess);
+ }
+
+ /* Success path */
+ CsrReleaseProcessLock();
+ Status = STATUS_SUCCESS;
+
+Quickie:
+ /* Return to normal priority */
+ CsrpSetToNormalPriority();
+ return Status;
+}
+
+/*++
+ * @name CsrUnlockProcess
+ * @implemented NT4
+ *
+ * The CsrUnlockProcess undoes a previous CsrLockProcessByClientId operation.
+ *
+ * @param CsrProcess
+ * Pointer to a previously locked CSR Process.
+ *
+ * @return STATUS_SUCCESS.
+ *
+ * @remarks This routine must be called with the Process Lock held.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrUnlockProcess(IN PCSR_PROCESS CsrProcess)
+{
+ /* Dereference the process */
+ CsrLockedDereferenceProcess(CsrProcess);
+
+ /* Release the lock and return */
+ CsrReleaseProcessLock();
+ return STATUS_SUCCESS;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CSR Sub System
+ * FILE: subsys/csr/csrsrv/server.c
+ * PURPOSE: CSR Server DLL Server Functions
+ * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
+ */
+
+/* INCLUDES ******************************************************************/
+#include "srv.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* DATA **********************************************************************/
+
+PCSR_API_ROUTINE CsrServerApiDispatchTable[5] =
+{
+ CsrSrvClientConnect,
+ CsrSrvUnusedFunction,
+ CsrSrvUnusedFunction,
+ CsrSrvIdentifyAlertableThread,
+ CsrSrvSetPriorityClass
+};
+
+BOOLEAN CsrServerApiServerValidTable[5] =
+{
+ TRUE,
+ FALSE,
+ TRUE,
+ TRUE,
+ TRUE
+};
+
+PCHAR CsrServerApiNameTable[5] =
+{
+ "ClientConnect",
+ "ThreadConnect",
+ "ProfileControl",
+ "IdentifyAlertableThread",
+ "SetPriorityClass"
+};
+
+PCSR_SERVER_DLL CsrLoadedServerDll[CSR_SERVER_DLL_MAX];
+PVOID CsrSrvSharedSectionHeap;
+PVOID CsrSrvSharedSectionBase;
+PVOID *CsrSrvSharedStaticServerData;
+ULONG CsrSrvSharedSectionSize;
+HANDLE CsrSrvSharedSection;
+
+/* PRIVATE FUNCTIONS**********************************************************/
+
+/*++
+ * @name CsrLoadServerDll
+ * @implemented NT4
+ *
+ * The CsrLoadServerDll routine loads a CSR Server DLL and calls its entrypoint
+ *
+ * @param DllString
+ * Pointer to the CSR Server DLL to load and call.
+ *
+ * @param EntryPoint
+ * Pointer to the name of the server's initialization function. If
+ * this parameter is NULL, the default ServerDllInitialize will be
+ * assumed.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrLoadServerDll(IN PCHAR DllString,
+ IN PCHAR EntryPoint OPTIONAL,
+ IN ULONG ServerId)
+{
+ NTSTATUS Status;
+ ANSI_STRING DllName;
+ UNICODE_STRING TempString, ErrorString;
+ ULONG_PTR Parameters[2];
+ HANDLE hServerDll = NULL;
+ ULONG Size;
+ PCSR_SERVER_DLL ServerDll;
+ STRING EntryPointString;
+ PCSR_SERVER_DLL_INIT_CALLBACK ServerDllInitProcedure;
+ ULONG Response;
+
+ /* Check if it's beyond the maximum we support */
+ if (ServerId >= CSR_SERVER_DLL_MAX) return STATUS_TOO_MANY_NAMES;
+
+ /* Check if it's already been loaded */
+ if (CsrLoadedServerDll[ServerId]) return STATUS_INVALID_PARAMETER;
+
+ /* Convert the name to Unicode */
+ ASSERT(DllString != NULL);
+ RtlInitAnsiString(&DllName, DllString);
+ Status = RtlAnsiStringToUnicodeString(&TempString, &DllName, TRUE);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* If we are loading ourselves, don't actually load us */
+ if (ServerId != CSR_SRV_SERVER)
+ {
+ /* Load the DLL */
+ Status = LdrLoadDll(NULL, 0, &TempString, &hServerDll);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Setup error parameters */
+ Parameters[0] = (ULONG_PTR)&TempString;
+ Parameters[1] = (ULONG_PTR)&ErrorString;
+ RtlInitUnicodeString(&ErrorString, L"Default Load Path");
+
+ /* Send a hard error */
+ NtRaiseHardError(Status,
+ 2,
+ 3,
+ Parameters,
+ OptionOk,
+ &Response);
+ }
+
+ /* Get rid of the string */
+ RtlFreeUnicodeString(&TempString);
+ if (!NT_SUCCESS(Status)) return Status;
+ }
+
+ /* Allocate a CSR DLL Object */
+ Size = sizeof(CSR_SERVER_DLL) + DllName.MaximumLength;
+ ServerDll = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, Size);
+ if (!ServerDll)
+ {
+ if (hServerDll) LdrUnloadDll(hServerDll);
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Set up the Object */
+ ServerDll->Length = Size;
+ ServerDll->SharedSection = CsrSrvSharedSectionHeap;
+ ServerDll->Event = CsrInitializationEvent;
+ ServerDll->Name.Length = DllName.Length;
+ ServerDll->Name.MaximumLength = DllName.MaximumLength;
+ ServerDll->Name.Buffer = (PCHAR)(ServerDll + 1);
+ if (DllName.Length)
+ {
+ strncpy(ServerDll->Name.Buffer, DllName.Buffer, DllName.Length);
+ }
+ ServerDll->ServerId = ServerId;
+ ServerDll->ServerHandle = hServerDll;
+
+ /* Now get the entrypoint */
+ if (hServerDll)
+ {
+ /* Initialize a string for the entrypoint, or use the default */
+ RtlInitAnsiString(&EntryPointString,
+ !(EntryPoint) ? "ServerDllInitialization" :
+ EntryPoint);
+
+ /* Get a pointer to it */
+ Status = LdrGetProcedureAddress(hServerDll,
+ &EntryPointString,
+ 0,
+ (PVOID)&ServerDllInitProcedure);
+ }
+ else
+ {
+ /* No handle, so we are loading ourselves */
+ ServerDllInitProcedure = CsrServerDllInitialization;
+ Status = STATUS_SUCCESS;
+ }
+
+ /* Check if we got the pointer, and call it */
+ if (NT_SUCCESS(Status))
+ {
+ /* Get the result from the Server DLL */
+ Status = ServerDllInitProcedure(ServerDll);
+
+ /* Check for Success */
+ if (NT_SUCCESS(Status))
+ {
+ /*
+ * Add this Server's Per-Process Data Size to the total that each
+ * process will need.
+ */
+ CsrTotalPerProcessDataLength += ServerDll->SizeOfProcessData;
+
+ /* Save the pointer in our list */
+ CsrLoadedServerDll[ServerDll->ServerId] = ServerDll;
+
+ /* Does it use our generic heap? */
+ if (ServerDll->SharedSection != CsrSrvSharedSectionHeap)
+ {
+ /* No, save the pointer to its shared section in our list */
+ CsrSrvSharedStaticServerData[ServerDll->ServerId] = ServerDll->SharedSection;
+ }
+ }
+ else
+ {
+ /* Use shared failure code */
+ goto LoadFailed;
+ }
+ }
+ else
+ {
+LoadFailed:
+ /* Server Init failed, unload it */
+ if (hServerDll) LdrUnloadDll(hServerDll);
+
+ /* Delete the Object */
+ RtlFreeHeap(CsrHeap, 0, ServerDll);
+ }
+
+ /* Return to caller */
+ return Status;
+}
+
+/*++
+ * @name CsrServerDllInitialization
+ * @implemented NT4
+ *
+ * The CsrServerDllInitialization is the initialization routine for
+ * the this Server DLL.
+ *
+ * @param LoadedServerDll
+ * Pointer to the CSR Server DLL structure representing this Server DLL.
+ *
+ * @return STATUS_SUCCESS.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrServerDllInitialization(IN PCSR_SERVER_DLL LoadedServerDll)
+{
+ /* Setup the DLL Object */
+ LoadedServerDll->ApiBase = 0;
+ LoadedServerDll->HighestApiSupported = 5;
+ LoadedServerDll->DispatchTable = CsrServerApiDispatchTable;
+ LoadedServerDll->ValidTable = CsrServerApiServerValidTable;
+ LoadedServerDll->NameTable = CsrServerApiNameTable;
+ LoadedServerDll->SizeOfProcessData = 0;
+ LoadedServerDll->ConnectCallback = NULL;
+ LoadedServerDll->DisconnectCallback = NULL;
+
+ /* All done */
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrSrvClientConnect
+ *
+ * The CsrSrvClientConnect CSR API handles a new connection to a server DLL.
+ *
+ * @param ApiMessage
+ * Pointer to the CSR API Message for this request.
+ *
+ * @param Reply
+ * Optional reply to this request.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_INVALID_PARAMETER
+ * or STATUS_TOO_MANY_NAMES in case of failure.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSrvClientConnect(IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply OPTIONAL)
+{
+ NTSTATUS Status;
+ PCSR_CLIENT_CONNECT ClientConnect;
+ PCSR_SERVER_DLL ServerDll;
+ PCSR_PROCESS CurrentProcess = ((PCSR_THREAD)NtCurrentTeb()->CsrClientThread)->Process;
+
+ /* Load the Message, set default reply */
+ ClientConnect = (PCSR_CLIENT_CONNECT)&ApiMessage->CsrClientConnect;
+ *Reply = 0;
+
+ /* Validate the ServerID */
+ if (ClientConnect->ServerId >= CSR_SERVER_DLL_MAX)
+ {
+ return STATUS_TOO_MANY_NAMES;
+ }
+ else if (!CsrLoadedServerDll[ClientConnect->ServerId])
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Validate the Message Buffer */
+ if (!(CsrValidateMessageBuffer(ApiMessage,
+ ClientConnect->ConnectionInfo,
+ ClientConnect->ConnectionInfoSize,
+ 1)))
+ {
+ /* Fail due to buffer overflow or other invalid buffer */
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Load the Server DLL */
+ ServerDll = CsrLoadedServerDll[ClientConnect->ServerId];
+
+ /* Check if it has a Connect Callback */
+ if (ServerDll->ConnectCallback)
+ {
+ /* Call the callback */
+ Status = ServerDll->ConnectCallback(CurrentProcess,
+ ClientConnect->ConnectionInfo,
+ &ClientConnect->ConnectionInfoSize);
+ }
+ else
+ {
+ /* Assume success */
+ Status = STATUS_SUCCESS;
+ }
+
+ /* Return status */
+ return Status;
+}
+
+/*++
+ * @name CsrSrvCreateSharedSection
+ *
+ * The CsrSrvCreateSharedSection creates the Shared Section that all CSR Server
+ * DLLs and Clients can use to share data.
+ *
+ * @param ParameterValue
+ * Specially formatted string from our registry command-line which
+ * specifies various arguments for the shared section.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSrvCreateSharedSection(IN PCHAR ParameterValue)
+{
+ PCHAR SizeValue = ParameterValue;
+ ULONG Size;
+ NTSTATUS Status;
+ LARGE_INTEGER SectionSize;
+ ULONG ViewSize = 0;
+ PPEB Peb = NtCurrentPeb();
+
+ /* If there's no parameter, fail */
+ if (!ParameterValue) return STATUS_INVALID_PARAMETER;
+
+ /* Find the first comma, and null terminate */
+ while (*SizeValue)
+ {
+ if (*SizeValue == ',')
+ {
+ *SizeValue++ = ANSI_NULL;
+ break;
+ }
+ else
+ {
+ SizeValue++;
+ }
+ }
+
+ /* Make sure it's valid */
+ if (!*SizeValue) return STATUS_INVALID_PARAMETER;
+
+ /* Convert it to an integer */
+ Status = RtlCharToInteger(SizeValue, 0, &Size);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Multiply by 1024 entries and round to page size */
+ CsrSrvSharedSectionSize = ROUND_UP(Size * 1024, CsrNtSysInfo.PageSize);
+
+ /* Create the Secion */
+ SectionSize.LowPart = CsrSrvSharedSectionSize;
+ SectionSize.HighPart = 0;
+ Status = NtCreateSection(&CsrSrvSharedSection,
+ SECTION_ALL_ACCESS,
+ NULL,
+ &SectionSize,
+ PAGE_EXECUTE_READWRITE,
+ SEC_BASED | SEC_RESERVE,
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Map the section */
+ Status = NtMapViewOfSection(CsrSrvSharedSection,
+ NtCurrentProcess(),
+ &CsrSrvSharedSectionBase,
+ 0,
+ 0,
+ NULL,
+ &ViewSize,
+ ViewUnmap,
+ MEM_TOP_DOWN,
+ PAGE_EXECUTE_READWRITE);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ NtClose(CsrSrvSharedSection);
+ return Status;
+ }
+
+ /* FIXME: Write the value to registry */
+
+ /* The Heap is the same place as the Base */
+ CsrSrvSharedSectionHeap = CsrSrvSharedSectionBase;
+
+ /* Create the heap */
+ if (!(RtlCreateHeap(HEAP_ZERO_MEMORY | HEAP_CLASS_7,
+ CsrSrvSharedSectionHeap,
+ CsrSrvSharedSectionSize,
+ PAGE_SIZE,
+ 0,
+ 0)))
+ {
+ /* Failure, unmap section and return */
+ NtUnmapViewOfSection(NtCurrentProcess(), CsrSrvSharedSectionBase);
+ NtClose(CsrSrvSharedSection);
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Now allocate space from the heap for the Shared Data */
+ CsrSrvSharedStaticServerData = RtlAllocateHeap(CsrSrvSharedSectionHeap,
+ 0,
+ CSR_SERVER_DLL_MAX *
+ sizeof(PVOID));
+ if (!CsrSrvSharedStaticServerData) return STATUS_NO_MEMORY;
+
+ /* Write the values to the PEB */
+ Peb->ReadOnlySharedMemoryBase = CsrSrvSharedSectionBase;
+ Peb->ReadOnlySharedMemoryHeap = CsrSrvSharedSectionHeap;
+ Peb->ReadOnlyStaticServerData = CsrSrvSharedStaticServerData;
+
+ /* Return */
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrSrvAttachSharedSection
+ *
+ * The CsrSrvAttachSharedSection maps the CSR Shared Section into a new
+ * CSR Process' address space, and returns the pointers to the section
+ * through the Connection Info structure.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process that is attempting a connection.
+ *
+ * @param ConnectInfo
+ * Pointer to the CSR Connection Info structure for the incoming
+ * connection.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSrvAttachSharedSection(IN PCSR_PROCESS CsrProcess OPTIONAL,
+ OUT PCSR_CONNECTION_INFO ConnectInfo)
+{
+ NTSTATUS Status;
+ ULONG ViewSize = 0;
+
+ /* Check if we have a process */
+ if (CsrProcess)
+ {
+ /* Map the sectio into this process */
+ Status = NtMapViewOfSection(CsrSrvSharedSection,
+ CsrProcess->ProcessHandle,
+ &CsrSrvSharedSectionBase,
+ 0,
+ 0,
+ NULL,
+ &ViewSize,
+ ViewUnmap,
+ SEC_NO_CHANGE,
+ PAGE_EXECUTE_READ);
+ if (!NT_SUCCESS(Status)) return Status;
+ }
+
+ /* Write the values in the Connection Info structure */
+ ConnectInfo->SharedSectionBase = CsrSrvSharedSectionBase;
+ ConnectInfo->SharedSectionHeap = CsrSrvSharedSectionHeap;
+ ConnectInfo->SharedSectionData = CsrSrvSharedStaticServerData;
+
+ /* Return success */
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrSrvIdentifyAlertableThread
+ * @implemented NT4
+ *
+ * The CsrSrvIdentifyAlertableThread CSR API marks a CSR Thread as alertable.
+ *
+ * @param ApiMessage
+ * Pointer to the CSR API Message for this request.
+ *
+ * @param Reply
+ * Pointer to an optional reply to this request.
+ *
+ * @return STATUS_SUCCESS.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSrvIdentifyAlertableThread(IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply)
+{
+ PCSR_THREAD CsrThread = NtCurrentTeb()->CsrClientThread;
+
+ /* Set the alertable flag */
+ CsrThread->Flags |= CsrThreadAltertable;
+
+ /* Return success */
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrSrvSetPriorityClass
+ * @implemented NT4
+ *
+ * The CsrSrvSetPriorityClass CSR API is deprecated.
+ *
+ * @param ApiMessage
+ * Pointer to the CSR API Message for this request.
+ *
+ * @param Reply
+ * Pointer to an optional reply to this request.
+ *
+ * @return STATUS_SUCCESS.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSrvSetPriorityClass(IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply)
+{
+ /* Deprecated */
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrSrvUnusedFunction
+ * @implemented NT4
+ *
+ * The CsrSrvUnusedFunction CSR API is a stub for deprecated APIs.
+ *
+ * The CsrSrvSetPriorityClass CSR API is deprecated.
+ *
+ * @param ApiMessage
+ * Pointer to the CSR API Message for this request.
+ *
+ * @param Reply
+ * Pointer to an optional reply to this request.
+ *
+ * @return STATUS_INVALID_PARAMETER.
+ *
+ * @remarks CsrSrvSetPriorityClass does not use this stub because it must
+ * return success.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSrvUnusedFunction(IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply)
+{
+ /* Deprecated */
+ return STATUS_INVALID_PARAMETER;
+}
+
+/* PUBLIC FUNCTIONS***********************************************************/
+
+/*++
+ * @name CsrSetCallingSpooler
+ * @implemented NT4
+ *
+ * the CsrSetCallingSpooler routine is deprecated.
+ *
+ * @param Reserved
+ * Deprecated
+ *
+ * @return None.
+ *
+ * @remarks This routine was used in archaic versions of NT for Printer Drivers.
+ *
+ *--*/
+VOID
+NTAPI
+CsrSetCallingSpooler(ULONG Reserved)
+{
+ /* Deprecated */
+ return;
+}
+
+/*++
+ * @name CsrUnhandledExceptionFilter
+ * @implemented NT5
+ *
+ * The CsrUnhandledExceptionFilter routine handles all exceptions
+ * within SEH-protected blocks.
+ *
+ * @param ExceptionPointers
+ * System-defined Argument.
+ *
+ * @return EXCEPTION_EXECUTE_HANDLER.
+ *
+ * @remarks None.
+ *
+ *--*/
+LONG
+NTAPI
+CsrUnhandledExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo)
+{
+ SYSTEM_KERNEL_DEBUGGER_INFORMATION DebuggerInfo;
+ EXCEPTION_DISPOSITION Result = EXCEPTION_EXECUTE_HANDLER;
+ BOOLEAN OldValue;
+ NTSTATUS Status;
+ UNICODE_STRING ErrorSource;
+ ULONG_PTR ErrorParameters[4];
+ ULONG Response;
+
+ /* Check if a debugger is installed */
+ Status = NtQuerySystemInformation(SystemKernelDebuggerInformation,
+ &DebuggerInfo,
+ sizeof(DebuggerInfo),
+ NULL);
+
+ /* Check if this is Session 0, and the Debugger is Enabled */
+ if ((NtCurrentPeb()->SessionId) && (NT_SUCCESS(Status)) &&
+ (DebuggerInfo.KernelDebuggerEnabled))
+ {
+ /* Call the Unhandled Exception Filter */
+ if ((Result = RtlUnhandledExceptionFilter(ExceptionInfo)) !=
+ EXCEPTION_CONTINUE_EXECUTION)
+ {
+ /* We're going to raise an error. Get Shutdown Privilege first */
+ Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
+ TRUE,
+ TRUE,
+ &OldValue);
+
+ /* Use the Process token if that failed */
+ if (Status == STATUS_NO_TOKEN)
+ {
+ Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
+ TRUE,
+ FALSE,
+ &OldValue);
+ }
+
+ /* Initialize our Name String */
+ RtlInitUnicodeString(&ErrorSource, L"Windows SubSystem");
+
+ /* Set the parameters */
+ ErrorParameters[0] = (ULONG_PTR)&ErrorSource;
+ ErrorParameters[1] = ExceptionInfo->ExceptionRecord->ExceptionCode;
+ ErrorParameters[2] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress;
+ ErrorParameters[3] = (ULONG_PTR)ExceptionInfo->ContextRecord;
+
+ /* Bugcheck */
+ Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
+ 4,
+ 1,
+ ErrorParameters,
+ OptionShutdownSystem,
+ &Response);
+ }
+
+ /* Just terminate us */
+ NtTerminateProcess(NtCurrentProcess(),
+ ExceptionInfo->ExceptionRecord->ExceptionCode);
+ }
+
+ return Result;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CSR Sub System
+ * FILE: subsys/csr/csrsrv/session.c
+ * PURPOSE: CSR Server DLL Session Implementation
+ * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "srv.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* DATA **********************************************************************/
+
+RTL_CRITICAL_SECTION CsrNtSessionLock;
+LIST_ENTRY CsrNtSessionList;
+HANDLE CsrSmApiPort;
+
+PSB_API_ROUTINE CsrServerSbApiDispatch[5] =
+{
+ CsrSbCreateSession,
+ CsrSbTerminateSession,
+ CsrSbForeignSessionComplete,
+ CsrSbCreateProcess,
+ NULL
+};
+
+PCHAR CsrServerSbApiName[5] =
+{
+ "SbCreateSession",
+ "SbTerminateSession",
+ "SbForeignSessionComplete",
+ "SbCreateProcess",
+ "Unknown Csr Sb Api Number"
+};
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+/*++
+ * @name CsrInitializeNtSessionList
+ *
+ * The CsrInitializeNtSessionList routine sets up support for CSR Sessions.
+ *
+ * @param None
+ *
+ * @return None
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrInitializeNtSessionList(VOID)
+{
+ DPRINT("CSRSRV: %s called\n", __FUNCTION__);
+
+ /* Initialize the Session List */
+ InitializeListHead(&CsrNtSessionList);
+
+ /* Initialize the Session Lock */
+ return RtlInitializeCriticalSection(&CsrNtSessionLock);
+}
+
+/*++
+ * @name CsrAllocateNtSession
+ *
+ * The CsrAllocateNtSession routine allocates a new CSR NT Session.
+ *
+ * @param SessionId
+ * Session ID of the CSR NT Session to allocate.
+ *
+ * @return Pointer to the newly allocated CSR NT Session.
+ *
+ * @remarks None.
+ *
+ *--*/
+PCSR_NT_SESSION
+NTAPI
+CsrAllocateNtSession(IN ULONG SessionId)
+{
+ PCSR_NT_SESSION NtSession;
+
+ /* Allocate an NT Session Object */
+ NtSession = RtlAllocateHeap(CsrHeap, 0, sizeof(CSR_NT_SESSION));
+ if (NtSession)
+ {
+ /* Setup the Session Object */
+ NtSession->SessionId = SessionId;
+ NtSession->ReferenceCount = 1;
+
+ /* Insert it into the Session List */
+ CsrAcquireNtSessionLock();
+ InsertHeadList(&CsrNtSessionList, &NtSession->SessionLink);
+ CsrReleaseNtSessionLock();
+ }
+ else
+ {
+ ASSERT(NtSession != NULL);
+ }
+
+ /* Return the Session (or NULL) */
+ return NtSession;
+}
+
+/*++
+ * @name CsrReferenceNtSession
+ *
+ * The CsrReferenceNtSession increases the reference count of a CSR NT Session.
+ *
+ * @param Session
+ * Pointer to the CSR NT Session to reference.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrReferenceNtSession(IN PCSR_NT_SESSION Session)
+{
+ /* Acquire the lock */
+ CsrAcquireNtSessionLock();
+
+ /* Sanity checks */
+ ASSERT(!IsListEmpty(&Session->SessionLink));
+ ASSERT(Session->SessionId != 0);
+ ASSERT(Session->ReferenceCount != 0);
+
+ /* Increase the reference count */
+ Session->ReferenceCount++;
+
+ /* Release the lock */
+ CsrReleaseNtSessionLock();
+}
+
+/*++
+ * @name CsrDereferenceNtSession
+ *
+ * The CsrDereferenceNtSession decreases the reference count of a
+ * CSR NT Session.
+ *
+ * @param Session
+ * Pointer to the CSR NT Session to reference.
+ *
+ * @param ExitStatus
+ * If this is the last reference to the session, this argument
+ * specifies the exit status.
+ *
+ * @return None.
+ *
+ * @remarks CsrDereferenceNtSession will complete the session if
+ * the last reference to it has been closed.
+ *
+ *--*/
+VOID
+NTAPI
+CsrDereferenceNtSession(IN PCSR_NT_SESSION Session,
+ IN NTSTATUS ExitStatus)
+{
+ /* Acquire the lock */
+ CsrAcquireNtSessionLock();
+
+ /* Sanity checks */
+ ASSERT(!IsListEmpty(&Session->SessionLink));
+ ASSERT(Session->SessionId != 0);
+ ASSERT(Session->ReferenceCount != 0);
+
+ /* Dereference the Session Object */
+ if (!(--Session->ReferenceCount))
+ {
+ /* Remove it from the list */
+ RemoveEntryList(&Session->SessionLink);
+
+ /* Release the lock */
+ CsrReleaseNtSessionLock();
+
+ /* Tell SM that we're done here */
+ SmSessionComplete(CsrSmApiPort, Session->SessionId, ExitStatus);
+
+ /* Free the Session Object */
+ RtlFreeHeap(CsrHeap, 0, Session);
+ }
+ else
+ {
+ /* Release the lock, the Session is still active */
+ CsrReleaseNtSessionLock();
+ }
+}
+
+
+/* SESSION MANAGER FUNCTIONS**************************************************/
+
+/*++
+ * @name CsrSbCreateSession
+ *
+ * The CsrSbCreateSession API is called by the Session Manager whenever a new
+ * session is created.
+ *
+ * @param ApiMessage
+ * Pointer to the Session Manager API Message.
+ *
+ * @return TRUE in case of success, FALSE othwerwise.
+ *
+ * @remarks The CsrSbCreateSession routine will initialize a new CSR NT
+ * Session and allocate a new CSR Process for the subsystem process.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrSbCreateSession(IN PSB_API_MSG ApiMessage)
+{
+ PSB_CREATE_SESSION_MSG CreateSession = &ApiMessage->CreateSession;
+ HANDLE hProcess, hThread;
+ PCSR_PROCESS CsrProcess;
+ NTSTATUS Status;
+ KERNEL_USER_TIMES KernelTimes;
+ PCSR_THREAD CsrThread;
+ PVOID ProcessData;
+ ULONG i;
+
+ /* Save the Process and Thread Handles */
+ hProcess = CreateSession->ProcessInfo.ProcessHandle;
+ hThread = CreateSession->ProcessInfo.ThreadHandle;
+
+ /* Lock the Processes */
+ CsrAcquireProcessLock();
+
+ /* Allocate a new process */
+ CsrProcess = CsrAllocateProcess();
+ if (!CsrProcess)
+ {
+ /* Fail */
+ ApiMessage->ReturnValue = STATUS_NO_MEMORY;
+ CsrReleaseProcessLock();
+ return TRUE;
+ }
+
+ /* Set the exception port */
+ Status = NtSetInformationProcess(hProcess,
+ ProcessExceptionPort,
+ &CsrApiPort,
+ sizeof(HANDLE));
+
+ /* Check for success */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail the request */
+ CsrDeallocateProcess(CsrProcess);
+ CsrReleaseProcessLock();
+
+ /* Strange as it seems, NTSTATUSes are actually returned */
+ return (BOOLEAN)STATUS_NO_MEMORY;
+ }
+
+ /* Get the Create Time */
+ Status = NtQueryInformationThread(hThread,
+ ThreadTimes,
+ &KernelTimes,
+ sizeof(KERNEL_USER_TIMES),
+ NULL);
+
+ /* Check for success */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail the request */
+ CsrDeallocateProcess(CsrProcess);
+ CsrReleaseProcessLock();
+
+ /* Strange as it seems, NTSTATUSes are actually returned */
+ return (BOOLEAN)Status;
+ }
+
+ /* Allocate a new Thread */
+ CsrThread = CsrAllocateThread(CsrProcess);
+ if (!CsrThread)
+ {
+ /* Fail the request */
+ CsrDeallocateProcess(CsrProcess);
+ ApiMessage->ReturnValue = STATUS_NO_MEMORY;
+ CsrReleaseProcessLock();
+ return TRUE;
+ }
+
+ /* Setup the Thread Object */
+ CsrThread->CreateTime = KernelTimes.CreateTime;
+ CsrThread->ClientId = CreateSession->ProcessInfo.ClientId;
+ CsrThread->ThreadHandle = hThread;
+ ProtectHandle(hThread);
+ CsrThread->Flags = 0;
+
+ /* Insert it into the Process List */
+ CsrInsertThread(CsrProcess, CsrThread);
+
+ /* Setup Process Data */
+ CsrProcess->ClientId = CreateSession->ProcessInfo.ClientId;
+ CsrProcess->ProcessHandle = hProcess;
+ CsrProcess->NtSession = CsrAllocateNtSession(CreateSession->SessionId);
+
+ /* Set the Process Priority */
+ CsrSetBackgroundPriority(CsrProcess);
+
+ /* Get the first data location */
+ ProcessData = &CsrProcess->ServerData[CSR_SERVER_DLL_MAX];
+
+ /* Loop every DLL */
+ for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+ {
+ /* Check if the DLL is loaded and has Process Data */
+ if (CsrLoadedServerDll[i] && CsrLoadedServerDll[i]->SizeOfProcessData)
+ {
+ /* Write the pointer to the data */
+ CsrProcess->ServerData[i] = ProcessData;
+
+ /* Move to the next data location */
+ ProcessData = (PVOID)((ULONG_PTR)ProcessData +
+ CsrLoadedServerDll[i]->SizeOfProcessData);
+ }
+ else
+ {
+ /* Nothing for this Process */
+ CsrProcess->ServerData[i] = NULL;
+ }
+ }
+
+ /* Insert the Process */
+ CsrInsertProcess(NULL, NULL, CsrProcess);
+
+ /* Activate the Thread */
+ ApiMessage->ReturnValue = NtResumeThread(hThread, NULL);
+
+ /* Release lock and return */
+ CsrReleaseProcessLock();
+ return TRUE;
+}
+
+/*++
+ * @name CsrSbForeignSessionComplete
+ *
+ * The CsrSbForeignSessionComplete API is called by the Session Manager
+ * whenever a foreign session is completed (ie: terminated).
+ *
+ * @param ApiMessage
+ * Pointer to the Session Manager API Message.
+ *
+ * @return TRUE in case of success, FALSE othwerwise.
+ *
+ * @remarks The CsrSbForeignSessionComplete API is not yet implemented.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrSbForeignSessionComplete(IN PSB_API_MSG ApiMessage)
+{
+ /* Deprecated/Unimplemented in NT */
+ ApiMessage->ReturnValue = STATUS_NOT_IMPLEMENTED;
+ return TRUE;
+}
+
+/*++
+ * @name CsrSbTerminateSession
+ *
+ * The CsrSbTerminateSession API is called by the Session Manager
+ * whenever a foreign session should be destroyed.
+ *
+ * @param ApiMessage
+ * Pointer to the Session Manager API Message.
+ *
+ * @return TRUE in case of success, FALSE othwerwise.
+ *
+ * @remarks The CsrSbTerminateSession API is not yet implemented.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrSbTerminateSession(IN PSB_API_MSG ApiMessage)
+{
+ ApiMessage->ReturnValue = STATUS_NOT_IMPLEMENTED;
+ return TRUE;
+}
+
+/*++
+ * @name CsrSbCreateProcess
+ *
+ * The CsrSbCreateProcess API is called by the Session Manager
+ * whenever a foreign session is created and a new process should be started.
+ *
+ * @param ApiMessage
+ * Pointer to the Session Manager API Message.
+ *
+ * @return TRUE in case of success, FALSE othwerwise.
+ *
+ * @remarks The CsrSbCreateProcess API is not yet implemented.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrSbCreateProcess(IN PSB_API_MSG ApiMessage)
+{
+ ApiMessage->ReturnValue = STATUS_NOT_IMPLEMENTED;
+ return TRUE;
+}
+
+/* EOF */
--- /dev/null
+#ifndef _SRV_H
+#define _SRV_H
+
+/* PSDK/NDK Headers */
+#define NTOS_MODE_USER
+#include <stdio.h>
+#define WIN32_NO_STATUS
+#include <windows.h>
+#include <winnt.h>
+#include <ndk/ntndk.h>
+
+/* CSR Header */
+#include <csr/server.h>
+#include <sm/smmsg.h>
+
+/* PSEH for SEH Support */
+#include <pseh/pseh2.h>
+
+/* DEFINES *******************************************************************/
+
+#define CSR_SERVER_DLL_MAX 4
+
+#define CsrAcquireProcessLock() \
+ RtlEnterCriticalSection(&CsrProcessLock);
+
+#define CsrReleaseProcessLock() \
+ RtlLeaveCriticalSection(&CsrProcessLock);
+
+#define CsrAcquireWaitLock() \
+ RtlEnterCriticalSection(&CsrWaitListsLock);
+
+#define CsrReleaseWaitLock() \
+ RtlLeaveCriticalSection(&CsrWaitListsLock);
+
+#define CsrAcquireNtSessionLock() \
+ RtlEnterCriticalSection(&CsrNtSessionLock)
+
+#define CsrReleaseNtSessionLock() \
+ RtlLeaveCriticalSection(&CsrNtSessionLock)
+
+#define CsrHashThread(t) \
+ (HandleToUlong(t)&(256 - 1))
+
+#define ProcessStructureListLocked() \
+ (CsrProcessLock.OwningThread == NtCurrentTeb()->ClientId.UniqueThread)
+
+#define SM_REG_KEY \
+ L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager"
+
+#define SESSION_ROOT L"\\Sessions"
+#define GLOBAL_ROOT L"\\GLOBAL??"
+#define SYMLINK_NAME L"SymbolicLink"
+#define SB_PORT_NAME L"SbAbiPort"
+#define CSR_PORT_NAME L"ApiPort"
+#define UNICODE_PATH_SEP L"\\"
+
+#define ROUND_UP(n, align) ROUND_DOWN(((ULONG)n) + (align) - 1, (align))
+#define ROUND_DOWN(n, align) (((ULONG)n) & ~((align) - 1l))
+
+/* DATA **********************************************************************/
+
+extern ULONG CsrTotalPerProcessDataLength;
+extern ULONG CsrMaxApiRequestThreads;
+extern PCSR_SERVER_DLL CsrLoadedServerDll[CSR_SERVER_DLL_MAX];
+extern PCSR_PROCESS CsrRootProcess;
+extern UNICODE_STRING CsrSbApiPortName;
+extern UNICODE_STRING CsrApiPortName;
+extern HANDLE CsrSbApiPort;
+extern HANDLE CsrSmApiPort;
+extern HANDLE CsrApiPort;
+extern HANDLE CsrHeap;
+extern RTL_CRITICAL_SECTION CsrProcessLock;
+extern RTL_CRITICAL_SECTION CsrWaitListsLock;
+extern LIST_ENTRY CsrThreadHashTable[256];
+extern HANDLE CsrInitializationEvent;
+extern SYSTEM_BASIC_INFORMATION CsrNtSysInfo;
+extern UNICODE_STRING CsrDirectoryName;
+extern HANDLE CsrObjectDirectory;
+extern PSB_API_ROUTINE CsrServerSbApiDispatch[5];
+extern ULONG CsrDebug;
+
+/* FUNCTIONS *****************************************************************/
+
+/* FIXME: Public APIs should go in the CSR Server Include */
+BOOLEAN
+NTAPI
+CsrCaptureArguments(
+ IN PCSR_THREAD CsrThread,
+ IN PCSR_API_MESSAGE ApiMessage
+);
+
+NTSTATUS
+NTAPI
+CsrLoadServerDll(
+ IN PCHAR DllString,
+ IN PCHAR EntryPoint,
+ IN ULONG ServerId
+);
+
+NTSTATUS
+NTAPI
+CsrServerInitialization(
+ ULONG ArgumentCount,
+ PCHAR Arguments[]
+);
+
+BOOLEAN
+NTAPI
+UnProtectHandle(IN HANDLE ObjectHandle);
+
+VOID
+NTAPI
+CsrLockedReferenceProcess(IN PCSR_PROCESS CsrProcess);
+
+VOID
+NTAPI
+CsrLockedReferenceThread(IN PCSR_THREAD CsrThread);
+
+NTSTATUS
+NTAPI
+CsrCreateSessionObjectDirectory(IN ULONG SessionId);
+
+NTSTATUS
+NTAPI
+CsrCreateObjectDirectory(IN PCHAR ObjectDirectory);
+
+NTSTATUS
+NTAPI
+CsrSrvCreateSharedSection(IN PCHAR ParameterValue);
+
+NTSTATUS
+NTAPI
+CsrInitializeNtSessionList(VOID);
+
+NTSTATUS
+NTAPI
+CsrInitializeProcessStructure(VOID);
+
+NTSTATUS
+NTAPI
+CsrApiPortInitialize(VOID);
+
+NTSTATUS
+NTAPI
+CsrSbApiPortInitialize(VOID);
+
+BOOLEAN
+NTAPI
+CsrSbCreateSession(IN PSB_API_MSG ApiMessage);
+
+BOOLEAN
+NTAPI
+CsrSbTerminateSession(IN PSB_API_MSG ApiMessage);
+
+BOOLEAN
+NTAPI
+CsrSbForeignSessionComplete(IN PSB_API_MSG ApiMessage);
+
+BOOLEAN
+NTAPI
+CsrSbCreateProcess(IN PSB_API_MSG ApiMessage);
+
+PCSR_PROCESS
+NTAPI
+CsrAllocateProcess(VOID);
+
+PCSR_THREAD
+NTAPI
+CsrAllocateThread(IN PCSR_PROCESS CsrProcess);
+
+VOID
+NTAPI
+CsrInsertThread(
+ IN PCSR_PROCESS Process,
+ IN PCSR_THREAD Thread
+);
+
+VOID
+NTAPI
+CsrSetBackgroundPriority(IN PCSR_PROCESS CsrProcess);
+
+VOID
+NTAPI
+CsrDeallocateProcess(IN PCSR_PROCESS CsrProcess);
+
+NTSTATUS
+NTAPI
+CsrGetProcessLuid(
+ HANDLE hProcess,
+ PLUID Luid
+);
+
+BOOLEAN
+NTAPI
+CsrImpersonateClient(IN PCSR_THREAD CsrThread);
+
+BOOLEAN
+NTAPI
+CsrRevertToSelf(VOID);
+
+PCSR_THREAD
+NTAPI
+CsrLocateThreadByClientId(
+ OUT PCSR_PROCESS *Process,
+ IN PCLIENT_ID ClientId
+);
+
+VOID
+NTAPI
+CsrDereferenceNtSession(
+ IN PCSR_NT_SESSION Session,
+ NTSTATUS ExitStatus
+);
+
+VOID
+NTAPI
+CsrReferenceNtSession(PCSR_NT_SESSION Session);
+
+VOID
+NTAPI
+CsrLockedDereferenceThread(PCSR_THREAD CsrThread);
+
+VOID
+NTAPI
+CsrLockedDereferenceProcess(PCSR_PROCESS CsrProcess);
+
+NTSTATUS
+NTAPI
+CsrLockProcessByClientId(
+ IN HANDLE Pid,
+ OUT PCSR_PROCESS *CsrProcess OPTIONAL
+);
+
+NTSTATUS
+NTAPI
+CsrUnlockProcess(PCSR_PROCESS CsrProcess);
+
+NTSTATUS
+NTAPI
+CsrSrvClientConnect(
+ IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply
+);
+
+NTSTATUS
+NTAPI
+CsrSrvUnusedFunction(
+ IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply
+);
+
+NTSTATUS
+NTAPI
+CsrSrvIdentifyAlertableThread(
+ IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply
+);
+
+NTSTATUS
+NTAPI
+CsrSrvSetPriorityClass(
+ IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply
+);
+
+NTSTATUS
+NTAPI
+CsrServerDllInitialization(IN PCSR_SERVER_DLL LoadedServerDll);
+
+VOID
+NTAPI
+CsrDereferenceThread(PCSR_THREAD CsrThread);
+
+VOID
+NTAPI
+CsrSbApiRequestThread(IN PVOID Parameter);
+
+NTSTATUS
+NTAPI
+CsrApiRequestThread(IN PVOID Parameter);
+
+BOOLEAN
+NTAPI
+ProtectHandle(IN HANDLE ObjectHandle);
+
+PCSR_THREAD
+NTAPI
+CsrAddStaticServerThread(
+ IN HANDLE hThread,
+ IN PCLIENT_ID ClientId,
+ IN ULONG ThreadFlags
+);
+
+PCSR_THREAD
+NTAPI
+CsrConnectToUser(VOID);
+
+PCSR_THREAD
+NTAPI
+CsrLocateThreadInProcess(
+ IN PCSR_PROCESS CsrProcess OPTIONAL,
+ IN PCLIENT_ID Cid
+);
+
+NTSTATUS
+NTAPI
+CsrSbApiHandleConnectionRequest(IN PSB_API_MSG Message);
+
+NTSTATUS
+NTAPI
+CsrApiHandleConnectionRequest(IN PCSR_API_MESSAGE ApiMessage);
+
+NTSTATUS
+NTAPI
+CsrSrvAttachSharedSection(
+ IN PCSR_PROCESS CsrProcess OPTIONAL,
+ OUT PCSR_CONNECTION_INFO ConnectInfo
+);
+
+VOID
+NTAPI
+CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage);
+
+BOOLEAN
+NTAPI
+CsrNotifyWaitBlock(
+ IN PCSR_WAIT_BLOCK WaitBlock,
+ IN PLIST_ENTRY WaitList,
+ IN PVOID WaitArgument1,
+ IN PVOID WaitArgument2,
+ IN ULONG WaitFlags,
+ IN BOOLEAN DereferenceThread
+);
+
+VOID
+NTAPI
+CsrDereferenceProcess(PCSR_PROCESS CsrProcess);
+
+VOID
+NTAPI
+CsrInsertProcess(
+ IN PCSR_PROCESS Parent OPTIONAL,
+ IN PCSR_PROCESS CurrentProcess OPTIONAL,
+ IN PCSR_PROCESS CsrProcess
+);
+
+NTSTATUS
+NTAPI
+CsrPopulateDosDevicesDirectory(
+ IN HANDLE DosDevicesDirectory,
+ IN PPROCESS_DEVICEMAP_INFORMATION DeviceMap
+);
+
+BOOLEAN
+NTAPI
+CsrValidateMessageBuffer(
+ IN PCSR_API_MESSAGE ApiMessage,
+ IN PVOID *Buffer,
+ IN ULONG ArgumentSize,
+ IN ULONG ArgumentCount
+);
+
+NTSTATUS
+NTAPI
+CsrCreateLocalSystemSD(OUT PSECURITY_DESCRIPTOR *LocalSystemSd);
+
+NTSTATUS
+NTAPI
+CsrDestroyThread(IN PCLIENT_ID Cid);
+
+NTSTATUS
+NTAPI
+CsrDestroyProcess(
+ IN PCLIENT_ID Cid,
+ IN NTSTATUS ExitStatus
+);
+
+LONG
+NTAPI
+CsrUnhandledExceptionFilter(
+ IN PEXCEPTION_POINTERS ExceptionInfo
+);
+
+VOID
+NTAPI
+CsrProcessRefcountZero(IN PCSR_PROCESS CsrProcess);
+
+VOID
+NTAPI
+CsrThreadRefcountZero(IN PCSR_THREAD CsrThread);
+
+NTSTATUS
+NTAPI
+CsrSetDirectorySecurity(IN HANDLE ObjectDirectory);
+#endif
--- /dev/null
+/*
+ * CSRSRV Status
+ */
+
+/* Organization
+ *
+ * api.c - Handles the LPC Reply/Request Threads which wait on Sb and Csr APIs.
+ * Also in charge of creating those threads and setting up the ports.
+ * Finally, it provides external APIs for validating the API buffers
+ * and doing server-to-server API calls.
+ *
+ * init.c - Handles initialization of CSRSRV, including command-line parsing,
+ * loading the Server DLLs, creating the Session Directories, setting
+ * up the DosDevices Object Directory, and initializing each component.
+ *
+ * process.c - Handles all internal functions dealing with the CSR Process Object,
+ * including de/allocation, de/referencing, un/locking, prority, and
+ * lookups. Also handles all external APIs which touch the CSR Process Object.
+ *
+ * server.c - Handles all internal functions related to loading and managing Server
+ * DLLs, as well as the routines handling the Shared Static Memory Section.
+ * Holds the API Dispatch/Valid/Name Tables and the public CSR_SERVER API
+ * interface. Also home of the SEH handler.
+ *
+ * session.c - Handles all internal functions dealing with the CSR Session Object,
+ * including de/allocation, de/referencing, and un/locking. Holds the SB API
+ * Dispatch/Name Tables and the public CsrSv API Interface for commmunication
+ * with the Session Manager.
+ *
+ * thread.c - Handles all internal functions dealing with the CSR Thread Object,
+ * including de/allocation, de/referencing, un/locking, impersonation, and
+ * lookups. Also handles all external APIs which touch the CSR Thread Object.
+ *
+ * wait.c - Handles all internal functions dealing with the CSR Wait Object,
+ * including de/allocation, de/referencing and un/locking. Also implements
+ * the external Wait API for creating, removing and/or notifying waits.
+ */
+
+/* Exported APIs, their location, and their status
+ * CsrAddStaticServerThread 753E679E 1 - server.c - IMPLEMENTED
+ * CsrCallServerFromServer 753E4FD9 2 - api.c - IMPLEMENTED
+ * CsrConnectToUser 753E4E48 3 - api.c - IMPLEMENTED
+ * CsrCreateProcess 753E6FD3 4 - process.c - IMPLEMENTED
+ * CsrCreateRemoteThread 753E73BD 5 - thread.c - IMPLEMENTED
+ * CsrCreateThread 753E72DA 6 - thread.c - IMPLEMENTED
+ * CsrCreateWait 753E770E 7 - wait.c - IMPLEMENTED
+ * CsrDebugProcess 753E7682 8 - process.c - IMPLEMENTED
+ * CsrDebugProcessStop 753E768A 9 - process.c - IMPLEMENTED
+ * CsrDereferenceProcess 753E6281 10 - process.c - IMPLEMENTED
+ * CsrDereferenceThread 753E6964 11 - thread.c - IMPLEMENTED
+ * CsrDereferenceWait 753E7886 12 - wait.c - IMPLEMENTED
+ * CsrDestroyProcess 753E7225 13 - process.c - IMPLEMENTED
+ * CsrDestroyThread 753E7478 14 - thread.c - IMPLEMENTED
+ * CsrExecServerThread 753E6841 15 - thread.c - IMPLEMENTED
+ * CsrGetProcessLuid 753E632F 16 - process.c - IMPLEMENTED
+ * CsrImpersonateClient 753E60F8 17 - thread.c - IMPLEMENTED
+ * CsrLockProcessByClientId 753E668F 18 - process.c - IMPLEMENTED
+ * CsrLockThreadByClientId 753E6719 19 - thread.c - IMPLEMENTED
+ * CsrMoveSatisfiedWait 753E7909 20 - wait.c - IMPLEMENTED
+ * CsrNotifyWait 753E782F 21 - wait.c - IMPLEMENTED
+ * CsrPopulateDosDevices 753E37A5 22 - init.c - IMPLEMENTED
+ * CsrQueryApiPort 753E4E42 23 - api.c - IMPLEMENTED
+ * CsrReferenceThread 753E61E5 24 - thread.c - IMPLEMENTED
+ * CsrRevertToSelf 753E615A 25 - thread.c - IMPLEMENTED
+ * CsrServerInitialization 753E3D75 26 - server.c - IMPLEMENTED
+ * CsrSetBackgroundPriority 753E5E87 27 - process.c - IMPLEMENTED
+ * CsrSetCallingSpooler 753E6425 28 - server.c - IMPLEMENTED
+ * CsrSetForegroundPriority 753E5E67 29 - process.c - IMPLEMENTED
+ * CsrShutdownProcesses 753E7547 30 - process.c - IMPLEMENTED
+ * CsrUnhandledExceptionFilter 753E3FE3 31 - server.c - IMPLEMENTED
+ * CsrUnlockProcess 753E66FD 32 - process.c - IMPLEMENTED
+ * CsrUnlockThread 753E7503 33 - thread.c - IMPLEMENTED
+ * CsrValidateMessageBuffer 753E528D 34 - api.c - IMPLEMENTED
+ * CsrValidateMessageString 753E5323 35 - api.c - UNIMPLEMENTED
+ */
+
+/* Public CSR API Interface Status (server.c)
+ * CsrSrvClientConnect - IMPLEMENTED
+ * CsrSrvUnusedFunction - IMPLEMENTED
+ * CsrSrvIdentifyAlertableThread - IMPLEMENTED
+ * CsrSrvSetPriorityClass - IMPLEMENTED
+ */
+
+/* Public SB API Interface Status (session.c)
+ * CsrSbCreateSession - IMPLEMENTED
+ * CsrSbForeignSessionComplete - IMPLEMENTED
+ * CsrSbTerminateSession - UNIMPLEMENTED
+ * CsrSbCreateProcess - UNIMPLEMENTED
+ */
+
+/* What's missing:
+ *
+ * - SMSS needs to be partly re-written to match some things done here.
+ * Among other things, SmConnectToSm, SmCompleteSession and the other
+ * Sm* Exported APIs have to be properly implemented, as well as the
+ * callback calling and SM LPC APIs. [DONE!]
+ *
+ * - NTDLL needs to get the Csr* routines properly implemented. [DONE!]
+ *
+ * - KERNEL32, USER32 need to register with their servers properly.
+ * Additionally, user32 needs to have ClientThreadStartup implemented
+ * properly and do the syscall NtUserInitialize (I think) which also
+ * needs to be implemented in win32k.sys. All this should be less then
+ * 100 lines of code. [KERNEL32 50% DONE, USER32 NOT DONE]
+ *
+ * - The skeleton code for winsrv and basesrv which connects with CSR/CSRSRV
+ * needs to be written. [NOT DONE]
+ *
+ * - The kernel's LPC implementation needs to be made compatible. [DONE!]
+ */
+
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CSR Sub System
+ * FILE: subsys/csr/csrsrv/thread.c
+ * PURPOSE: CSR Server DLL Thread Implementation
+ * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "srv.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* DATA **********************************************************************/
+
+LIST_ENTRY CsrThreadHashTable[256];
+SECURITY_QUALITY_OF_SERVICE CsrSecurityQos =
+{
+ sizeof(SECURITY_QUALITY_OF_SERVICE),
+ SecurityImpersonation,
+ SECURITY_STATIC_TRACKING,
+ FALSE
+};
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+/*++
+ * @name CsrAllocateThread
+ *
+ * The CsrAllocateThread routine allocates a new CSR Thread object.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process which will contain this CSR Thread.
+ *
+ * @return Pointer to the newly allocated CSR Thread.
+ *
+ * @remarks None.
+ *
+ *--*/
+PCSR_THREAD
+NTAPI
+CsrAllocateThread(IN PCSR_PROCESS CsrProcess)
+{
+ PCSR_THREAD CsrThread;
+
+ /* Allocate the structure */
+ CsrThread = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, sizeof(CSR_THREAD));
+ if (!CsrThread) return NULL;
+
+ /* Reference the Thread and Process */
+ CsrThread->ReferenceCount++;
+ CsrProcess->ReferenceCount++;
+
+ /* Set the Parent Process */
+ CsrThread->Process = CsrProcess;
+
+ /* Return Thread */
+ return CsrThread;
+}
+
+/*++
+ * @name CsrLocateThreadByClientId
+ *
+ * The CsrLocateThreadByClientId routine locates the CSR Thread and,
+ * optionally, its parent CSR Process, corresponding to a Client ID.
+ *
+ * @param Process
+ * Optional pointer to a CSR Process pointer which will contain
+ * the CSR Thread's parent.
+ *
+ * @param ClientId
+ * Pointer to a Client ID structure containing the Unique Thread ID
+ * to look up.
+ *
+ * @return Pointer to the CSR Thread corresponding to this CID, or NULL if
+ * none was found.
+ *
+ * @remarks None.
+ *
+ *--*/
+PCSR_THREAD
+NTAPI
+CsrLocateThreadByClientId(OUT PCSR_PROCESS *Process OPTIONAL,
+ IN PCLIENT_ID ClientId)
+{
+ ULONG i;
+ PLIST_ENTRY NextEntry;
+ PCSR_THREAD FoundThread;
+ ASSERT(ProcessStructureListLocked());
+
+ /* Hash the Thread */
+ i = CsrHashThread(ClientId->UniqueThread);
+
+ /* Set the list pointers */
+ NextEntry = CsrThreadHashTable[i].Flink;
+
+ /* Star the loop */
+ while (NextEntry != &CsrThreadHashTable[i])
+ {
+ /* Get the thread */
+ FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
+
+ /* Compare the CID */
+ if (*(PULONGLONG)&FoundThread->ClientId == *(PULONGLONG)ClientId)
+ {
+ /* Match found, return the process */
+ *Process = FoundThread->Process;
+
+ /* Return thread too */
+ return FoundThread;
+ }
+
+ /* Next */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* Nothing found */
+ return NULL;
+}
+
+/*++
+ * @name CsrLocateThreadInProcess
+ *
+ * The CsrLocateThreadInProcess routine locates the CSR Thread
+ * corresponding to a Client ID inside a specific CSR Process.
+ *
+ * @param Process
+ * Optional pointer to the CSR Process which contains the CSR Thread
+ * that will be looked up.
+ *
+ * @param ClientId
+ * Pointer to a Client ID structure containing the Unique Thread ID
+ * to look up.
+ *
+ * @return Pointer to the CSR Thread corresponding to this CID, or NULL if
+ * none was found.
+ *
+ * @remarks If the CsrProcess argument is NULL, the lookup will be done inside
+ * CsrRootProcess.
+ *
+ *--*/
+PCSR_THREAD
+NTAPI
+CsrLocateThreadInProcess(IN PCSR_PROCESS CsrProcess OPTIONAL,
+ IN PCLIENT_ID Cid)
+{
+ PLIST_ENTRY NextEntry;
+ PCSR_THREAD FoundThread = NULL;
+
+ /* Use the Root Process if none was specified */
+ if (!CsrProcess) CsrProcess = CsrRootProcess;
+
+ /* Save the List pointers */
+ NextEntry = CsrProcess->ThreadList.Flink;
+
+ /* Start the Loop */
+ while (NextEntry != &CsrProcess->ThreadList)
+ {
+ /* Get Thread Entry */
+ FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
+
+ /* Check for TID Match */
+ if (FoundThread->ClientId.UniqueThread == Cid->UniqueThread) break;
+
+ /* Next entry */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* Return what we found */
+ return FoundThread;
+}
+
+/*++
+ * @name CsrInsertThread
+ *
+ * The CsrInsertThread routine inserts a CSR Thread into its parent's
+ * Thread List and into the Thread Hash Table.
+ *
+ * @param Process
+ * Pointer to the CSR Process containing this CSR Thread.
+ *
+ * @param Thread
+ * Pointer to the CSR Thread to be inserted.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrInsertThread(IN PCSR_PROCESS Process,
+ IN PCSR_THREAD Thread)
+{
+ ULONG i;
+ ASSERT(ProcessStructureListLocked());
+
+ /* Insert it into the Regular List */
+ InsertTailList(&Process->ThreadList, &Thread->Link);
+
+ /* Increase Thread Count */
+ Process->ThreadCount++;
+
+ /* Hash the Thread */
+ i = CsrHashThread(Thread->ClientId.UniqueThread);
+
+ /* Insert it there too */
+ InsertHeadList(&CsrThreadHashTable[i], &Thread->HashLinks);
+}
+
+/*++
+ * @name CsrDeallocateThread
+ *
+ * The CsrDeallocateThread frees the memory associated with a CSR Thread.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread to be freed.
+ *
+ * @return None.
+ *
+ * @remarks Do not call this routine. It is reserved for the internal
+ * thread management routines when a CSR Thread has been cleanly
+ * dereferenced and killed.
+ *
+ *--*/
+VOID
+NTAPI
+CsrDeallocateThread(IN PCSR_THREAD CsrThread)
+{
+ /* Free the process object from the heap */
+ ASSERT(CsrThread->WaitBlock == NULL);
+ RtlFreeHeap(CsrHeap, 0, CsrThread);
+}
+
+/*++
+ * @name CsrLockedReferenceThread
+ *
+ * The CsrLockedReferenceThread refences a CSR Thread while the
+ * Process Lock is already being held.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread to be referenced.
+ *
+ * @return None.
+ *
+ * @remarks This routine will return with the Process Lock held.
+ *
+ *--*/
+VOID
+NTAPI
+CsrLockedReferenceThread(IN PCSR_THREAD CsrThread)
+{
+ /* Increment the reference count */
+ ++CsrThread->ReferenceCount;
+}
+
+/*++
+ * @name CsrLockedDereferenceThread
+ *
+ * The CsrLockedDereferenceThread derefences a CSR Thread while the
+ * Process Lock is already being held.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread to be dereferenced.
+ *
+ * @return None.
+ *
+ * @remarks This routine will return with the Process Lock held.
+ *
+ *--*/
+VOID
+NTAPI
+CsrLockedDereferenceThread(IN PCSR_THREAD CsrThread)
+{
+ LONG LockCount;
+
+ /* Decrease reference count */
+ LockCount = --CsrThread->ReferenceCount;
+ ASSERT(LockCount >= 0);
+ if (!LockCount)
+ {
+ /* Call the generic cleanup code */
+ CsrThreadRefcountZero(CsrThread);
+ CsrAcquireProcessLock();
+ }
+}
+
+/*++
+ * @name CsrRemoveThread
+ *
+ * The CsrRemoveThread function undoes a CsrInsertThread operation and
+ * removes the CSR Thread from the the Hash Table and Thread List.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread to remove.
+ *
+ * @return None.
+ *
+ * @remarks If this CSR Thread is the last one inside a CSR Process, the
+ * parent will be dereferenced and the CsrProcessLastThreadTerminated
+ * flag will be set.
+ *
+ * After executing this routine, the CSR Thread will have the
+ * CsrThreadInTermination flag set.
+ *
+ *--*/
+VOID
+NTAPI
+CsrRemoveThread(IN PCSR_THREAD CsrThread)
+{
+ ASSERT(ProcessStructureListLocked());
+
+ /* Remove it from the List */
+ RemoveEntryList(&CsrThread->Link);
+
+ /* Decreate the thread count of the process */
+ --CsrThread->Process->ThreadCount;
+
+ /* Remove it from the Hash List as well */
+ if (CsrThread->HashLinks.Flink) RemoveEntryList(&CsrThread->HashLinks);
+
+ /* Check if this is the last Thread */
+ if (!CsrThread->Process->ThreadCount)
+ {
+ /* Check if it's not already been marked for deletion */
+ if (!(CsrThread->Process->Flags & CsrProcessLastThreadTerminated))
+ {
+ /* Let everyone know this process is about to lose the thread */
+ CsrThread->Process->Flags |= CsrProcessLastThreadTerminated;
+
+ /* Reference the Process */
+ CsrLockedDereferenceProcess(CsrThread->Process);
+ }
+ }
+
+ /* Mark the thread for deletion */
+ CsrThread->Flags |= CsrThreadInTermination;
+}
+
+/*++
+ * @name CsrThreadRefcountZero
+ *
+ * The CsrThreadRefcountZero routine is executed when a CSR Thread has lost
+ * all its active references. It removes and de-allocates the CSR Thread.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread that is to be deleted.
+ *
+ * @return None.
+ *
+ * @remarks Do not call this routine. It is reserved for the internal
+ * thread management routines when a CSR Thread has lost all
+ * its references.
+ *
+ * This routine is called with the Process Lock held.
+ *
+ *--*/
+VOID
+NTAPI
+CsrThreadRefcountZero(IN PCSR_THREAD CsrThread)
+{
+ PCSR_PROCESS CsrProcess = CsrThread->Process;
+ NTSTATUS Status;
+
+ /* Remove this thread */
+ CsrRemoveThread(CsrThread);
+
+ /* Release the Process Lock */
+ CsrReleaseProcessLock();
+
+ /* Close the NT Thread Handle */
+ UnProtectHandle(CsrThread->ThreadHandle);
+ Status = NtClose(CsrThread->ThreadHandle);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* De-allocate the CSR Thread Object */
+ CsrDeallocateThread(CsrThread);
+
+ /* Remove a reference from the process */
+ CsrDereferenceProcess(CsrProcess);
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+/*++
+ * @name CsrAddStaticServerThread
+ * @implemented NT4
+ *
+ * The CsrAddStaticServerThread routine adds a new CSR Thread to the
+ * CSR Server Process (CsrRootProcess).
+ *
+ * @param hThread
+ * Handle to an existing NT Thread to which to associate this
+ * CSR Thread.
+ *
+ * @param ClientId
+ * Pointer to the Client ID structure of the NT Thread to associate
+ * with this CSR Thread.
+ *
+ * @param ThreadFlags
+ * Initial CSR Thread Flags to associate to this CSR Thread. Usually
+ * CsrThreadIsServerThread.
+ *
+ * @return Pointer to the newly allocated CSR Thread.
+ *
+ * @remarks None.
+ *
+ *--*/
+PCSR_THREAD
+NTAPI
+CsrAddStaticServerThread(IN HANDLE hThread,
+ IN PCLIENT_ID ClientId,
+ IN ULONG ThreadFlags)
+{
+ PCSR_THREAD CsrThread;
+
+ /* Get the Lock */
+ CsrAcquireProcessLock();
+
+ /* Allocate the Server Thread */
+ CsrThread = CsrAllocateThread(CsrRootProcess);
+ if (CsrThread)
+ {
+ /* Setup the Object */
+ CsrThread->ThreadHandle = hThread;
+ ProtectHandle(hThread);
+ CsrThread->ClientId = *ClientId;
+ CsrThread->Flags = ThreadFlags;
+
+ /* Insert it into the Thread List */
+ InsertTailList(&CsrRootProcess->ThreadList, &CsrThread->Link);
+
+ /* Increment the thread count */
+ CsrRootProcess->ThreadCount++;
+ }
+ else
+ {
+ DPRINT1("CsrAddStaticServerThread: alloc failed for thread 0x%x\n", hThread);
+ }
+
+ /* Release the Process Lock and return */
+ CsrReleaseProcessLock();
+ return CsrThread;
+}
+
+/*++
+ * @name CsrCreateRemoteThread
+ * @implemented NT4
+ *
+ * The CsrCreateRemoteThread routine creates a CSR Thread object for
+ * an NT Thread which is not part of the current NT Process.
+ *
+ * @param hThread
+ * Handle to an existing NT Thread to which to associate this
+ * CSR Thread.
+ *
+ * @param ClientId
+ * Pointer to the Client ID structure of the NT Thread to associate
+ * with this CSR Thread.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrCreateRemoteThread(IN HANDLE hThread,
+ IN PCLIENT_ID ClientId)
+{
+ NTSTATUS Status;
+ HANDLE ThreadHandle;
+ PCSR_THREAD CsrThread;
+ PCSR_PROCESS CsrProcess;
+ KERNEL_USER_TIMES KernelTimes;
+
+ DPRINT("CSRSRV: %s called\n", __FUNCTION__);
+
+ /* Get the Thread Create Time */
+ Status = NtQueryInformationThread(hThread,
+ ThreadTimes,
+ &KernelTimes,
+ sizeof(KernelTimes),
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Lock the Owner Process */
+ Status = CsrLockProcessByClientId(&ClientId->UniqueProcess, &CsrProcess);
+
+ /* Make sure the thread didn't terminate */
+ if (KernelTimes.ExitTime.QuadPart)
+ {
+ /* Unlock the process and return */
+ CsrUnlockProcess(CsrProcess);
+ return STATUS_THREAD_IS_TERMINATING;
+ }
+
+ /* Allocate a CSR Thread Structure */
+ CsrThread = CsrAllocateThread(CsrProcess);
+ if (!CsrThread)
+ {
+ DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
+ CsrUnlockProcess(CsrProcess);
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Duplicate the Thread Handle */
+ Status = NtDuplicateObject(NtCurrentProcess(),
+ hThread,
+ NtCurrentProcess(),
+ &ThreadHandle,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS);
+ /* Allow failure */
+ if (!NT_SUCCESS(Status)) ThreadHandle = hThread;
+
+ /* Save the data we have */
+ CsrThread->CreateTime = KernelTimes.CreateTime;
+ CsrThread->ClientId = *ClientId;
+ CsrThread->ThreadHandle = ThreadHandle;
+ ProtectHandle(ThreadHandle);
+ CsrThread->Flags = 0;
+
+ /* Insert the Thread into the Process */
+ CsrInsertThread(CsrProcess, CsrThread);
+
+ /* Release the lock and return */
+ CsrUnlockProcess(CsrProcess);
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrCreateThread
+ * @implemented NT4
+ *
+ * The CsrCreateThread routine creates a CSR Thread object for an NT Thread.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process which will contain the CSR Thread.
+ *
+ * @param hThread
+ * Handle to an existing NT Thread to which to associate this
+ * CSR Thread.
+ *
+ * @param ClientId
+ * Pointer to the Client ID structure of the NT Thread to associate
+ * with this CSR Thread.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrCreateThread(IN PCSR_PROCESS CsrProcess,
+ IN HANDLE hThread,
+ IN PCLIENT_ID ClientId,
+ IN BOOLEAN HaveClient)
+{
+ NTSTATUS Status;
+ PCSR_THREAD CsrThread, CurrentThread;
+ PCSR_PROCESS CurrentProcess;
+ CLIENT_ID CurrentCid;
+ KERNEL_USER_TIMES KernelTimes;
+ DPRINT("CSRSRV: %s called\n", __FUNCTION__);
+
+ if (HaveClient)
+ {
+ /* Get the current thread and CID */
+ CurrentThread = NtCurrentTeb()->CsrClientThread;
+ CurrentCid = CurrentThread->ClientId;
+
+ /* Acquire the Process Lock */
+ CsrAcquireProcessLock();
+
+ /* Get the current Process and make sure the Thread is valid with this CID */
+ CurrentThread = CsrLocateThreadByClientId(&CurrentProcess, &CurrentCid);
+ if (!CurrentThread)
+ {
+ DPRINT1("CSRSRV:%s: invalid thread!\n", __FUNCTION__);
+ CsrReleaseProcessLock();
+ return STATUS_THREAD_IS_TERMINATING;
+ }
+ }
+ else
+ {
+ /* Acquire the Process Lock */
+ CsrAcquireProcessLock();
+ }
+
+ /* Get the Thread Create Time */
+ Status = NtQueryInformationThread(hThread,
+ ThreadTimes,
+ (PVOID)&KernelTimes,
+ sizeof(KernelTimes),
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ CsrReleaseProcessLock();
+ return Status;
+ }
+
+ /* Allocate a CSR Thread Structure */
+ CsrThread = CsrAllocateThread(CsrProcess);
+ if (!CsrThread)
+ {
+ DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
+ CsrReleaseProcessLock();
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Save the data we have */
+ CsrThread->CreateTime = KernelTimes.CreateTime;
+ CsrThread->ClientId = *ClientId;
+ CsrThread->ThreadHandle = hThread;
+ ProtectHandle(hThread);
+ CsrThread->Flags = 0;
+
+ /* Insert the Thread into the Process */
+ CsrInsertThread(CsrProcess, CsrThread);
+
+ /* Release the lock and return */
+ CsrReleaseProcessLock();
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrDereferenceThread
+ * @implemented NT4
+ *
+ * The CsrDereferenceThread routine removes a reference from a CSR Thread.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread to dereference.
+ *
+ * @return None.
+ *
+ * @remarks If the reference count has reached zero (ie: the CSR Thread has
+ * no more active references), it will be deleted.
+ *
+ *--*/
+VOID
+NTAPI
+CsrDereferenceThread(IN PCSR_THREAD CsrThread)
+{
+ /* Acquire process lock */
+ CsrAcquireProcessLock();
+
+ /* Decrease reference count */
+ ASSERT(CsrThread->ReferenceCount > 0);
+ if (!(--CsrThread->ReferenceCount))
+ {
+ /* Call the generic cleanup code */
+ CsrThreadRefcountZero(CsrThread);
+ }
+ else
+ {
+ /* Just release the lock */
+ CsrReleaseProcessLock();
+ }
+}
+
+/*++
+ * @name CsrExecServerThread
+ * @implemented NT4
+ *
+ * The CsrExecServerThread routine creates an NT Thread and then
+ * initializes a CSR Thread for it.
+ *
+ * @param ThreadHandler
+ * Pointer to the thread's startup routine.
+ *
+ * @param Flags
+ * Initial CSR Thread Flags to set to the CSR Thread.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks This routine is similar to CsrAddStaticServerThread, but it
+ * also creates an NT Thread instead of expecting one to already
+ * exist.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrExecServerThread(IN PVOID ThreadHandler,
+ IN ULONG Flags)
+{
+ PCSR_THREAD CsrThread;
+ HANDLE hThread;
+ CLIENT_ID ClientId;
+ NTSTATUS Status;
+
+ /* Acquire process lock */
+ CsrAcquireProcessLock();
+
+ /* Allocate a CSR Thread in the Root Process */
+ ASSERT(CsrRootProcess != NULL);
+ CsrThread = CsrAllocateThread(CsrRootProcess);
+ if (!CsrThread)
+ {
+ /* Fail */
+ CsrReleaseProcessLock();
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Create the Thread */
+ Status = RtlCreateUserThread(NtCurrentProcess(),
+ NULL,
+ FALSE,
+ 0,
+ 0,
+ 0,
+ ThreadHandler,
+ NULL,
+ &hThread,
+ &ClientId);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ CsrDeallocateThread(CsrThread);
+ CsrReleaseProcessLock();
+ return Status;
+ }
+
+ /* Setup the Thread Object */
+ CsrThread->ThreadHandle = hThread;
+ ProtectHandle(hThread);
+ CsrThread->ClientId = ClientId;
+ CsrThread->Flags = Flags;
+
+ /* Insert it into the Thread List */
+ InsertHeadList(&CsrRootProcess->ThreadList, &CsrThread->Link);
+
+ /* Increase the thread count */
+ CsrRootProcess->ThreadCount++;
+
+ /* Return */
+ CsrReleaseProcessLock();
+ return Status;
+}
+
+/*++
+ * @name CsrDestroyThread
+ * @implemented NT4
+ *
+ * The CsrDestroyThread routine destroys the CSR Thread corresponding to
+ * a given Thread ID.
+ *
+ * @param Cid
+ * Pointer to the Client ID Structure corresponding to the CSR
+ * Thread which is about to be destroyed.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING
+ * if the CSR Thread is already terminating.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrDestroyThread(IN PCLIENT_ID Cid)
+{
+ CLIENT_ID ClientId = *Cid;
+ PCSR_THREAD CsrThread;
+ PCSR_PROCESS CsrProcess;
+
+ /* Acquire lock */
+ CsrAcquireProcessLock();
+
+ /* Find the thread */
+ CsrThread = CsrLocateThreadByClientId(&CsrProcess,
+ &ClientId);
+
+ /* Make sure we got one back, and that it's not already gone */
+ if (!CsrThread || CsrThread->Flags & CsrThreadTerminated)
+ {
+ /* Release the lock and return failure */
+ CsrReleaseProcessLock();
+ return STATUS_THREAD_IS_TERMINATING;
+ }
+
+ /* Set the terminated flag */
+ CsrThread->Flags |= CsrThreadTerminated;
+
+ /* Acquire the Wait Lock */
+ CsrAcquireWaitLock();
+
+ /* Do we have an active wait block? */
+ if (CsrThread->WaitBlock)
+ {
+ /* Notify waiters of termination */
+ CsrNotifyWaitBlock(CsrThread->WaitBlock,
+ NULL,
+ NULL,
+ NULL,
+ CsrProcessTerminating,
+ TRUE);
+ }
+
+ /* Release the Wait Lock */
+ CsrReleaseWaitLock();
+
+ /* Dereference the thread */
+ CsrLockedDereferenceThread(CsrThread);
+
+ /* Release the Process Lock and return success */
+ CsrReleaseProcessLock();
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrImpersonateClient
+ * @implemented NT4
+ *
+ * The CsrImpersonateClient will impersonate the given CSR Thread.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread to impersonate.
+ *
+ * @return TRUE if impersionation suceeded, false otherwise.
+ *
+ * @remarks Impersonation can be recursive.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrImpersonateClient(IN PCSR_THREAD CsrThread)
+{
+ NTSTATUS Status;
+ PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
+
+ /* Use the current thread if none given */
+ if (!CsrThread) CsrThread = CurrentThread;
+
+ /* Still no thread, something is wrong */
+ if (!CsrThread) return FALSE;
+
+ /* Make the call */
+ Status = NtImpersonateThread(NtCurrentThread(),
+ CsrThread->ThreadHandle,
+ &CsrSecurityQos);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: Can't impersonate client thread - Status = %lx\n", Status);
+ if (Status != STATUS_BAD_IMPERSONATION_LEVEL) DbgBreakPoint();
+ return FALSE;
+ }
+
+ /* Increase the impersonation count for the current thread and return */
+ if (CurrentThread) ++CurrentThread->ImpersonationCount;
+ return TRUE;
+}
+
+/*++
+ * @name CsrRevertToSelf
+ * @implemented NT4
+ *
+ * The CsrRevertToSelf routine will attempt to remove an active impersonation.
+ *
+ * @param None.
+ *
+ * @return TRUE if the reversion was succesful, false otherwise.
+ *
+ * @remarks Impersonation can be recursive; as such, the impersonation token
+ * will only be deleted once the CSR Thread's impersonaton count
+ * has reached zero.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrRevertToSelf(VOID)
+{
+ NTSTATUS Status;
+ PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
+ HANDLE ImpersonationToken = NULL;
+
+ /* Check if we have a Current Thread */
+ if (CurrentThread)
+ {
+ /* Make sure impersonation is on */
+ if (!CurrentThread->ImpersonationCount)
+ {
+ DPRINT1("CSRSS: CsrRevertToSelf called while not impersonating\n");
+ DbgBreakPoint();
+ return FALSE;
+ }
+ else if (--CurrentThread->ImpersonationCount > 0)
+ {
+ /* Success; impersonation count decreased but still not zero */
+ return TRUE;
+ }
+ }
+
+ /* Impersonation has been totally removed, revert to ourselves */
+ Status = NtSetInformationThread(NtCurrentThread(),
+ ThreadImpersonationToken,
+ &ImpersonationToken,
+ sizeof(HANDLE));
+
+ /* Return TRUE or FALSE */
+ ASSERT(NT_SUCCESS(Status));
+ return NT_SUCCESS(Status);
+}
+
+/*++
+ * @name CsrLockThreadByClientId
+ * @implemented NT4
+ *
+ * The CsrLockThreadByClientId routine locks the CSR Thread corresponding
+ * to the given Thread ID and optionally returns it.
+ *
+ * @param Tid
+ * Thread ID corresponding to the CSR Thread which will be locked.
+ *
+ * @param CsrThread
+ * Optional pointer to a CSR Thread pointer which will hold the
+ * CSR Thread corresponding to the given Thread ID.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * othwerwise.
+ *
+ * @remarks Locking a CSR Thread is defined as acquiring an extra
+ * reference to it and returning with the Process Lock held.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrLockThreadByClientId(IN HANDLE Tid,
+ OUT PCSR_THREAD *CsrThread)
+{
+ PLIST_ENTRY NextEntry;
+ PCSR_THREAD CurrentThread = NULL;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ ULONG i;
+
+ /* Acquire the lock */
+ CsrAcquireProcessLock();
+
+ /* Assume failure */
+ ASSERT(CsrThread != NULL);
+ *CsrThread = NULL;
+
+ /* Convert to Hash */
+ i = CsrHashThread(Tid);
+
+ /* Setup the List Pointers */
+ NextEntry = CsrThreadHashTable[i].Flink;
+
+ /* Start Loop */
+ while (NextEntry != &CsrThreadHashTable[i])
+ {
+ /* Get the Process */
+ CurrentThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
+
+ /* Check for PID Match */
+ if ((CurrentThread->ClientId.UniqueThread == Tid) &&
+ !(CurrentThread->Flags & CsrThreadTerminated))
+ {
+ /* Get out of here */
+ break;
+ }
+
+ /* Next entry */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* Nothing found if we got back to the list */
+ if (NextEntry == &CsrThreadHashTable[i]) CurrentThread = NULL;
+
+ /* Did the loop find something? */
+ if (CurrentThread)
+ {
+ /* Reference the found thread */
+ Status = STATUS_SUCCESS;
+ CurrentThread->ReferenceCount++;
+ *CsrThread = CurrentThread;
+ }
+ else
+ {
+ /* Nothing found, release the lock */
+ Status = STATUS_UNSUCCESSFUL;
+ CsrReleaseProcessLock();
+ }
+
+ /* Return the status */
+ return Status;
+}
+
+/*++
+ * @name CsrReferenceThread
+ * @implemented NT4
+ *
+ * The CsrReferenceThread routine increases the active reference count of
+ * a CSR Thread.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread whose reference count will be increased.
+ *
+ * @return None.
+ *
+ * @remarks Do not use this routine if the Process Lock is already held.
+ *
+ *--*/
+VOID
+NTAPI
+CsrReferenceThread(PCSR_THREAD CsrThread)
+{
+ /* Acquire process lock */
+ CsrAcquireProcessLock();
+
+ /* Sanity checks */
+ ASSERT(CsrThread->Flags & CsrThreadTerminated); // CSR_THREAD_DESTROYED in ASSERT
+ ASSERT(CsrThread->ReferenceCount != 0);
+
+ /* Increment reference count */
+ CsrThread->ReferenceCount++;
+
+ /* Release the lock */
+ CsrReleaseProcessLock();
+}
+
+/*++
+ * @name CsrUnlockThread
+ * @implemented NT4
+ *
+ * The CsrUnlockThread undoes a previous CsrLockThreadByClientId operation.
+ *
+ * @param CsrThread
+ * Pointer to a previously locked CSR Thread.
+ *
+ * @return STATUS_SUCCESS.
+ *
+ * @remarks This routine must be called with the Process Lock held.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrUnlockThread(PCSR_THREAD CsrThread)
+{
+ /* Dereference the Thread */
+ ASSERT(ProcessStructureListLocked());
+ CsrLockedDereferenceThread(CsrThread);
+
+ /* Release the lock and return */
+ CsrReleaseProcessLock();
+ return STATUS_SUCCESS;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CSR Sub System
+ * FILE: subsys/csr/csrsrv/wait.c
+ * PURPOSE: CSR Server DLL Wait Implementation
+ * PROGRAMMERS: Emanuele Aliberti
+ * Alex Ionescu (alex@relsoft.net)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "srv.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* DATA **********************************************************************/
+
+RTL_CRITICAL_SECTION CsrWaitListsLock;
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+/*++
+ * @name CsrInitializeWait
+ *
+ * The CsrInitializeWait routine initializes a CSR Wait Object.
+ *
+ * @param WaitFunction
+ * Pointer to the function that will handle this wait.
+ *
+ * @param CsrWaitThread
+ * Pointer to the CSR Thread that will perform the wait.
+ *
+ * @param WaitApiMessage
+ * Pointer to the CSR API Message associated to this wait.
+ *
+ * @param WaitContext
+ * Pointer to a user-defined parameter associated to this wait.
+ *
+ * @param NewWaitBlock
+ * Pointed to the initialized CSR Wait Block for this wait.
+ *
+ * @return TRUE in case of success, FALSE othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrInitializeWait(IN CSR_WAIT_FUNCTION WaitFunction,
+ IN PCSR_THREAD CsrWaitThread,
+ IN OUT PCSR_API_MESSAGE WaitApiMessage,
+ IN PVOID WaitContext,
+ OUT PCSR_WAIT_BLOCK *NewWaitBlock)
+{
+ ULONG Size;
+ PCSR_WAIT_BLOCK WaitBlock;
+
+ /* Calculate the size of the wait block */
+ Size = sizeof(CSR_WAIT_BLOCK) -
+ sizeof(WaitBlock->WaitApiMessage) +
+ WaitApiMessage->Header.u1.s1.TotalLength;
+
+ /* Allocate the Wait Block */
+ WaitBlock = RtlAllocateHeap(CsrHeap, 0, Size);
+ if (!WaitBlock)
+ {
+ /* Fail */
+ WaitApiMessage->Status = STATUS_NO_MEMORY;
+ return FALSE;
+ }
+
+ /* Initialize it */
+ WaitBlock->Size = Size;
+ WaitBlock->WaitThread = CsrWaitThread;
+ WaitBlock->WaitContext = WaitContext;
+ WaitBlock->WaitFunction = WaitFunction;
+ WaitBlock->UserWaitList.Flink = NULL;
+ WaitBlock->UserWaitList.Blink = NULL;
+ WaitBlock->WaitList = WaitBlock->UserWaitList;
+
+ /* Copy the message */
+ RtlMoveMemory(&WaitBlock->WaitApiMessage,
+ WaitApiMessage,
+ WaitApiMessage->Header.u1.s1.TotalLength);
+
+ /* Return the block */
+ *NewWaitBlock = WaitBlock;
+ return TRUE;
+}
+
+/*++
+ * @name CsrNotifyWaitBlock
+ *
+ * The CsrNotifyWaitBlock routine calls the wait function for a registered
+ * CSR Wait Block, and replies to the attached CSR API Message, if any.
+ *
+ * @param WaitBlock
+ * Pointer to the CSR Wait Block
+ *
+ * @param WaitList
+ * Pointer to the wait list for this wait.
+ *
+ * @param WaitArgument[1-2]
+ * User-defined values to pass to the wait function.
+ *
+ * @param WaitFlags
+ * Wait flags for this wait.
+ *
+ * @param DereferenceThread
+ * Specifies whether the CSR Thread should be dereferenced at the
+ * end of this wait.
+ *
+ * @return TRUE in case of success, FALSE otherwise.
+ *
+ * @remarks After a wait block is notified, the wait function becomes invalid.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrNotifyWaitBlock(IN PCSR_WAIT_BLOCK WaitBlock,
+ IN PLIST_ENTRY WaitList,
+ IN PVOID WaitArgument1,
+ IN PVOID WaitArgument2,
+ IN ULONG WaitFlags,
+ IN BOOLEAN DereferenceThread)
+{
+ /* Call the wait function */
+ if ((WaitBlock->WaitFunction)(WaitList,
+ WaitBlock->WaitThread,
+ &WaitBlock->WaitApiMessage,
+ WaitBlock->WaitContext,
+ WaitArgument1,
+ WaitArgument2,
+ WaitFlags))
+ {
+ /* The wait is done, clear the block */
+ WaitBlock->WaitThread->WaitBlock = NULL;
+
+ /* Check for captured arguments */
+ if (WaitBlock->WaitApiMessage.CsrCaptureData)
+ {
+ /* Release them */
+ CsrReleaseCapturedArguments(&WaitBlock->WaitApiMessage);
+ }
+
+ /* Reply to the port */
+ NtReplyPort(WaitBlock->WaitThread->Process->ClientPort,
+ (PPORT_MESSAGE)&WaitBlock->WaitApiMessage);
+
+ /* Check if we should dereference the thread */
+ if (DereferenceThread)
+ {
+ /* Remove it from the Wait List */
+ if (WaitBlock->WaitList.Flink)
+ {
+ RemoveEntryList(&WaitBlock->WaitList);
+ }
+
+ /* Remove it from the User Wait List */
+ if (WaitBlock->UserWaitList.Flink)
+ {
+ RemoveEntryList(&WaitBlock->UserWaitList);
+ }
+
+ /* Dereference teh thread */
+ CsrDereferenceThread(WaitBlock->WaitThread);
+
+ /* Free the wait block */
+ RtlFreeHeap(CsrHeap, 0, WaitBlock);
+ }
+ else
+ {
+ /* The wait is complete, but the thread is being kept alive */
+ WaitBlock->WaitFunction = NULL;
+ }
+
+ /* The wait suceeded */
+ return TRUE;
+ }
+
+ /* The wait failed */
+ return FALSE;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*++
+ * @name CsrCreateWait
+ * @implemented NT4
+ *
+ * The CsrCreateWait routine creates a CSR Wait.
+ *
+ * @param WaitList
+ * Pointer to a list entry of the waits to associate.
+ *
+ * @param WaitFunction
+ * Pointer to the function that will handle this wait.
+ *
+ * @param CsrWaitThread
+ * Pointer to the CSR Thread that will perform the wait.
+ *
+ * @param WaitApiMessage
+ * Pointer to the CSR API Message associated to this wait.
+ *
+ * @param WaitContext
+ * Pointer to a user-defined parameter associated to this wait.
+ *
+ * @param UserWaitList
+ * Pointer to a list entry of the user-defined waits to associate.
+ *
+ * @return TRUE in case of success, FALSE otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrCreateWait(IN PLIST_ENTRY WaitList,
+ IN CSR_WAIT_FUNCTION WaitFunction,
+ IN PCSR_THREAD CsrWaitThread,
+ IN OUT PCSR_API_MESSAGE WaitApiMessage,
+ IN PVOID WaitContext,
+ IN PLIST_ENTRY UserWaitList OPTIONAL)
+{
+ PCSR_WAIT_BLOCK WaitBlock;
+
+ /* Initialize the wait */
+ if (!CsrInitializeWait(WaitFunction,
+ CsrWaitThread,
+ WaitApiMessage,
+ WaitContext,
+ &WaitBlock))
+ {
+ return FALSE;
+ }
+
+ /* Acquire the Wait Lock */
+ CsrAcquireWaitLock();
+
+ /* Make sure the thread wasn't destroyed */
+ if (CsrWaitThread->Flags & CsrThreadTerminated)
+ {
+ /* Fail the wait */
+ RtlFreeHeap(CsrHeap, 0, WaitBlock);
+ CsrReleaseWaitLock();
+ return FALSE;
+ }
+
+ /* Insert the wait in the queue */
+ InsertTailList(WaitList, &WaitBlock->WaitList);
+
+ /* Insert the User Wait too, if one was given */
+ if (UserWaitList) InsertTailList(UserWaitList, &WaitBlock->UserWaitList);
+
+ /* Return */
+ CsrReleaseWaitLock();
+ return TRUE;
+}
+
+/*++
+ * @name CsrDereferenceWait
+ * @implemented NT4
+ *
+ * The CsrDereferenceWait routine derefences a CSR Wait Block.
+ *
+ * @param WaitList
+ * Pointer to the Wait List associated to the wait.
+
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrDereferenceWait(IN PLIST_ENTRY WaitList)
+{
+ PLIST_ENTRY NextEntry;
+ PCSR_WAIT_BLOCK WaitBlock;
+
+ /* Acquire the Process and Wait Locks */
+ CsrAcquireProcessLock();
+ CsrAcquireWaitLock();
+
+ /* Set the list pointers */
+ NextEntry = WaitList->Flink;
+
+ /* Start the loop */
+ while (NextEntry != WaitList)
+ {
+ /* Get the wait block */
+ WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
+
+ /* Move to the next entry */
+ NextEntry = NextEntry->Flink;
+
+ /* Check if there's no Wait Routine */
+ if (!WaitBlock->WaitFunction)
+ {
+ /* Remove it from the Wait List */
+ if (WaitBlock->WaitList.Flink)
+ {
+ RemoveEntryList(&WaitBlock->WaitList);
+ }
+
+ /* Remove it from the User Wait List */
+ if (WaitBlock->UserWaitList.Flink)
+ {
+ RemoveEntryList(&WaitBlock->UserWaitList);
+ }
+
+ /* Dereference the thread waiting on it */
+ CsrDereferenceThread(WaitBlock->WaitThread);
+
+ /* Free the block */
+ RtlFreeHeap(CsrHeap, 0, WaitBlock);
+ }
+ }
+
+ /* Release the locks */
+ CsrReleaseWaitLock();
+ CsrReleaseProcessLock();
+}
+
+/*++
+ * @name CsrMoveSatisfiedWait
+ * @implemented NT5
+ *
+ * The CsrMoveSatisfiedWait routine moves satisfied waits from a wait list
+ * to another list entry.
+ *
+ * @param NewEntry
+ * Pointer to a list entry where the satisfied waits will be added.
+ *
+ * @param WaitList
+ * Pointer to a list entry to analyze for satisfied waits.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrMoveSatisfiedWait(IN PLIST_ENTRY NewEntry,
+ IN PLIST_ENTRY WaitList)
+{
+ PLIST_ENTRY NextEntry;
+ PCSR_WAIT_BLOCK WaitBlock;
+
+ /* Acquire the Wait Lock */
+ CsrAcquireWaitLock();
+
+ /* Set the List pointers */
+ NextEntry = WaitList->Flink;
+
+ /* Start looping */
+ while (NextEntry != WaitList)
+ {
+ /* Get the Wait block */
+ WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
+
+ /* Go to the next entry */
+ NextEntry = NextEntry->Flink;
+
+ /* Check if there is a Wait Callback */
+ if (WaitBlock->WaitFunction)
+ {
+ /* Remove it from the Wait Block Queue */
+ RemoveEntryList(&WaitBlock->WaitList);
+
+ /* Insert the new entry */
+ InsertTailList(&WaitBlock->WaitList, NewEntry);
+ }
+ }
+
+ /* Release the wait lock */
+ CsrReleaseWaitLock();
+}
+
+/*++
+ * @name CsrNotifyWait
+ * @implemented NT4
+ *
+ * The CsrNotifyWait notifies a CSR Wait Block.
+ *
+ * @param WaitList
+ * Pointer to the list entry for this wait.
+ *
+ * @param WaitType
+ * Type of the wait to perform, either WaitAny or WaitAll.
+ *
+ * @param WaitArgument[1-2]
+ * User-defined argument to pass on to the wait function.
+ *
+ * @return TRUE in case of success, FALSE othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrNotifyWait(IN PLIST_ENTRY WaitList,
+ IN ULONG WaitType,
+ IN PVOID WaitArgument1,
+ IN PVOID WaitArgument2)
+{
+ PLIST_ENTRY NextEntry;
+ PCSR_WAIT_BLOCK WaitBlock;
+ BOOLEAN NotifySuccess = FALSE;
+
+ /* Acquire the Wait Lock */
+ CsrAcquireWaitLock();
+
+ /* Set the List pointers */
+ NextEntry = WaitList->Flink;
+
+ /* Start looping */
+ while (NextEntry != WaitList)
+ {
+ /* Get the Wait block */
+ WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
+
+ /* Go to the next entry */
+ NextEntry = NextEntry->Flink;
+
+ /* Check if there is a Wait Callback */
+ if (WaitBlock->WaitFunction)
+ {
+ /* Notify the Waiter */
+ NotifySuccess |= CsrNotifyWaitBlock(WaitBlock,
+ WaitList,
+ WaitArgument1,
+ WaitArgument2,
+ 0,
+ FALSE);
+
+ /* We've already done a wait, so leave unless this is a Wait All */
+ if (WaitType != WaitAll) break;
+ }
+ }
+
+ /* Release the wait lock and return */
+ CsrReleaseWaitLock();
+ return NotifySuccess;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CSR Sub System
+ * FILE: subsys/csr/csrss.c
+ * PURPOSE: CSR Executable
+ * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#define WIN32_NO_STATUS
+#include <windows.h>
+#define NTOS_MODE_USER
+#include <ndk/ntndk.h>
+#include <csr/server.h>
+
+#define NDEBUG
+#include <debug.h>
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+VOID
+NTAPI
+CsrpSetDefaultProcessHardErrorMode (VOID)
+{
+ ULONG DefaultHardErrorMode = 0;
+
+ /* Disable hard errors */
+ NtSetInformationProcess(NtCurrentProcess(),
+ ProcessDefaultHardErrorMode,
+ &DefaultHardErrorMode,
+ sizeof(DefaultHardErrorMode));
+}
+
+/*
+ * Note: Standard entrypoint for Native C Programs.
+ * The OS backend (NtProcessStartup) which calls this routine is
+ * implemented in a CRT-like static library (much like mainCRTStartup).
+ * Do NOT manually add the NtProcessStartup entrypoint or anything else.
+ */
+int
+_cdecl
+_main(int argc,
+ char *argv[],
+ char *envp[],
+ int DebugFlag)
+{
+ KPRIORITY BasePriority = (8 + 1) + 4;
+ NTSTATUS Status;
+ ULONG Response;
+ UNREFERENCED_PARAMETER(envp);
+ UNREFERENCED_PARAMETER(DebugFlag);
+
+ /* Set the Priority */
+ NtSetInformationProcess(NtCurrentProcess(),
+ ProcessBasePriority,
+ &BasePriority,
+ sizeof(KPRIORITY));
+
+ /* Give us IOPL so that we can access the VGA registers */
+ Status = NtSetInformationProcess(NtCurrentProcess(),
+ ProcessUserModeIOPL,
+ NULL,
+ 0);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Raise a hard error */
+ DPRINT1("CSRSS: Could not raise IOPL: %x\n", Status);
+ Status = NtRaiseHardError(STATUS_IO_PRIVILEGE_FAILED,
+ 0,
+ 0,
+ NULL,
+ OptionOk,
+ &Response);
+ }
+
+ /* Initialize CSR through CSRSRV */
+ Status = CsrServerInitialization(argc, argv);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Kill us */
+ DPRINT1("CSRSS: CsrServerInitialization failed:% lx\n", Status);
+ NtTerminateProcess(NtCurrentProcess(), Status);
+ }
+
+ /* Disable errors */
+ CsrpSetDefaultProcessHardErrorMode();
+
+ /* If this is Session 0, make sure killing us bugchecks the system */
+ if (!NtCurrentPeb()->SessionId) RtlSetProcessIsCritical(TRUE, NULL, FALSE);
+
+ /* Kill this thread. CSRSRV keeps us going */
+ NtTerminateThread(NtCurrentThread(), Status);
+ return 0;
+}
+
+/* EOF */
--- /dev/null
+
+include_directories(${REACTOS_SOURCE_DIR}/subsystems/win32/csrss/include)
+include_directories(${REACTOS_SOURCE_DIR}/include/reactos/subsys)
+
+spec2def(csrsrv.dll csrsrv.spec ADD_IMPORTLIB)
+
+list(APPEND SOURCE
+ api/process.c
+ api/user.c
+ api/wapi.c
+ procsup.c
+ thredsup.c
+ init.c
+ wait.c
+ session.c
+ server.c
+ ${CMAKE_CURRENT_BINARY_DIR}/csrsrv.def)
+
+add_library(csrsrv SHARED ${SOURCE})
+
+target_link_libraries(csrsrv ${PSEH_LIB} smlib)
+
+set_module_type(csrsrv nativedll)
+
+add_importlibs(csrsrv ntdll smdll)
+
+add_pch(csrsrv srv.h)
+
+add_dependencies(csrsrv psdk bugcodes)
+add_cd_file(TARGET csrsrv DESTINATION reactos/system32 FOR all)
+
--- /dev/null
+/*
+ * subsystems/win32/csrss/csrsrv/api/process.c
+ *
+ * "\windows\ApiPort" port process management functions
+ *
+ * ReactOS Operating System
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <srv.h>
+
+#define NDEBUG
+#include <debug.h>
+
+extern NTSTATUS CallProcessCreated(PCSR_PROCESS, PCSR_PROCESS);
+
+/* GLOBALS *******************************************************************/
+
+/* FUNCTIONS *****************************************************************/
+
+/**********************************************************************
+ * CSRSS API
+ *********************************************************************/
+
+CSR_API(CsrSrvCreateProcess)
+{
+ NTSTATUS Status;
+ HANDLE ProcessHandle, ThreadHandle;
+ PCSR_THREAD CsrThread;
+ PCSR_PROCESS NewProcessData;
+ ULONG Flags, VdmPower = 0, DebugFlags = 0;
+
+ /* Get the current client thread */
+ CsrThread = NtCurrentTeb()->CsrClientThread;
+ ASSERT(CsrThread != NULL);
+
+ /* Extract the flags out of the process handle */
+ Flags = (ULONG_PTR)Request->Data.CreateProcessRequest.ProcessHandle & 3;
+ Request->Data.CreateProcessRequest.ProcessHandle = (HANDLE)((ULONG_PTR)Request->Data.CreateProcessRequest.ProcessHandle & ~3);
+
+ /* Duplicate the process handle */
+ Status = NtDuplicateObject(CsrThread->Process->ProcessHandle,
+ Request->Data.CreateProcessRequest.ProcessHandle,
+ NtCurrentProcess(),
+ &ProcessHandle,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to duplicate process handle\n");
+ return Status;
+ }
+
+ /* Duplicate the thread handle */
+ Status = NtDuplicateObject(CsrThread->Process->ProcessHandle,
+ Request->Data.CreateProcessRequest.ThreadHandle,
+ NtCurrentProcess(),
+ &ThreadHandle,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to duplicate process handle\n");
+ NtClose(ProcessHandle);
+ return Status;
+ }
+
+ /* See if this is a VDM process */
+ if (VdmPower)
+ {
+ /* Request VDM powers */
+ Status = NtSetInformationProcess(ProcessHandle,
+ ProcessWx86Information,
+ &VdmPower,
+ sizeof(VdmPower));
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to get VDM powers\n");
+ NtClose(ProcessHandle);
+ NtClose(ThreadHandle);
+ return Status;
+ }
+ }
+
+ /* Convert some flags. FIXME: More need conversion */
+ if (Request->Data.CreateProcessRequest.CreationFlags & CREATE_NEW_PROCESS_GROUP)
+ {
+ DebugFlags |= CsrProcessCreateNewGroup;
+ }
+
+ /* FIXME: SxS Stuff */
+
+ /* Call CSRSRV to create the CSR_PROCESS structure and the first CSR_THREAD */
+ Status = CsrCreateProcess(ProcessHandle,
+ ThreadHandle,
+ &Request->Data.CreateProcessRequest.ClientId,
+ CsrThread->Process->NtSession,
+ DebugFlags,
+ NULL);
+ if (Status == STATUS_THREAD_IS_TERMINATING)
+ {
+ DPRINT1("Thread already dead\n");
+ return Status;
+ }
+
+ /* Check for other failures */
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to create process/thread structures: %lx\n", Status);
+ return Status;
+ }
+
+ /* FIXME: Should notify user32 */
+
+ /* FIXME: VDM vodoo */
+
+ /* ReactOS Compatibility */
+ Status = CsrLockProcessByClientId(Request->Data.CreateProcessRequest.ClientId.UniqueProcess, &NewProcessData);
+ ASSERT(Status == STATUS_SUCCESS);
+ if (!(Request->Data.CreateProcessRequest.CreationFlags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)))
+ {
+ NewProcessData->ParentConsole = ProcessData->Console;
+ NewProcessData->bInheritHandles = Request->Data.CreateProcessRequest.bInheritHandles;
+ }
+ RtlInitializeCriticalSection(&NewProcessData->HandleTableLock);
+ CallProcessCreated(ProcessData, NewProcessData);
+ CsrUnlockProcess(NewProcessData);
+
+ /* Return the result of this operation */
+ return Status;
+}
+
+CSR_API(CsrSrvCreateThread)
+{
+ PCSR_THREAD CurrentThread;
+ HANDLE ThreadHandle;
+ NTSTATUS Status;
+ PCSR_PROCESS CsrProcess;
+
+ /* Get the current CSR thread */
+ CurrentThread = NtCurrentTeb()->CsrClientThread;
+ if (!CurrentThread)
+ {
+ DPRINT1("Server Thread TID: [%lx.%lx]\n",
+ Request->Data.CreateThreadRequest.ClientId.UniqueProcess,
+ Request->Data.CreateThreadRequest.ClientId.UniqueThread);
+ return STATUS_SUCCESS; // server-to-server
+ }
+
+ /* Get the CSR Process for this request */
+ CsrProcess = CurrentThread->Process;
+ if (CsrProcess->ClientId.UniqueProcess !=
+ Request->Data.CreateThreadRequest.ClientId.UniqueProcess)
+ {
+ /* This is a remote thread request -- is it within the server itself? */
+ if (Request->Data.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(Request->Data.CreateThreadRequest.ClientId.UniqueProcess,
+ &CsrProcess);
+ if (!NT_SUCCESS(Status)) return Status;
+ }
+
+ /* Duplicate the thread handle so we can own it */
+ Status = NtDuplicateObject(CurrentThread->Process->ProcessHandle,
+ Request->Data.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,
+ &Request->Data.CreateThreadRequest.ClientId);
+ }
+
+ /* Unlock the process and return */
+ if (CsrProcess != CurrentThread->Process) CsrUnlockProcess(CsrProcess);
+ return Status;
+}
+
+CSR_API(CsrTerminateProcess)
+{
+ PCSR_THREAD CsrThread = NtCurrentTeb()->CsrClientThread;
+ ASSERT(CsrThread != NULL);
+
+ /* Set magic flag so we don't reply this message back */
+ Request->Type = 0xBABE;
+
+ /* Remove the CSR_THREADs and CSR_PROCESS */
+ return CsrDestroyProcess(&CsrThread->ClientId,
+ (NTSTATUS)Request->Data.TerminateProcessRequest.uExitCode);
+}
+
+CSR_API(CsrConnectProcess)
+{
+
+ return(STATUS_SUCCESS);
+}
+
+CSR_API(CsrGetShutdownParameters)
+{
+
+ Request->Data.GetShutdownParametersRequest.Level = ProcessData->ShutdownLevel;
+ Request->Data.GetShutdownParametersRequest.Flags = ProcessData->ShutdownFlags;
+
+ return(STATUS_SUCCESS);
+}
+
+CSR_API(CsrSetShutdownParameters)
+{
+
+ ProcessData->ShutdownLevel = Request->Data.SetShutdownParametersRequest.Level;
+ ProcessData->ShutdownFlags = Request->Data.SetShutdownParametersRequest.Flags;
+
+ return(STATUS_SUCCESS);
+}
+
+/* EOF */
--- /dev/null
+/*
+ * subsystems/win32/csrss/csrsrv/api/user.c
+ *
+ * User functions
+ *
+ * ReactOS Operating System
+ *
+ * PROGRAMMER: Eric Kohl
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <srv.h>
+
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS *******************************************************************/
+
+static BOOLEAN ServicesProcessIdValid = FALSE;
+static ULONG_PTR ServicesProcessId;
+
+
+/* FUNCTIONS *****************************************************************/
+
+CSR_API(CsrRegisterServicesProcess)
+{
+ if (ServicesProcessIdValid == TRUE)
+ {
+ /* Only accept a single call */
+ return STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ ServicesProcessId = (ULONG_PTR)Request->Data.RegisterServicesProcessRequest.ProcessId;
+ ServicesProcessIdValid = TRUE;
+ return STATUS_SUCCESS;
+ }
+}
+
+/* EOF */
--- /dev/null
+/*
+ * subsystems/win32/csrss/csrsrv/api/wapi.c
+ *
+ * CSRSS port message processing
+ *
+ * ReactOS Operating System
+ *
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <srv.h>
+
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS *******************************************************************/
+
+static unsigned ApiDefinitionsCount = 0;
+static PCSRSS_API_DEFINITION ApiDefinitions = NULL;
+UNICODE_STRING CsrApiPortName;
+volatile LONG CsrpStaticThreadCount;
+volatile LONG CsrpDynamicThreadTotal;
+extern ULONG CsrMaxApiRequestThreads;
+
+/* FUNCTIONS *****************************************************************/
+
+NTSTATUS FASTCALL
+CsrApiRegisterDefinitions(PCSRSS_API_DEFINITION NewDefinitions)
+{
+ unsigned NewCount;
+ PCSRSS_API_DEFINITION Scan;
+ PCSRSS_API_DEFINITION New;
+
+ DPRINT("CSR: %s called\n", __FUNCTION__);
+
+ NewCount = 0;
+ for (Scan = NewDefinitions; 0 != Scan->Handler; Scan++)
+ {
+ NewCount++;
+ }
+
+ New = RtlAllocateHeap(CsrHeap, 0,
+ (ApiDefinitionsCount + NewCount)
+ * sizeof(CSRSS_API_DEFINITION));
+ if (NULL == New)
+ {
+ DPRINT1("Unable to allocate memory\n");
+ return STATUS_NO_MEMORY;
+ }
+ if (0 != ApiDefinitionsCount)
+ {
+ RtlCopyMemory(New, ApiDefinitions,
+ ApiDefinitionsCount * sizeof(CSRSS_API_DEFINITION));
+ RtlFreeHeap(CsrHeap, 0, ApiDefinitions);
+ }
+ RtlCopyMemory(New + ApiDefinitionsCount, NewDefinitions,
+ NewCount * sizeof(CSRSS_API_DEFINITION));
+ ApiDefinitions = New;
+ ApiDefinitionsCount += NewCount;
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+FASTCALL
+CsrApiCallHandler(PCSR_PROCESS ProcessData,
+ PCSR_API_MESSAGE Request)
+{
+ unsigned DefIndex;
+ ULONG Type;
+
+ DPRINT("CSR: Calling handler for type: %x.\n", Request->Type);
+ Type = Request->Type & 0xFFFF; /* FIXME: USE MACRO */
+ DPRINT("CSR: API Number: %x ServerID: %x\n",Type, Request->Type >> 16);
+
+ /* FIXME: Extract DefIndex instead of looping */
+ for (DefIndex = 0; DefIndex < ApiDefinitionsCount; DefIndex++)
+ {
+ if (ApiDefinitions[DefIndex].Type == Type)
+ {
+ if (Request->Header.u1.s1.DataLength < ApiDefinitions[DefIndex].MinRequestSize)
+ {
+ DPRINT1("Request type %d min request size %d actual %d\n",
+ Type, ApiDefinitions[DefIndex].MinRequestSize,
+ Request->Header.u1.s1.DataLength);
+ Request->Status = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ Request->Status = (ApiDefinitions[DefIndex].Handler)(ProcessData, Request);
+ }
+ return;
+ }
+ }
+ DPRINT1("CSR: Unknown request type 0x%x\n", Request->Type);
+ Request->Status = STATUS_INVALID_SYSTEM_SERVICE;
+}
+
+VOID
+CallHardError(IN PCSR_THREAD ThreadData,
+ IN PHARDERROR_MSG HardErrorMessage);
+
+static
+VOID
+NTAPI
+CsrHandleHardError(IN PCSR_THREAD ThreadData,
+ IN OUT PHARDERROR_MSG Message)
+{
+ DPRINT1("CSR: received hard error %lx\n", Message->Status);
+
+ /* Call the hard error handler in win32csr */
+ CallHardError(ThreadData, Message);
+}
+
+/*++
+ * @name CsrCallServerFromServer
+ * @implemented NT4
+ *
+ * The CsrCallServerFromServer routine calls a CSR API from within a server.
+ * It avoids using LPC messages since the request isn't coming from a client.
+ *
+ * @param ReceiveMsg
+ * Pointer to the CSR API Message to send to the server.
+ *
+ * @param ReplyMsg
+ * Pointer to the CSR API Message to receive from the server.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_ILLEGAL_FUNCTION
+ * if the opcode is invalid, or STATUS_ACCESS_VIOLATION if there
+ * was a problem executing the API.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrCallServerFromServer(PCSR_API_MESSAGE ReceiveMsg,
+ PCSR_API_MESSAGE ReplyMsg)
+{
+#if 0 // real code
+ ULONG ServerId;
+ PCSR_SERVER_DLL ServerDll;
+ ULONG ApiId;
+ ULONG Reply;
+ NTSTATUS Status;
+
+ /* Get the Server ID */
+ ServerId = CSR_SERVER_ID_FROM_OPCODE(ReceiveMsg->Opcode);
+
+ /* Make sure that the ID is within limits, and the Server DLL loaded */
+ if ((ServerId >= CSR_SERVER_DLL_MAX) ||
+ (!(ServerDll = CsrLoadedServerDll[ServerId])))
+ {
+ /* We are beyond the Maximum Server ID */
+ DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n", ServerId, ServerDll);
+ ReplyMsg->Status = (ULONG)STATUS_ILLEGAL_FUNCTION;
+ return STATUS_ILLEGAL_FUNCTION;
+ }
+ else
+ {
+ /* Get the API ID */
+ ApiId = CSR_API_ID_FROM_OPCODE(ReceiveMsg->Opcode);
+
+ /* Normalize it with our Base ID */
+ ApiId -= ServerDll->ApiBase;
+
+ /* Make sure that the ID is within limits, and the entry exists */
+ if ((ApiId >= ServerDll->HighestApiSupported) ||
+ ((ServerDll->ValidTable) && !(ServerDll->ValidTable[ApiId])))
+ {
+ /* We are beyond the Maximum API ID, or it doesn't exist */
+ DPRINT1("CSRSS: %lx (%s) is invalid ApiTableIndex for %Z or is an "
+ "invalid API to call from the server.\n",
+ ServerDll->ValidTable[ApiId],
+ ((ServerDll->NameTable) && (ServerDll->NameTable[ApiId])) ?
+ ServerDll->NameTable[ApiId] : "*** UNKNOWN ***", &ServerDll->Name);
+ DbgBreakPoint();
+ ReplyMsg->Status = (ULONG)STATUS_ILLEGAL_FUNCTION;
+ return STATUS_ILLEGAL_FUNCTION;
+ }
+ }
+
+ if (CsrDebug & 2)
+ {
+ DPRINT1("CSRSS: %s Api Request received from server process\n",
+ ServerDll->NameTable[ApiId]);
+ }
+
+ /* Validation complete, start SEH */
+ _SEH2_TRY
+ {
+ /* Call the API and get the result */
+ Status = (ServerDll->DispatchTable[ApiId])(ReceiveMsg, &Reply);
+
+ /* Return the result, no matter what it is */
+ ReplyMsg->Status = Status;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* If we got an exception, return access violation */
+ ReplyMsg->Status = STATUS_ACCESS_VIOLATION;
+ }
+ _SEH2_END;
+
+ /* Return success */
+ return STATUS_SUCCESS;
+
+#else // Hacky reactos code
+
+ PCSR_PROCESS ProcessData;
+
+ /* Get the Process Data */
+ CsrLockProcessByClientId(&ReceiveMsg->Header.ClientId.UniqueProcess, &ProcessData);
+ if (!ProcessData)
+ {
+ DPRINT1("Message: Unable to find data for process 0x%x\n",
+ ReceiveMsg->Header.ClientId.UniqueProcess);
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ /* Validation complete, start SEH */
+ _SEH2_TRY
+ {
+ /* Call the API and get the result */
+ CsrApiCallHandler(ProcessData, ReplyMsg);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* If we got an exception, return access violation */
+ ReplyMsg->Status = STATUS_ACCESS_VIOLATION;
+ }
+ _SEH2_END;
+
+ /* Release the process reference */
+ CsrUnlockProcess(ProcessData);
+
+ /* Return success */
+ return STATUS_SUCCESS;
+#endif
+}
+
+/*++
+ * @name CsrApiPortInitialize
+ *
+ * The CsrApiPortInitialize routine initializes the LPC Port used for
+ * communications with the Client/Server Runtime (CSR) and initializes the
+ * static thread that will handle connection requests and APIs.
+ *
+ * @param None
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrApiPortInitialize(VOID)
+{
+ ULONG Size;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ NTSTATUS Status;
+ HANDLE hRequestEvent, hThread;
+ CLIENT_ID ClientId;
+ PLIST_ENTRY ListHead, NextEntry;
+ PCSR_THREAD ServerThread;
+
+ /* Calculate how much space we'll need for the Port Name */
+ Size = CsrDirectoryName.Length + sizeof(CSR_PORT_NAME) + sizeof(WCHAR);
+
+ /* Create the buffer for it */
+ CsrApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
+ if (!CsrApiPortName.Buffer) return STATUS_NO_MEMORY;
+
+ /* Setup the rest of the empty string */
+ CsrApiPortName.Length = 0;
+ CsrApiPortName.MaximumLength = (USHORT)Size;
+ RtlAppendUnicodeStringToString(&CsrApiPortName, &CsrDirectoryName);
+ RtlAppendUnicodeToString(&CsrApiPortName, UNICODE_PATH_SEP);
+ RtlAppendUnicodeToString(&CsrApiPortName, CSR_PORT_NAME);
+ if (CsrDebug & 1)
+ {
+ DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName);
+ DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
+ sizeof(CSR_CONNECTION_INFO), sizeof(CSR_API_MESSAGE));
+ }
+
+ /* FIXME: Create a Security Descriptor */
+
+ /* Initialize the Attributes */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &CsrApiPortName,
+ 0,
+ NULL,
+ NULL /* FIXME*/);
+
+ /* Create the Port Object */
+ Status = NtCreatePort(&CsrApiPort,
+ &ObjectAttributes,
+ LPC_MAX_DATA_LENGTH, // hack ; sizeof(CSR_CONNECTION_INFO),
+ LPC_MAX_MESSAGE_LENGTH, // hack ; sizeof(CSR_API_MESSAGE),
+ 16 * PAGE_SIZE);
+ if (NT_SUCCESS(Status))
+ {
+ /* Create the event the Port Thread will use */
+ Status = NtCreateEvent(&hRequestEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE);
+ if (NT_SUCCESS(Status))
+ {
+ /* Create the Request Thread */
+ Status = RtlCreateUserThread(NtCurrentProcess(),
+ NULL,
+ TRUE,
+ 0,
+ 0,
+ 0,
+ (PVOID)ClientConnectionThread,//CsrApiRequestThread,
+ (PVOID)hRequestEvent,
+ &hThread,
+ &ClientId);
+ if (NT_SUCCESS(Status))
+ {
+ /* Add this as a static thread to CSRSRV */
+ CsrAddStaticServerThread(hThread, &ClientId, CsrThreadIsServerThread);
+
+ /* Get the Thread List Pointers */
+ ListHead = &CsrRootProcess->ThreadList;
+ NextEntry = ListHead->Flink;
+
+ /* Start looping the list */
+ while (NextEntry != ListHead)
+ {
+ /* Get the Thread */
+ ServerThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
+
+ /* Start it up */
+ Status = NtResumeThread(ServerThread->ThreadHandle, NULL);
+
+ /* Is this a Server Thread? */
+ if (ServerThread->Flags & CsrThreadIsServerThread)
+ {
+ /* If so, then wait for it to initialize */
+ Status = NtWaitForSingleObject(hRequestEvent, FALSE, NULL);
+ ASSERT(NT_SUCCESS(Status));
+ }
+
+ /* Next thread */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* We don't need this anymore */
+ NtClose(hRequestEvent);
+ }
+ }
+ }
+
+ /* Return */
+ return Status;
+}
+
+PBASE_STATIC_SERVER_DATA BaseStaticServerData;
+
+NTSTATUS
+NTAPI
+CreateBaseAcls(OUT PACL* Dacl,
+ OUT PACL* RestrictedDacl)
+{
+ PSID SystemSid, WorldSid, RestrictedSid;
+ SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
+ SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
+ NTSTATUS Status;
+ UCHAR KeyValueBuffer[0x40];
+ PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
+ UNICODE_STRING KeyName;
+ ULONG ProtectionMode = 0;
+ ULONG AclLength, ResultLength;
+ HANDLE hKey;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+
+ /* Open the Session Manager Key */
+ RtlInitUnicodeString(&KeyName, SM_REG_KEY);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
+ if (NT_SUCCESS(Status))
+ {
+ /* Read the key value */
+ RtlInitUnicodeString(&KeyName, L"ProtectionMode");
+ Status = NtQueryValueKey(hKey,
+ &KeyName,
+ KeyValuePartialInformation,
+ KeyValueBuffer,
+ sizeof(KeyValueBuffer),
+ &ResultLength);
+
+ /* Make sure it's what we expect it to be */
+ KeyValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
+ if ((NT_SUCCESS(Status)) && (KeyValuePartialInfo->Type == REG_DWORD) &&
+ (*(PULONG)KeyValuePartialInfo->Data))
+ {
+ /* Save the Protection Mode */
+ ProtectionMode = *(PULONG)KeyValuePartialInfo->Data;
+ }
+
+ /* Close the handle */
+ NtClose(hKey);
+ }
+
+ /* Allocate the System SID */
+ Status = RtlAllocateAndInitializeSid(&NtAuthority,
+ 1, SECURITY_LOCAL_SYSTEM_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &SystemSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Allocate the World SID */
+ Status = RtlAllocateAndInitializeSid(&WorldAuthority,
+ 1, SECURITY_WORLD_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &WorldSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Allocate the restricted SID */
+ Status = RtlAllocateAndInitializeSid(&NtAuthority,
+ 1, SECURITY_RESTRICTED_CODE_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &RestrictedSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Allocate one ACL with 3 ACEs each for one SID */
+ AclLength = sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) +
+ RtlLengthSid(SystemSid) +
+ RtlLengthSid(RestrictedSid) +
+ RtlLengthSid(WorldSid);
+ *Dacl = RtlAllocateHeap(CsrHeap, 0, AclLength);
+ ASSERT(*Dacl != NULL);
+
+ /* Set the correct header fields */
+ Status = RtlCreateAcl(*Dacl, AclLength, ACL_REVISION2);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Give the appropriate rights to each SID */
+ /* FIXME: Should check SessionId/ProtectionMode */
+ Status = RtlAddAccessAllowedAce(*Dacl, ACL_REVISION2, DIRECTORY_QUERY | DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_SUBDIRECTORY | READ_CONTROL, WorldSid);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(*Dacl, ACL_REVISION2, DIRECTORY_ALL_ACCESS, SystemSid);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(*Dacl, ACL_REVISION2, DIRECTORY_TRAVERSE, RestrictedSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Now allocate the restricted DACL */
+ *RestrictedDacl = RtlAllocateHeap(CsrHeap, 0, AclLength);
+ ASSERT(*RestrictedDacl != NULL);
+
+ /* Initialize it */
+ Status = RtlCreateAcl(*RestrictedDacl, AclLength, ACL_REVISION2);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* And add the same ACEs as before */
+ /* FIXME: Not really fully correct */
+ Status = RtlAddAccessAllowedAce(*RestrictedDacl, ACL_REVISION2, DIRECTORY_QUERY | DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_SUBDIRECTORY | READ_CONTROL, WorldSid);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(*RestrictedDacl, ACL_REVISION2, DIRECTORY_ALL_ACCESS, SystemSid);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(*RestrictedDacl, ACL_REVISION2, DIRECTORY_TRAVERSE, RestrictedSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* The SIDs are captured, can free them now */
+ RtlFreeHeap(CsrHeap, 0, SystemSid);
+ RtlFreeHeap(CsrHeap, 0, WorldSid);
+ RtlFreeHeap(CsrHeap, 0, RestrictedSid);
+ return Status;
+}
+
+VOID
+WINAPI
+BasepFakeStaticServerData(VOID)
+{
+ NTSTATUS Status;
+ WCHAR Buffer[MAX_PATH];
+ PWCHAR HeapBuffer;
+ UNICODE_STRING SystemRootString;
+ UNICODE_STRING UnexpandedSystemRootString = RTL_CONSTANT_STRING(L"%SystemRoot%");
+ UNICODE_STRING BaseSrvCSDString;
+ UNICODE_STRING BaseSrvWindowsDirectory;
+ UNICODE_STRING BaseSrvWindowsSystemDirectory;
+ UNICODE_STRING BnoString;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ ULONG SessionId;
+ HANDLE BaseSrvNamedObjectDirectory;
+ HANDLE BaseSrvRestrictedObjectDirectory;
+ PACL BnoDacl, BnoRestrictedDacl;
+ PSECURITY_DESCRIPTOR BnoSd;
+ HANDLE SymHandle;
+ UNICODE_STRING DirectoryName, SymlinkName;
+ ULONG LuidEnabled;
+ RTL_QUERY_REGISTRY_TABLE BaseServerRegistryConfigurationTable[2] =
+ {
+ {
+ NULL,
+ RTL_QUERY_REGISTRY_DIRECT,
+ L"CSDVersion",
+ &BaseSrvCSDString
+ },
+ {0}
+ };
+
+ /* Get the session ID */
+ SessionId = NtCurrentPeb()->SessionId;
+
+ /* Get the Windows directory */
+ RtlInitEmptyUnicodeString(&SystemRootString, Buffer, sizeof(Buffer));
+ Status = RtlExpandEnvironmentStrings_U(NULL,
+ &UnexpandedSystemRootString,
+ &SystemRootString,
+ NULL);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Create the base directory */
+ Buffer[SystemRootString.Length / sizeof(WCHAR)] = UNICODE_NULL;
+ Status = RtlCreateUnicodeString(&BaseSrvWindowsDirectory,
+ SystemRootString.Buffer);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Create the system directory */
+ wcscat(SystemRootString.Buffer, L"\\system32");
+ Status = RtlCreateUnicodeString(&BaseSrvWindowsSystemDirectory,
+ SystemRootString.Buffer);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* FIXME: Check Session ID */
+ wcscpy(Buffer, L"\\BaseNamedObjects");
+ RtlInitUnicodeString(&BnoString, Buffer);
+
+ /* Allocate the server data */
+ BaseStaticServerData = RtlAllocateHeap(CsrSrvSharedSectionHeap,
+ HEAP_ZERO_MEMORY,
+ sizeof(BASE_STATIC_SERVER_DATA));
+ ASSERT(BaseStaticServerData != NULL);
+
+ /* Process timezone information */
+ BaseStaticServerData->TermsrvClientTimeZoneId = TIME_ZONE_ID_INVALID;
+ BaseStaticServerData->TermsrvClientTimeZoneChangeNum = 0;
+ Status = NtQuerySystemInformation(SystemTimeOfDayInformation,
+ &BaseStaticServerData->TimeOfDay,
+ sizeof(BaseStaticServerData->TimeOfDay),
+ NULL);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Make a shared heap copy of the Windows directory */
+ BaseStaticServerData->WindowsDirectory = BaseSrvWindowsDirectory;
+ HeapBuffer = RtlAllocateHeap(CsrSrvSharedSectionHeap,
+ 0,
+ BaseSrvWindowsDirectory.MaximumLength);
+ ASSERT(HeapBuffer);
+ RtlCopyMemory(HeapBuffer,
+ BaseStaticServerData->WindowsDirectory.Buffer,
+ BaseSrvWindowsDirectory.MaximumLength);
+ BaseStaticServerData->WindowsDirectory.Buffer = HeapBuffer;
+
+ /* Make a shared heap copy of the System directory */
+ BaseStaticServerData->WindowsSystemDirectory = BaseSrvWindowsSystemDirectory;
+ HeapBuffer = RtlAllocateHeap(CsrSrvSharedSectionHeap,
+ 0,
+ BaseSrvWindowsSystemDirectory.MaximumLength);
+ ASSERT(HeapBuffer);
+ RtlCopyMemory(HeapBuffer,
+ BaseStaticServerData->WindowsSystemDirectory.Buffer,
+ BaseSrvWindowsSystemDirectory.MaximumLength);
+ BaseStaticServerData->WindowsSystemDirectory.Buffer = HeapBuffer;
+
+ /* This string is not used */
+ RtlInitEmptyUnicodeString(&BaseStaticServerData->WindowsSys32x86Directory,
+ NULL,
+ 0);
+
+ /* Make a shared heap copy of the BNO directory */
+ BaseStaticServerData->NamedObjectDirectory = BnoString;
+ BaseStaticServerData->NamedObjectDirectory.MaximumLength = BnoString.Length +
+ sizeof(UNICODE_NULL);
+ HeapBuffer = RtlAllocateHeap(CsrSrvSharedSectionHeap,
+ 0,
+ BaseStaticServerData->NamedObjectDirectory.MaximumLength);
+ ASSERT(HeapBuffer);
+ RtlCopyMemory(HeapBuffer,
+ BaseStaticServerData->NamedObjectDirectory.Buffer,
+ BaseStaticServerData->NamedObjectDirectory.MaximumLength);
+ BaseStaticServerData->NamedObjectDirectory.Buffer = HeapBuffer;
+
+ /*
+ * Confirmed that in Windows, CSDNumber and RCNumber are actually Length
+ * and MaximumLength of the CSD String, since the same UNICODE_STRING is
+ * being queried twice, the first time as a ULONG!
+ *
+ * Somehow, in Windows this doesn't cause a buffer overflow, but it might
+ * in ReactOS, so this code is disabled until someone figures out WTF.
+ */
+ BaseStaticServerData->CSDNumber = 0;
+ BaseStaticServerData->RCNumber = 0;
+
+ /* Initialize the CSD string and query its value from the registry */
+ RtlInitEmptyUnicodeString(&BaseSrvCSDString, Buffer, sizeof(Buffer));
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
+ L"",
+ BaseServerRegistryConfigurationTable,
+ NULL,
+ NULL);
+ if (NT_SUCCESS(Status))
+ {
+ /* Copy into the shared buffer */
+ wcsncpy(BaseStaticServerData->CSDVersion,
+ BaseSrvCSDString.Buffer,
+ BaseSrvCSDString.Length / sizeof(WCHAR));
+ }
+ else
+ {
+ /* NULL-terminate to indicate nothing is there */
+ BaseStaticServerData->CSDVersion[0] = UNICODE_NULL;
+ }
+
+ /* Cache the system information */
+ Status = NtQuerySystemInformation(SystemBasicInformation,
+ &BaseStaticServerData->SysInfo,
+ sizeof(BaseStaticServerData->SysInfo),
+ NULL);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* FIXME: Should query the registry for these */
+ BaseStaticServerData->DefaultSeparateVDM = FALSE;
+ BaseStaticServerData->IsWowTaskReady = FALSE;
+
+ /* Allocate a security descriptor and create it */
+ BnoSd = RtlAllocateHeap(CsrHeap, 0, 1024);
+ ASSERT(BnoSd);
+ Status = RtlCreateSecurityDescriptor(BnoSd, SECURITY_DESCRIPTOR_REVISION);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Create the BNO and \Restricted DACLs */
+ Status = CreateBaseAcls(&BnoDacl, &BnoRestrictedDacl);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Set the BNO DACL as active for now */
+ Status = RtlSetDaclSecurityDescriptor(BnoSd, TRUE, BnoDacl, FALSE);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Create the BNO directory */
+ RtlInitUnicodeString(&BnoString, L"\\BaseNamedObjects");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &BnoString,
+ OBJ_OPENIF | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
+ NULL,
+ BnoSd);
+ Status = NtCreateDirectoryObject(&BaseSrvNamedObjectDirectory,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Check if we are session 0 */
+ if (!SessionId)
+ {
+ /* Mark this as a session 0 directory */
+ Status = NtSetInformationObject(BaseSrvNamedObjectDirectory,
+ ObjectSessionInformation,
+ NULL,
+ 0);
+ ASSERT(NT_SUCCESS(Status));
+ }
+
+ /* Check if LUID device maps are enabled */
+ Status = NtQueryInformationProcess(NtCurrentProcess(),
+ ProcessLUIDDeviceMapsEnabled,
+ &LuidEnabled,
+ sizeof(LuidEnabled),
+ NULL);
+ ASSERT(NT_SUCCESS(Status));
+ BaseStaticServerData->LUIDDeviceMapsEnabled = LuidEnabled;
+ if (!BaseStaticServerData->LUIDDeviceMapsEnabled)
+ {
+ /* Make Global point back to BNO */
+ RtlInitUnicodeString(&DirectoryName, L"Global");
+ RtlInitUnicodeString(&SymlinkName, L"\\BaseNamedObjects");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &DirectoryName,
+ OBJ_OPENIF | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
+ BaseSrvNamedObjectDirectory,
+ BnoSd);
+ Status = NtCreateSymbolicLinkObject(&SymHandle,
+ SYMBOLIC_LINK_ALL_ACCESS,
+ &ObjectAttributes,
+ &SymlinkName);
+ if ((NT_SUCCESS(Status)) && !(SessionId)) NtClose(SymHandle);
+
+ /* Make local point back to \Sessions\x\BNO */
+ RtlInitUnicodeString(&DirectoryName, L"Local");
+ ASSERT(SessionId == 0);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &DirectoryName,
+ OBJ_OPENIF | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
+ BaseSrvNamedObjectDirectory,
+ BnoSd);
+ Status = NtCreateSymbolicLinkObject(&SymHandle,
+ SYMBOLIC_LINK_ALL_ACCESS,
+ &ObjectAttributes,
+ &SymlinkName);
+ if ((NT_SUCCESS(Status)) && !(SessionId)) NtClose(SymHandle);
+
+ /* Make Session point back to BNOLINKS */
+ RtlInitUnicodeString(&DirectoryName, L"Session");
+ RtlInitUnicodeString(&SymlinkName, L"\\Sessions\\BNOLINKS");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &DirectoryName,
+ OBJ_OPENIF | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
+ BaseSrvNamedObjectDirectory,
+ BnoSd);
+ Status = NtCreateSymbolicLinkObject(&SymHandle,
+ SYMBOLIC_LINK_ALL_ACCESS,
+ &ObjectAttributes,
+ &SymlinkName);
+ if ((NT_SUCCESS(Status)) && !(SessionId)) NtClose(SymHandle);
+
+ /* Create the BNO\Restricted directory and set the restricted DACL */
+ RtlInitUnicodeString(&DirectoryName, L"Restricted");
+ Status = RtlSetDaclSecurityDescriptor(BnoSd, TRUE, BnoRestrictedDacl, FALSE);
+ ASSERT(NT_SUCCESS(Status));
+ InitializeObjectAttributes(&ObjectAttributes,
+ &DirectoryName,
+ OBJ_OPENIF | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
+ BaseSrvNamedObjectDirectory,
+ BnoSd);
+ Status = NtCreateDirectoryObject(&BaseSrvRestrictedObjectDirectory,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes);
+ ASSERT(NT_SUCCESS(Status));
+ }
+
+ /* Finally, set the pointer */
+ CsrSrvSharedStaticServerData[CSR_CONSOLE] = BaseStaticServerData;
+}
+
+NTSTATUS WINAPI
+CsrpHandleConnectionRequest(PPORT_MESSAGE Request)
+{
+ NTSTATUS Status;
+ HANDLE ServerPort = NULL;//, ServerThread = NULL;
+ PCSR_PROCESS ProcessData = NULL;
+ REMOTE_PORT_VIEW RemotePortView;
+// CLIENT_ID ClientId;
+ BOOLEAN AllowConnection = FALSE;
+ PCSR_CONNECTION_INFO ConnectInfo;
+ ServerPort = NULL;
+
+ DPRINT("CSR: %s: Handling: %p\n", __FUNCTION__, Request);
+
+ ConnectInfo = (PCSR_CONNECTION_INFO)(Request + 1);
+
+ /* Save the process ID */
+ RtlZeroMemory(ConnectInfo, sizeof(CSR_CONNECTION_INFO));
+
+ CsrLockProcessByClientId(Request->ClientId.UniqueProcess, &ProcessData);
+ if (!ProcessData)
+ {
+ DPRINT1("CSRSRV: Unknown process: %lx. Will be rejecting connection\n",
+ Request->ClientId.UniqueProcess);
+ }
+
+ if ((ProcessData) && (ProcessData != CsrRootProcess))
+ {
+ /* Attach the Shared Section */
+ Status = CsrSrvAttachSharedSection(ProcessData, ConnectInfo);
+ if (NT_SUCCESS(Status))
+ {
+ DPRINT("Connection ok\n");
+ AllowConnection = TRUE;
+ }
+ else
+ {
+ DPRINT1("Shared section map failed: %lx\n", Status);
+ }
+ }
+ else if (ProcessData == CsrRootProcess)
+ {
+ AllowConnection = TRUE;
+ }
+
+ /* Release the process */
+ if (ProcessData) CsrUnlockProcess(ProcessData);
+
+ /* Setup the Port View Structure */
+ RemotePortView.Length = sizeof(REMOTE_PORT_VIEW);
+ RemotePortView.ViewSize = 0;
+ RemotePortView.ViewBase = NULL;
+
+ /* Save the Process ID */
+ ConnectInfo->ProcessId = NtCurrentTeb()->ClientId.UniqueProcess;
+
+ Status = NtAcceptConnectPort(&ServerPort,
+ AllowConnection ? UlongToPtr(ProcessData->SequenceNumber) : 0,
+ Request,
+ AllowConnection,
+ NULL,
+ &RemotePortView);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status);
+ }
+ else if (AllowConnection)
+ {
+ if (CsrDebug & 2)
+ {
+ DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
+ Request->ClientId.UniqueProcess,
+ Request->ClientId.UniqueThread,
+ RemotePortView.ViewBase,
+ RemotePortView.ViewSize);
+ }
+
+ /* Set some Port Data in the Process */
+ ProcessData->ClientPort = ServerPort;
+ ProcessData->ClientViewBase = (ULONG_PTR)RemotePortView.ViewBase;
+ ProcessData->ClientViewBounds = (ULONG_PTR)((ULONG_PTR)RemotePortView.ViewBase +
+ (ULONG_PTR)RemotePortView.ViewSize);
+
+ /* Complete the connection */
+ Status = NtCompleteConnectPort(ServerPort);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status);
+ }
+ }
+ else
+ {
+ DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
+ Request->ClientId.UniqueProcess,
+ Request->ClientId.UniqueThread);
+ }
+
+ return Status;
+}
+
+/*++
+ * @name CsrConnectToUser
+ * @implemented NT4
+ *
+ * The CsrConnectToUser connects to the User subsystem.
+ *
+ * @param None
+ *
+ * @return A pointer to the CSR Thread
+ *
+ * @remarks None.
+ *
+ *--*/
+PCSR_THREAD
+NTAPI
+CsrConnectToUser(VOID)
+{
+ PTEB Teb = NtCurrentTeb();
+ PCSR_THREAD CsrThread;
+#if 0
+ NTSTATUS Status;
+ ANSI_STRING DllName;
+ UNICODE_STRING TempName;
+ HANDLE hUser32;
+ STRING StartupName;
+
+ /* Check if we didn't already find it */
+ if (!CsrClientThreadSetup)
+ {
+ /* Get the DLL Handle for user32.dll */
+ RtlInitAnsiString(&DllName, "user32");
+ RtlAnsiStringToUnicodeString(&TempName, &DllName, TRUE);
+ Status = LdrGetDllHandle(NULL,
+ NULL,
+ &TempName,
+ &hUser32);
+ RtlFreeUnicodeString(&TempName);
+
+ /* If we got teh handle, get the Client Thread Startup Entrypoint */
+ if (NT_SUCCESS(Status))
+ {
+ RtlInitAnsiString(&StartupName,"ClientThreadSetup");
+ Status = LdrGetProcedureAddress(hUser32,
+ &StartupName,
+ 0,
+ (PVOID)&CsrClientThreadSetup);
+ }
+ }
+
+ /* Connect to user32 */
+ CsrClientThreadSetup();
+#endif
+ /* Save pointer to this thread in TEB */
+ CsrThread = CsrLocateThreadInProcess(NULL, &Teb->ClientId);
+ if (CsrThread) Teb->CsrClientThread = CsrThread;
+
+ /* Return it */
+ return CsrThread;
+}
+
+/*++
+ * @name CsrpCheckRequestThreads
+ *
+ * The CsrpCheckRequestThreads routine checks if there are no more threads
+ * to handle CSR API Requests, and creates a new thread if possible, to
+ * avoid starvation.
+ *
+ * @param None.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * if a new thread couldn't be created.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrpCheckRequestThreads(VOID)
+{
+ HANDLE hThread;
+ CLIENT_ID ClientId;
+ NTSTATUS Status;
+
+ /* Decrease the count, and see if we're out */
+ if (!(_InterlockedDecrement(&CsrpStaticThreadCount)))
+ {
+ /* Check if we've still got space for a Dynamic Thread */
+ if (CsrpDynamicThreadTotal < CsrMaxApiRequestThreads)
+ {
+ /* Create a new dynamic thread */
+ Status = RtlCreateUserThread(NtCurrentProcess(),
+ NULL,
+ TRUE,
+ 0,
+ 0,
+ 0,
+ (PVOID)ClientConnectionThread,//CsrApiRequestThread,
+ NULL,
+ &hThread,
+ &ClientId);
+ /* Check success */
+ if (NT_SUCCESS(Status))
+ {
+ /* Increase the thread counts */
+ _InterlockedIncrement(&CsrpStaticThreadCount);
+ _InterlockedIncrement(&CsrpDynamicThreadTotal);
+
+ /* Add a new server thread */
+ if (CsrAddStaticServerThread(hThread,
+ &ClientId,
+ CsrThreadIsServerThread))
+ {
+ /* Activate it */
+ NtResumeThread(hThread, NULL);
+ }
+ else
+ {
+ /* Failed to create a new static thread */
+ _InterlockedDecrement(&CsrpStaticThreadCount);
+ _InterlockedDecrement(&CsrpDynamicThreadTotal);
+
+ /* Terminate it */
+ DPRINT1("Failing\n");
+ NtTerminateThread(hThread, 0);
+ NtClose(hThread);
+
+ /* Return */
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+ }
+ }
+
+ /* Success */
+ return STATUS_SUCCESS;
+}
+
+VOID
+WINAPI
+ClientConnectionThread(IN PVOID Parameter)
+{
+ PTEB Teb = NtCurrentTeb();
+ LARGE_INTEGER TimeOut;
+ NTSTATUS Status;
+ BYTE RawRequest[LPC_MAX_DATA_LENGTH];
+ PCSR_API_MESSAGE Request = (PCSR_API_MESSAGE)RawRequest;
+ PCSR_API_MESSAGE Reply;
+ PCSR_PROCESS CsrProcess;
+ PCSR_THREAD ServerThread, CsrThread;
+ ULONG MessageType;
+ HANDLE ReplyPort;
+ PDBGKM_MSG DebugMessage;
+ PHARDERROR_MSG HardErrorMsg;
+ PCLIENT_DIED_MSG ClientDiedMsg;
+ DPRINT("CSR: %s called\n", __FUNCTION__);
+
+ /* Setup LPC loop port and message */
+ Reply = NULL;
+ ReplyPort = CsrApiPort;
+
+ /* Connect to user32 */
+ while (!CsrConnectToUser())
+ {
+ /* Set up the timeout for the connect (30 seconds) */
+ TimeOut.QuadPart = -30 * 1000 * 1000 * 10;
+
+ /* Keep trying until we get a response */
+ Teb->Win32ClientInfo[0] = 0;
+ NtDelayExecution(FALSE, &TimeOut);
+ }
+
+ /* Get our thread */
+ ServerThread = Teb->CsrClientThread;
+
+ /* If we got an event... */
+ if (Parameter)
+ {
+ /* Set it, to let stuff waiting on us load */
+ Status = NtSetEvent((HANDLE)Parameter, NULL);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Increase the Thread Counts */
+ _InterlockedIncrement(&CsrpStaticThreadCount);
+ _InterlockedIncrement(&CsrpDynamicThreadTotal);
+ }
+
+ /* Now start the loop */
+ while (TRUE)
+ {
+ /* Make sure the real CID is set */
+ Teb->RealClientId = Teb->ClientId;
+
+ /* Debug check */
+ if (Teb->CountOfOwnedCriticalSections)
+ {
+ DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
+ Teb->CountOfOwnedCriticalSections);
+ DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
+ Request, Reply);
+ DbgBreakPoint();
+ }
+
+ /* Send the reply and wait for a new request */
+ DPRINT("Replying to: %lx (%lx)\n", ReplyPort, CsrApiPort);
+ Status = NtReplyWaitReceivePort(ReplyPort,
+ 0,
+ &Reply->Header,
+ &Request->Header);
+ /* Check if we didn't get success */
+ if (Status != STATUS_SUCCESS)
+ {
+ /* Was it a failure or another success code? */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Check for specific status cases */
+ if ((Status != STATUS_INVALID_CID) &&
+ (Status != STATUS_UNSUCCESSFUL) &&
+ ((Status == STATUS_INVALID_HANDLE) || (ReplyPort == CsrApiPort)))
+ {
+ /* Notify the debugger */
+ DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status);
+ DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort, CsrApiPort);
+ }
+
+ /* We failed big time, so start out fresh */
+ Reply = NULL;
+ ReplyPort = CsrApiPort;
+ DPRINT1("failed: %lx\n", Status);
+ continue;
+ }
+ else
+ {
+ /* A bizare "success" code, just try again */
+ DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status);
+ continue;
+ }
+ }
+
+ /* Use whatever Client ID we got */
+ Teb->RealClientId = Request->Header.ClientId;
+
+ /* Get the Message Type */
+ MessageType = Request->Header.u2.s2.Type;
+
+ /* Handle connection requests */
+ if (MessageType == LPC_CONNECTION_REQUEST)
+ {
+ /* Handle the Connection Request */
+ DPRINT("Accepting new connection\n");
+ CsrpHandleConnectionRequest((PPORT_MESSAGE)Request);
+ Reply = NULL;
+ ReplyPort = CsrApiPort;
+ continue;
+ }
+
+ /* It's some other kind of request. Get the lock for the lookup */
+ CsrAcquireProcessLock();
+
+ /* Now do the lookup to get the CSR_THREAD */
+ CsrThread = CsrLocateThreadByClientId(&CsrProcess,
+ &Request->Header.ClientId);
+
+ /* Did we find a thread? */
+ if (!CsrThread)
+ {
+ /* This wasn't a CSR Thread, release lock */
+ CsrReleaseProcessLock();
+
+ /* If this was an exception, handle it */
+ if (MessageType == LPC_EXCEPTION)
+ {
+ DPRINT1("Exception from unknown thread, just continue\n");
+ Reply = Request;
+ ReplyPort = CsrApiPort;
+ Reply->Status = DBG_CONTINUE;
+ }
+ else if (MessageType == LPC_PORT_CLOSED ||
+ MessageType == LPC_CLIENT_DIED)
+ {
+ /* The Client or Port are gone, loop again */
+ DPRINT("Death from unknown thread, just continue\n");
+ Reply = NULL;
+ ReplyPort = CsrApiPort;
+ }
+ else if (MessageType == LPC_ERROR_EVENT)
+ {
+ /* If it's a hard error, handle this too */
+ DPRINT1("Hard error from unknown thread, call handlers\n");
+HandleHardError:
+ HardErrorMsg = (PHARDERROR_MSG)Request;
+
+ /* Default it to unhandled */
+ HardErrorMsg->Response = ResponseNotHandled;
+
+ /* Check if there are free api threads */
+ CsrpCheckRequestThreads();
+ if (CsrpStaticThreadCount)
+ {
+ CsrHandleHardError(CsrThread, (PHARDERROR_MSG)Request);
+ }
+
+ /* If the response was 0xFFFFFFFF, we'll ignore it */
+ if (HardErrorMsg->Response == 0xFFFFFFFF)
+ {
+ Reply = NULL;
+ ReplyPort = CsrApiPort;
+ }
+ else
+ {
+ if (CsrThread) CsrDereferenceThread(CsrThread);
+ Reply = Request;
+ ReplyPort = CsrApiPort;
+ }
+ }
+ else if (MessageType == LPC_REQUEST)
+ {
+ /* This is an API Message coming from a non-CSR Thread */
+ DPRINT1("No thread found for request %lx and clientID %lx.%lx\n",
+ Request->Type & 0xFFFF,
+ Request->Header.ClientId.UniqueProcess,
+ Request->Header.ClientId.UniqueThread);
+ Reply = Request;
+ ReplyPort = CsrApiPort;
+ Reply->Status = STATUS_ILLEGAL_FUNCTION;
+ }
+ else if (MessageType == LPC_DATAGRAM)
+ {
+ DPRINT1("Kernel datagram: not yet supported\n");
+ Reply = NULL;
+ ReplyPort = CsrApiPort;
+ }
+ else
+ {
+ /* Some other ignored message type */
+ Reply = NULL;
+ ReplyPort = CsrApiPort;
+ }
+
+ /* Keep going */
+ continue;
+ }
+
+ /* We have a valid thread, was this an LPC Request? */
+ if (MessageType != LPC_REQUEST)
+ {
+ /* It's not an API, check if the client died */
+ if (MessageType == LPC_CLIENT_DIED)
+ {
+ /* Get the information and check if it matches our thread */
+ ClientDiedMsg = (PCLIENT_DIED_MSG)Request;
+ if (ClientDiedMsg->CreateTime.QuadPart == CsrThread->CreateTime.QuadPart)
+ {
+ /* Reference the thread */
+ CsrLockedReferenceThread(CsrThread);
+
+ /* Destroy the thread in the API Message */
+ CsrDestroyThread(&Request->Header.ClientId);
+
+ /* Check if the thread was actually ourselves */
+ if (CsrProcess->ThreadCount == 1)
+ {
+ /* Kill the process manually here */
+ DPRINT1("Last thread\n");
+ CsrDestroyProcess(&CsrThread->ClientId, 0);
+ }
+
+ /* Remove our extra reference */
+ CsrLockedDereferenceThread(CsrThread);
+ }
+
+ /* Release the lock and keep looping */
+ CsrReleaseProcessLock();
+ Reply = NULL;
+ ReplyPort = CsrApiPort;
+ continue;
+ }
+
+ /* Reference the thread and release the lock */
+ CsrLockedReferenceThread(CsrThread);
+ CsrReleaseProcessLock();
+
+ /* If this was an exception, handle it */
+ if (MessageType == LPC_EXCEPTION)
+ {
+ /* Kill the process */
+ DPRINT1("Exception in %lx.%lx. Killing...\n",
+ Request->Header.ClientId.UniqueProcess,
+ Request->Header.ClientId.UniqueThread);
+ NtTerminateProcess(CsrProcess->ProcessHandle, STATUS_ABANDONED);
+
+ /* Destroy it from CSR */
+ CsrDestroyProcess(&Request->Header.ClientId, STATUS_ABANDONED);
+
+ /* Return a Debug Message */
+ DebugMessage = (PDBGKM_MSG)Request;
+ DebugMessage->ReturnedStatus = DBG_CONTINUE;
+ Reply = Request;
+ ReplyPort = CsrApiPort;
+
+ /* Remove our extra reference */
+ CsrDereferenceThread(CsrThread);
+ }
+ else if (MessageType == LPC_ERROR_EVENT)
+ {
+ DPRINT1("Hard error from known CSR thread... handling\n");
+ goto HandleHardError;
+ }
+ else
+ {
+ /* Something else */
+ DPRINT1("Unhandled message type: %lx\n", MessageType);
+ CsrDereferenceThread(CsrThread);
+ Reply = NULL;
+ }
+
+ /* Keep looping */
+ continue;
+ }
+
+ /* We got an API Request */
+ CsrLockedReferenceThread(CsrThread);
+ CsrReleaseProcessLock();
+
+ /* Assume success */
+ Reply = Request;
+ Request->Status = STATUS_SUCCESS;
+
+ /* Now we reply to a particular client */
+ ReplyPort = CsrThread->Process->ClientPort;
+
+ DPRINT("CSR: Got CSR API: %x [Message Origin: %x]\n",
+ Request->Type,
+ Request->Header.ClientId.UniqueThread);
+
+ /* Validation complete, start SEH */
+ _SEH2_TRY
+ {
+ /* Make sure we have enough threads */
+ CsrpCheckRequestThreads();
+
+ /* Set the client thread pointer */
+ NtCurrentTeb()->CsrClientThread = CsrThread;
+
+ /* Call the Handler */
+ CsrApiCallHandler(CsrThread->Process, Request);
+
+ /* Increase the static thread count */
+ _InterlockedIncrement(&CsrpStaticThreadCount);
+
+ /* Restore the server thread */
+ NtCurrentTeb()->CsrClientThread = ServerThread;
+
+ /* Check if this is a dead client now */
+ if (Request->Type == 0xBABE)
+ {
+ /* Reply to the death message */
+ NtReplyPort(ReplyPort, &Reply->Header);
+
+ /* Reply back to the API port now */
+ ReplyPort = CsrApiPort;
+ Reply = NULL;
+
+ /* Drop the reference */
+ CsrDereferenceThread(CsrThread);
+ }
+ else
+ {
+ /* Drop the reference */
+ CsrDereferenceThread(CsrThread);
+ }
+ }
+ _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
+ {
+ Reply = NULL;
+ ReplyPort = CsrApiPort;
+ }
+ _SEH2_END;
+ }
+
+ /* Close the port and exit the thread */
+ // NtClose(ServerPort);
+
+ DPRINT1("CSR: %s done\n", __FUNCTION__);
+ /* We're out of the loop for some reason, terminate! */
+ NtTerminateThread(NtCurrentThread(), Status);
+ //return Status;
+}
+
+/*++
+ * @name CsrReleaseCapturedArguments
+ * @implemented NT5.1
+ *
+ * The CsrReleaseCapturedArguments routine releases a Capture Buffer
+ * that was previously captured with CsrCaptureArguments.
+ *
+ * @param ApiMessage
+ * Pointer to the CSR API Message containing the Capture Buffer
+ * that needs to be released.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage)
+{
+ PCSR_CAPTURE_BUFFER RemoteCaptureBuffer, LocalCaptureBuffer;
+ SIZE_T BufferDistance;
+ ULONG PointerCount;
+ ULONG_PTR **PointerOffsets, *CurrentPointer;
+
+ /* Get the capture buffers */
+ RemoteCaptureBuffer = ApiMessage->CsrCaptureData;
+ LocalCaptureBuffer = RemoteCaptureBuffer->PreviousCaptureBuffer;
+
+ /* Free the previous one */
+ RemoteCaptureBuffer->PreviousCaptureBuffer = NULL;
+
+ /* Find out the difference between the two buffers */
+ BufferDistance = (ULONG_PTR)LocalCaptureBuffer - (ULONG_PTR)RemoteCaptureBuffer;
+
+ /* Save the pointer count and offset pointer */
+ PointerCount = RemoteCaptureBuffer->PointerCount;
+ PointerOffsets = (ULONG_PTR**)(RemoteCaptureBuffer + 1);
+
+ /* Start the loop */
+ while (PointerCount)
+ {
+ /* Get the current pointer */
+ CurrentPointer = *PointerOffsets++;
+ if (CurrentPointer)
+ {
+ /* Add it to the CSR Message structure */
+ CurrentPointer += (ULONG_PTR)ApiMessage;
+
+ /* Modify the pointer to take into account its new position */
+ *CurrentPointer += BufferDistance;
+ }
+
+ /* Move to the next Pointer */
+ PointerCount--;
+ }
+
+ /* Copy the data back */
+ RtlMoveMemory(LocalCaptureBuffer, RemoteCaptureBuffer, RemoteCaptureBuffer->Size);
+
+ /* Free our allocated buffer */
+ RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer);
+}
+
+/* EOF */
--- /dev/null
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "Client/Server Runtime SubSystem Process\0"
+#define REACTOS_STR_INTERNAL_NAME "csrsrv\0"
+#define REACTOS_STR_ORIGINAL_FILENAME "csrsrv.dll\0"
+#include <reactos/version.rc>
--- /dev/null
+@ stdcall CsrAddStaticServerThread(ptr ptr long)
+@ stdcall CsrCallServerFromServer(ptr ptr)
+;@ stdcall CsrConnectToUser()
+;@ stdcall CsrCreateProcess(ptr ptr ptr ptr long ptr)
+@ stdcall CsrCreateRemoteThread(ptr ptr)
+@ stdcall CsrCreateThread(ptr ptr ptr)
+;@ stdcall CsrCreateWait(ptr ptr ptr ptr ptr ptr)
+;@ stdcall CsrDebugProcess(ptr)
+;@ stdcall CsrDebugProcessStop(ptr)
+;@ stdcall CsrDereferenceProcess(ptr)
+;@ stdcall CsrDereferenceThread(ptr)
+;@ stdcall CsrDereferenceWait(ptr)
+;@ stdcall CsrDestroyProcess(ptr long)
+;@ stdcall CsrDestroyThread(ptr)
+@ stdcall CsrEnumProcesses(ptr ptr) ; Temporary hack
+;@ stdcall CsrExecServerThread(ptr long)
+@ stdcall CsrGetProcessLuid(ptr ptr)
+@ stdcall CsrImpersonateClient(ptr)
+@ stdcall CsrLockProcessByClientId(ptr ptr)
+;@ stdcall CsrLockThreadByClientId(ptr ptr)
+;@ stdcall CsrMoveSatisfiedWait(ptr ptr)
+;@ stdcall CsrNotifyWait(ptr long ptr ptr)
+;@ stdcall CsrPopulateDosDevices()
+;@ stdcall CsrQueryApiPort()
+;@ stdcall CsrReferenceThread(ptr)
+@ stdcall CsrRevertToSelf()
+@ stdcall CsrServerInitialization(long ptr)
+;@ stdcall CsrSetBackgroundPriority(ptr)
+;@ stdcall CsrSetCallingSpooler(long)
+;@ stdcall CsrSetForegroundPriority(ptr)
+;@ stdcall CsrShutdownProcesses(ptr long)
+;@ stdcall CsrUnhandledExceptionFilter(ptr)
+@ stdcall CsrUnlockProcess(ptr)
+;@ stdcall CsrUnlockThread(ptr)
+;@ stdcall CsrValidateMessageBuffer(ptr ptr long long)
+;@ stdcall CsrValidateMessageString(ptr ptr)
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: subsys/csrss/include/api.h
+ * PURPOSE: CSRSS API interface
+ */
+
+#pragma once
+
+#define NTOS_MODE_USER
+#include <ndk/psfuncs.h>
+#include <ndk/rtlfuncs.h>
+
+#include <csrss/csrss.h>
+
+#define CSR_SRV_SERVER 0
+#define CSR_SERVER_DLL_MAX 4
+#define LOCK RtlEnterCriticalSection(&ProcessDataLock)
+#define UNLOCK RtlLeaveCriticalSection(&ProcessDataLock)
+#define CsrAcquireProcessLock() LOCK
+#define CsrReleaseProcessLock() UNLOCK
+#define ProcessStructureListLocked() \
+ (ProcessDataLock.OwningThread == NtCurrentTeb()->ClientId.UniqueThread)
+
+#define CsrAcquireWaitLock() \
+ RtlEnterCriticalSection(&CsrWaitListsLock);
+
+#define CsrReleaseWaitLock() \
+ RtlLeaveCriticalSection(&CsrWaitListsLock);
+
+#define CsrAcquireNtSessionLock() \
+ RtlEnterCriticalSection(&CsrNtSessionLock);
+
+#define CsrReleaseNtSessionLock() \
+ RtlLeaveCriticalSection(&CsrNtSessionLock);
+
+typedef enum _CSR_THREAD_FLAGS
+{
+ CsrThreadAltertable = 0x1,
+ CsrThreadInTermination = 0x2,
+ CsrThreadTerminated = 0x4,
+ CsrThreadIsServerThread = 0x10
+} CSR_THREAD_FLAGS, *PCSR_THREAD_FLAGS;
+
+typedef enum _SHUTDOWN_RESULT
+{
+ CsrShutdownCsrProcess = 1,
+ CsrShutdownNonCsrProcess,
+ CsrShutdownCancelled
+} SHUTDOWN_RESULT, *PSHUTDOWN_RESULT;
+
+typedef enum _CSR_SHUTDOWN_FLAGS
+{
+ CsrShutdownSystem = 4,
+ CsrShutdownOther = 8
+} CSR_SHUTDOWN_FLAGS, *PCSR_SHUTDOWN_FLAGS;
+
+typedef enum _CSR_DEBUG_FLAGS
+{
+ CsrDebugOnlyThisProcess = 1,
+ CsrDebugProcessChildren = 2
+} CSR_PROCESS_DEBUG_FLAGS, *PCSR_PROCESS_DEBUG_FLAGS;
+
+typedef enum _CSR_PROCESS_FLAGS
+{
+ CsrProcessTerminating = 0x1,
+ CsrProcessSkipShutdown = 0x2,
+ CsrProcessNormalPriority = 0x10,
+ CsrProcessIdlePriority = 0x20,
+ CsrProcessHighPriority = 0x40,
+ CsrProcessRealtimePriority = 0x80,
+ CsrProcessCreateNewGroup = 0x100,
+ CsrProcessTerminated = 0x200,
+ CsrProcessLastThreadTerminated = 0x400,
+ CsrProcessIsConsoleApp = 0x800
+} CSR_PROCESS_FLAGS, *PCSR_PROCESS_FLAGS;
+
+#define CsrProcessPriorityFlags (CsrProcessNormalPriority | \
+ CsrProcessIdlePriority | \
+ CsrProcessHighPriority | \
+ CsrProcessRealtimePriority)
+
+typedef struct _CSRSS_CON_PROCESS_DATA
+{
+ HANDLE ConsoleEvent;
+ struct tagCSRSS_CONSOLE *Console;
+ struct tagCSRSS_CONSOLE *ParentConsole;
+ BOOL bInheritHandles;
+ RTL_CRITICAL_SECTION HandleTableLock;
+ ULONG HandleTableSize;
+ struct _CSRSS_HANDLE *HandleTable;
+ PCONTROLDISPATCHER CtrlDispatcher;
+ LIST_ENTRY ConsoleLink;
+} CSRSS_CON_PROCESS_DATA, *PCSRSS_CON_PROCESS_DATA;
+
+typedef struct _CSR_NT_SESSION
+{
+ ULONG ReferenceCount;
+ LIST_ENTRY SessionLink;
+ ULONG SessionId;
+} CSR_NT_SESSION, *PCSR_NT_SESSION;
+
+typedef struct _CSR_PROCESS
+{
+ CLIENT_ID ClientId;
+ LIST_ENTRY ListLink;
+ LIST_ENTRY ThreadList;
+ struct _CSR_PROCESS *Parent;
+ PCSR_NT_SESSION NtSession;
+ ULONG ExpectedVersion;
+ HANDLE ClientPort;
+ ULONG_PTR ClientViewBase;
+ ULONG_PTR ClientViewBounds;
+ HANDLE ProcessHandle;
+ ULONG SequenceNumber;
+ ULONG Flags;
+ ULONG DebugFlags;
+ CLIENT_ID DebugCid;
+ ULONG ReferenceCount;
+ ULONG ProcessGroupId;
+ ULONG ProcessGroupSequence;
+ ULONG fVDM;
+ ULONG ThreadCount;
+ ULONG PriorityClass;
+ ULONG Reserved;
+ ULONG ShutdownLevel;
+ ULONG ShutdownFlags;
+// PVOID ServerData[ANYSIZE_ARRAY];
+ CSRSS_CON_PROCESS_DATA;
+} CSR_PROCESS, *PCSR_PROCESS;
+
+typedef struct _CSR_THREAD
+{
+ LARGE_INTEGER CreateTime;
+ LIST_ENTRY Link;
+ LIST_ENTRY HashLinks;
+ CLIENT_ID ClientId;
+ PCSR_PROCESS Process;
+ struct _CSR_WAIT_BLOCK *WaitBlock;
+ HANDLE ThreadHandle;
+ ULONG Flags;
+ ULONG ReferenceCount;
+ ULONG ImpersonationCount;
+} CSR_THREAD, *PCSR_THREAD;
+
+typedef
+BOOLEAN
+(*CSR_WAIT_FUNCTION)(
+ IN PLIST_ENTRY WaitList,
+ IN PCSR_THREAD WaitThread,
+ IN PCSR_API_MESSAGE WaitApiMessage,
+ IN PVOID WaitContext,
+ IN PVOID WaitArgument1,
+ IN PVOID WaitArgument2,
+ IN ULONG WaitFlags
+);
+
+typedef struct _CSR_WAIT_BLOCK
+{
+ ULONG Size;
+ LIST_ENTRY WaitList;
+ LIST_ENTRY UserWaitList;
+ PVOID WaitContext;
+ PCSR_THREAD WaitThread;
+ CSR_WAIT_FUNCTION WaitFunction;
+ CSR_API_MESSAGE WaitApiMessage;
+} CSR_WAIT_BLOCK, *PCSR_WAIT_BLOCK;
+
+typedef
+NTSTATUS
+(NTAPI *PCSR_CONNECT_CALLBACK)(
+ IN PCSR_PROCESS CsrProcess,
+ IN OUT PVOID ConnectionInfo,
+ IN OUT PULONG ConnectionInfoLength
+);
+
+typedef
+VOID
+(NTAPI *PCSR_DISCONNECT_CALLBACK)(IN PCSR_PROCESS CsrProcess);
+
+typedef
+NTSTATUS
+(NTAPI *PCSR_NEWPROCESS_CALLBACK)(
+ IN PCSR_PROCESS Parent,
+ IN PCSR_PROCESS CsrProcess
+);
+
+typedef
+VOID
+(NTAPI *PCSR_HARDERROR_CALLBACK)(
+ IN PCSR_THREAD CsrThread,
+ IN PHARDERROR_MSG HardErrorMessage
+);
+
+typedef
+ULONG
+(NTAPI *PCSR_SHUTDOWNPROCESS_CALLBACK)(
+ IN PCSR_PROCESS CsrProcess,
+ IN ULONG Flags,
+ IN BOOLEAN FirstPhase
+);
+
+typedef
+NTSTATUS
+(NTAPI *PCSR_API_ROUTINE)(
+ IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply
+);
+
+typedef struct _CSR_SERVER_DLL
+{
+ ULONG Length;
+ HANDLE Event;
+ ANSI_STRING Name;
+ HANDLE ServerHandle;
+ ULONG ServerId;
+ ULONG Unknown;
+ ULONG ApiBase;
+ ULONG HighestApiSupported;
+ PCSR_API_ROUTINE *DispatchTable;
+ PBOOLEAN ValidTable;
+ PCHAR *NameTable;
+ ULONG SizeOfProcessData;
+ PCSR_CONNECT_CALLBACK ConnectCallback;
+ PCSR_DISCONNECT_CALLBACK DisconnectCallback;
+ PCSR_HARDERROR_CALLBACK HardErrorCallback;
+ PVOID SharedSection;
+ PCSR_NEWPROCESS_CALLBACK NewProcessCallback;
+ PCSR_SHUTDOWNPROCESS_CALLBACK ShutdownProcessCallback;
+ ULONG Unknown2[3];
+} CSR_SERVER_DLL, *PCSR_SERVER_DLL;
+
+typedef
+NTSTATUS
+(NTAPI *PCSR_SERVER_DLL_INIT_CALLBACK)(IN PCSR_SERVER_DLL ServerDll);
+
+
+typedef NTSTATUS (WINAPI *CSRSS_API_PROC)(PCSR_PROCESS ProcessData,
+ PCSR_API_MESSAGE Request);
+
+typedef struct _CSRSS_API_DEFINITION
+{
+ ULONG Type;
+ ULONG MinRequestSize;
+ CSRSS_API_PROC Handler;
+} CSRSS_API_DEFINITION, *PCSRSS_API_DEFINITION;
+
+#define CSRSS_DEFINE_API(Func, Handler) \
+ { Func, sizeof(CSRSS_##Func), Handler }
+
+typedef struct _CSRSS_LISTEN_DATA
+{
+ HANDLE ApiPortHandle;
+ ULONG ApiDefinitionsCount;
+ PCSRSS_API_DEFINITION *ApiDefinitions;
+} CSRSS_LISTEN_DATA, *PCSRSS_LISTEN_DATA;
+
+#define CSR_API(n) NTSTATUS WINAPI n ( \
+ PCSR_PROCESS ProcessData, \
+ PCSR_API_MESSAGE Request)
+
+/* init.c */
+extern HANDLE hBootstrapOk;
+NTSTATUS NTAPI CsrServerInitialization(ULONG ArgumentCount, PCHAR Arguments[]);
+
+/* api/process.c */
+CSR_API(CsrConnectProcess);
+CSR_API(CsrSrvCreateProcess);
+CSR_API(CsrTerminateProcess);
+CSR_API(CsrSrvCreateThread);
+CSR_API(CsrGetShutdownParameters);
+CSR_API(CsrSetShutdownParameters);
+
+VOID
+NTAPI
+CsrSetBackgroundPriority(IN PCSR_PROCESS CsrProcess);
+
+PCSR_THREAD
+NTAPI
+CsrAllocateThread(IN PCSR_PROCESS CsrProcess);
+
+PCSR_PROCESS
+NTAPI
+CsrAllocateProcess(VOID);
+
+VOID
+NTAPI
+CsrDeallocateProcess(IN PCSR_PROCESS CsrProcess);
+
+VOID
+NTAPI
+CsrRemoveProcess(IN PCSR_PROCESS CsrProcess);
+
+VOID
+NTAPI
+CsrDereferenceThread(IN PCSR_THREAD CsrThread);
+
+VOID
+NTAPI
+CsrInsertProcess(IN PCSR_PROCESS Parent OPTIONAL,
+ IN PCSR_PROCESS CurrentProcess OPTIONAL,
+ IN PCSR_PROCESS CsrProcess);
+
+
+/* api/wapi.c */
+NTSTATUS FASTCALL CsrApiRegisterDefinitions(PCSRSS_API_DEFINITION NewDefinitions);
+VOID FASTCALL CsrApiCallHandler(PCSR_PROCESS ProcessData,
+ PCSR_API_MESSAGE Request);
+VOID WINAPI CsrSbApiRequestThread (PVOID PortHandle);
+VOID NTAPI ClientConnectionThread(HANDLE ServerPort);
+
+VOID
+NTAPI
+CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage);
+
+extern HANDLE CsrApiPort;
+extern HANDLE CsrSmApiPort;
+extern HANDLE CsrSbApiPort;
+extern LIST_ENTRY CsrThreadHashTable[256];
+extern PCSR_PROCESS CsrRootProcess;
+extern RTL_CRITICAL_SECTION ProcessDataLock, CsrWaitListsLock;
+extern UNICODE_STRING CsrDirectoryName;
+extern ULONG CsrDebug;
+extern ULONG CsrTotalPerProcessDataLength;
+extern SYSTEM_BASIC_INFORMATION CsrNtSysInfo;
+extern PVOID CsrSrvSharedSectionHeap;
+extern PVOID *CsrSrvSharedStaticServerData;
+extern HANDLE CsrInitializationEvent;
+extern PCSR_SERVER_DLL CsrLoadedServerDll[CSR_SERVER_DLL_MAX];
+extern ULONG CsrMaxApiRequestThreads;
+
+NTSTATUS
+NTAPI
+CsrApiPortInitialize(VOID);
+
+NTSTATUS
+NTAPI
+CsrCreateProcess(IN HANDLE hProcess,
+ IN HANDLE hThread,
+ IN PCLIENT_ID ClientId,
+ IN PCSR_NT_SESSION NtSession,
+ IN ULONG Flags,
+ IN PCLIENT_ID DebugCid);
+
+BOOLEAN
+NTAPI
+ProtectHandle(IN HANDLE ObjectHandle);
+
+VOID
+NTAPI
+CsrInsertThread(IN PCSR_PROCESS Process,
+IN PCSR_THREAD Thread);
+
+VOID
+NTAPI
+CsrLockedReferenceThread(IN PCSR_THREAD CsrThread);
+
+/* api/process.c */
+typedef NTSTATUS (WINAPI *CSRSS_ENUM_PROCESS_PROC)(PCSR_PROCESS ProcessData,
+ PVOID Context);
+NTSTATUS WINAPI CsrInitializeProcessStructure(VOID);
+
+NTSTATUS WINAPI CsrEnumProcesses(CSRSS_ENUM_PROCESS_PROC EnumProc, PVOID Context);
+PCSR_THREAD NTAPI CsrAddStaticServerThread(IN HANDLE hThread, IN PCLIENT_ID ClientId, IN ULONG ThreadFlags);
+PCSR_THREAD NTAPI CsrLocateThreadInProcess(IN PCSR_PROCESS CsrProcess OPTIONAL, IN PCLIENT_ID Cid);
+PCSR_THREAD NTAPI CsrLocateThreadByClientId(OUT PCSR_PROCESS *Process OPTIONAL, IN PCLIENT_ID ClientId);
+NTSTATUS NTAPI CsrLockProcessByClientId(IN HANDLE Pid, OUT PCSR_PROCESS *CsrProcess OPTIONAL);
+NTSTATUS NTAPI CsrCreateThread(IN PCSR_PROCESS CsrProcess, IN HANDLE hThread, IN PCLIENT_ID ClientId);
+NTSTATUS NTAPI CsrUnlockProcess(IN PCSR_PROCESS CsrProcess);
+
+//hack
+VOID NTAPI CsrThreadRefcountZero(IN PCSR_THREAD CsrThread);
+
+NTSTATUS
+NTAPI
+CsrInitializeNtSessionList(VOID);
+
+NTSTATUS
+NTAPI
+CsrSrvAttachSharedSection(IN PCSR_PROCESS CsrProcess OPTIONAL,
+OUT PCSR_CONNECTION_INFO ConnectInfo);
+
+NTSTATUS
+NTAPI
+CsrSrvCreateSharedSection(IN PCHAR ParameterValue);
+
+NTSTATUS
+NTAPI
+CsrSrvClientConnect(
+ IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply
+);
+
+NTSTATUS
+NTAPI
+CsrSrvUnusedFunction(
+ IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply
+);
+
+NTSTATUS
+NTAPI
+CsrSrvIdentifyAlertableThread(
+ IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply
+);
+
+NTSTATUS
+NTAPI
+CsrSrvSetPriorityClass(
+ IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply
+);
+
+NTSTATUS
+NTAPI
+CsrDestroyProcess(IN PCLIENT_ID Cid,
+IN NTSTATUS ExitStatus);
+
+NTSTATUS
+NTAPI
+CsrDestroyThread(IN PCLIENT_ID Cid);
+
+VOID
+NTAPI
+CsrLockedDereferenceThread(IN PCSR_THREAD CsrThread);
+
+BOOLEAN
+NTAPI
+CsrNotifyWaitBlock(IN PCSR_WAIT_BLOCK WaitBlock,
+ IN PLIST_ENTRY WaitList,
+ IN PVOID WaitArgument1,
+ IN PVOID WaitArgument2,
+ IN ULONG WaitFlags,
+ IN BOOLEAN DereferenceThread);
+
+VOID
+NTAPI
+CsrReferenceNtSession(IN PCSR_NT_SESSION Session);
+
+LONG
+NTAPI
+CsrUnhandledExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo);
+
+VOID
+NTAPI
+CsrDereferenceNtSession(IN PCSR_NT_SESSION Session,
+IN NTSTATUS ExitStatus);
+
+VOID
+NTAPI
+CsrLockedDereferenceProcess(PCSR_PROCESS CsrProcess);
+
+VOID
+NTAPI
+CsrDereferenceProcess(IN PCSR_PROCESS CsrProcess);
+
+NTSTATUS
+NTAPI
+CsrLoadServerDll(IN PCHAR DllString,
+ IN PCHAR EntryPoint OPTIONAL,
+ IN ULONG ServerId);
+
+/* api/user.c */
+CSR_API(CsrRegisterServicesProcess);
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: subsys/csrss/include/csrplugin.h
+ * PURPOSE: CSRSS plugin interface
+ */
+
+/*
+ * CSRSS is a native application and can only implicitly link against native
+ * DLLs. Since e.g. user32.dll and gdi32.dll are win32 DLLs and not native
+ * DLLs it is not possible to call functions in those DLLs directly from
+ * CSRSS.
+ * However, it is possible to explicitly load a non-native DLL. Such a DLL
+ * can then in turn be implicitly linked against other DLLs in its own
+ * subsystem.
+ */
+
+#pragma once
+
+#include "api.h"
+
+typedef NTSTATUS (WINAPI *CSRSS_ENUM_PROCESSES_PROC)(CSRSS_ENUM_PROCESS_PROC EnumProc,
+ PVOID Context);
+
+typedef struct tagCSRSS_EXPORTED_FUNCS
+{
+ CSRSS_ENUM_PROCESSES_PROC CsrEnumProcessesProc;
+} CSRSS_EXPORTED_FUNCS, *PCSRSS_EXPORTED_FUNCS;
+
+typedef BOOL (WINAPI *CSRPLUGIN_INIT_COMPLETE_PROC)(void);
+
+typedef VOID (WINAPI *CSRPLUGIN_HARDERROR_PROC)(IN PCSR_THREAD ThreadData,
+ IN PHARDERROR_MSG HardErrorMessage);
+
+typedef NTSTATUS (WINAPI *CSRPLUGIN_PROCESS_INHERIT_PROC)(IN PCSR_PROCESS SourceProcessData,
+ IN PCSR_PROCESS TargetProcessData);
+
+typedef ULONG (WINAPI *CSRPLUGIN_PROCESS_DELETED_PROC)(IN PCSR_PROCESS ProcessData, IN ULONG Unused, IN BOOLEAN Flag);
+
+typedef struct tagCSRSS_SERVER_PROCS
+{
+ CSRPLUGIN_INIT_COMPLETE_PROC InitCompleteProc;
+ CSRPLUGIN_HARDERROR_PROC HardErrorProc;
+ CSRPLUGIN_PROCESS_INHERIT_PROC ProcessInheritProc;
+ CSRPLUGIN_PROCESS_DELETED_PROC ProcessDeletedProc;
+} CSRPLUGIN_SERVER_PROCS, *PCSRPLUGIN_SERVER_PROCS;
+
+typedef BOOL (WINAPI *CSRPLUGIN_INITIALIZE_PROC)(PCSRSS_API_DEFINITION *ApiDefinitions,
+ PCSRPLUGIN_SERVER_PROCS ServerProcs);
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CSR Sub System
+ * FILE: subsystems/win32/csrss/csrsrv/init.c
+ * PURPOSE: CSR Server DLL Initialization
+ * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
+ * ReactOS Portable Systems Group
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include "srv.h"
+#define NDEBUG
+#include <debug.h>
+
+/* DATA ***********************************************************************/
+
+HANDLE CsrHeap = (HANDLE) 0;
+HANDLE CsrObjectDirectory = (HANDLE) 0;
+UNICODE_STRING CsrDirectoryName;
+UNICODE_STRING CsrSbApiPortName;
+HANDLE CsrSbApiPort = 0;
+PCSR_THREAD CsrSbApiRequestThreadPtr;
+HANDLE CsrSmApiPort;
+HANDLE hSbApiPort = (HANDLE) 0;
+HANDLE CsrApiPort = (HANDLE) 0;
+ULONG CsrDebug = 0;//0xFFFFFFFF;
+ULONG CsrMaxApiRequestThreads;
+ULONG CsrTotalPerProcessDataLength;
+ULONG SessionId;
+HANDLE BNOLinksDirectory;
+HANDLE SessionObjectDirectory;
+HANDLE DosDevicesDirectory;
+HANDLE CsrInitializationEvent;
+SYSTEM_BASIC_INFORMATION CsrNtSysInfo;
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+VOID
+CallHardError(IN PCSR_THREAD ThreadData,
+ IN PHARDERROR_MSG HardErrorMessage)
+{
+ unsigned i;
+ PCSR_SERVER_DLL ServerDll;
+
+ DPRINT("CSR: %s called\n", __FUNCTION__);
+
+ /* Notify the Server DLLs */
+ for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+ {
+ /* Get the current Server DLL */
+ ServerDll = CsrLoadedServerDll[i];
+
+ /* Make sure it's valid and that it has callback */
+ if ((ServerDll) && (ServerDll->HardErrorCallback))
+ {
+ ServerDll->HardErrorCallback(ThreadData, HardErrorMessage);
+ }
+ }
+}
+
+NTSTATUS
+CallProcessCreated(IN PCSR_PROCESS SourceProcessData,
+ IN PCSR_PROCESS TargetProcessData)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ unsigned i;
+ PCSR_SERVER_DLL ServerDll;
+
+ DPRINT("CSR: %s called\n", __FUNCTION__);
+
+ /* Notify the Server DLLs */
+ for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+ {
+ /* Get the current Server DLL */
+ ServerDll = CsrLoadedServerDll[i];
+
+ /* Make sure it's valid and that it has callback */
+ if ((ServerDll) && (ServerDll->NewProcessCallback))
+ {
+ Status = ServerDll->NewProcessCallback(SourceProcessData, TargetProcessData);
+ }
+ }
+
+ return Status;
+}
+
+CSRSS_API_DEFINITION NativeDefinitions[] =
+ {
+ CSRSS_DEFINE_API(CREATE_PROCESS, CsrSrvCreateProcess),
+ CSRSS_DEFINE_API(CREATE_THREAD, CsrSrvCreateThread),
+ CSRSS_DEFINE_API(TERMINATE_PROCESS, CsrTerminateProcess),
+ CSRSS_DEFINE_API(CONNECT_PROCESS, CsrConnectProcess),
+ CSRSS_DEFINE_API(REGISTER_SERVICES_PROCESS, CsrRegisterServicesProcess),
+ CSRSS_DEFINE_API(GET_SHUTDOWN_PARAMETERS, CsrGetShutdownParameters),
+ CSRSS_DEFINE_API(SET_SHUTDOWN_PARAMETERS, CsrSetShutdownParameters),
+ { 0, 0, NULL }
+ };
+
+/* === INIT ROUTINES === */
+
+VOID
+WINAPI
+BasepFakeStaticServerData(VOID);
+
+/*++
+ * @name CsrSetProcessSecurity
+ *
+ * The CsrSetProcessSecurity routine protects access to the CSRSS process
+ * from unauthorized tampering.
+ *
+ * @param None.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSetProcessSecurity(VOID)
+{
+ NTSTATUS Status;
+ HANDLE hToken, hProcess = NtCurrentProcess();
+ ULONG Length;
+ PTOKEN_USER TokenInfo = NULL;
+ PSECURITY_DESCRIPTOR ProcSd = NULL;
+ PACL Dacl;
+ PSID UserSid;
+
+ /* Open our token */
+ Status = NtOpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
+ if (!NT_SUCCESS(Status)) goto Quickie;
+
+ /* Get the Token User Length */
+ NtQueryInformationToken(hToken, TokenUser, NULL, 0, &Length);
+
+ /* Allocate space for it */
+ TokenInfo = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, Length);
+ if (!TokenInfo)
+ {
+ Status = STATUS_NO_MEMORY;
+ goto Quickie;
+ }
+
+ /* Now query the data */
+ Status = NtQueryInformationToken(hToken, TokenUser, TokenInfo, Length, &Length);
+ NtClose(hToken);
+ if (!NT_SUCCESS(Status)) goto Quickie;
+
+ /* Now check the SID Length */
+ UserSid = TokenInfo->User.Sid;
+ Length = RtlLengthSid(UserSid) + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
+
+ /* Allocate a buffer for the Security Descriptor, with SID and DACL */
+ ProcSd = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, SECURITY_DESCRIPTOR_MIN_LENGTH + Length);
+ if (!ProcSd)
+ {
+ Status = STATUS_NO_MEMORY;
+ goto Quickie;
+ }
+
+ /* Set the pointer to the DACL */
+ Dacl = (PACL)((ULONG_PTR)ProcSd + SECURITY_DESCRIPTOR_MIN_LENGTH);
+
+ /* Now create the SD itself */
+ Status = RtlCreateSecurityDescriptor(ProcSd, SECURITY_DESCRIPTOR_REVISION);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: SD creation failed - status = %lx\n", Status);
+ goto Quickie;
+ }
+
+ /* Create the DACL for it*/
+ Status = RtlCreateAcl(Dacl, Length, ACL_REVISION2);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: DACL creation failed - status = %lx\n", Status);
+ goto Quickie;
+ }
+
+ /* Create the ACE */
+ Status = RtlAddAccessAllowedAce(Dacl,
+ ACL_REVISION,
+ PROCESS_VM_READ | PROCESS_VM_WRITE |
+ PROCESS_VM_OPERATION | PROCESS_DUP_HANDLE |
+ PROCESS_TERMINATE | PROCESS_SUSPEND_RESUME |
+ PROCESS_QUERY_INFORMATION | READ_CONTROL,
+ UserSid);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: ACE creation failed - status = %lx\n", Status);
+ goto Quickie;
+ }
+
+ /* Clear the DACL in the SD */
+ Status = RtlSetDaclSecurityDescriptor(ProcSd, TRUE, Dacl, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: set DACL failed - status = %lx\n", Status);
+ goto Quickie;
+ }
+
+ /* Write the SD into the Process */
+ Status = NtSetSecurityObject(hProcess, DACL_SECURITY_INFORMATION, ProcSd);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: set process DACL failed - status = %lx\n", Status);
+ goto Quickie;
+ }
+
+ /* Free the memory and return */
+Quickie:
+ if (ProcSd) RtlFreeHeap(CsrHeap, 0, ProcSd);
+ RtlFreeHeap(CsrHeap, 0, TokenInfo);
+ return Status;
+}
+
+/*++
+ * @name CsrSetDirectorySecurity
+ *
+ * The CsrSetDirectorySecurity routine sets the security descriptor for the
+ * specified Object Directory.
+ *
+ * @param ObjectDirectory
+ * Handle fo the Object Directory to protect.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSetDirectorySecurity(IN HANDLE ObjectDirectory)
+{
+ /* FIXME: Implement */
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name GetDosDevicesProtection
+ *
+ * The GetDosDevicesProtection creates a security descriptor for the DOS Devices
+ * Object Directory.
+ *
+ * @param DosDevicesSd
+ * Pointer to the Security Descriptor to return.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks Depending on the DOS Devices Protection Mode (set in the registry),
+ * regular users may or may not have full access to the directory.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+GetDosDevicesProtection(OUT PSECURITY_DESCRIPTOR DosDevicesSd)
+{
+ SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
+ SID_IDENTIFIER_AUTHORITY CreatorAuthority = {SECURITY_CREATOR_SID_AUTHORITY};
+ SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
+ PSID WorldSid, CreatorSid, AdminSid, SystemSid;
+ UCHAR KeyValueBuffer[0x40];
+ PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
+ UNICODE_STRING KeyName;
+ ULONG ProtectionMode = 0;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PACL Dacl;
+ PACCESS_ALLOWED_ACE Ace;
+ HANDLE hKey;
+ NTSTATUS Status;
+ ULONG ResultLength, SidLength, AclLength;
+
+ /* Create the SD */
+ Status = RtlCreateSecurityDescriptor(DosDevicesSd, SECURITY_DESCRIPTOR_REVISION);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Initialize the System SID */
+ Status = RtlAllocateAndInitializeSid(&NtSidAuthority, 1,
+ SECURITY_LOCAL_SYSTEM_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &SystemSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Initialize the World SID */
+ Status = RtlAllocateAndInitializeSid(&WorldAuthority, 1,
+ SECURITY_WORLD_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &WorldSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Initialize the Admin SID */
+ Status = RtlAllocateAndInitializeSid(&NtSidAuthority, 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &AdminSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Initialize the Creator SID */
+ Status = RtlAllocateAndInitializeSid(&CreatorAuthority, 1,
+ SECURITY_CREATOR_OWNER_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &CreatorSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Open the Session Manager Key */
+ RtlInitUnicodeString(&KeyName, SM_REG_KEY);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
+ if (NT_SUCCESS(Status))
+ {
+ /* Read the key value */
+ RtlInitUnicodeString(&KeyName, L"ProtectionMode");
+ Status = NtQueryValueKey(hKey,
+ &KeyName,
+ KeyValuePartialInformation,
+ KeyValueBuffer,
+ sizeof(KeyValueBuffer),
+ &ResultLength);
+
+ /* Make sure it's what we expect it to be */
+ KeyValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
+ if ((NT_SUCCESS(Status)) && (KeyValuePartialInfo->Type == REG_DWORD) &&
+ (*(PULONG)KeyValuePartialInfo->Data))
+ {
+ /* Save the Protection Mode */
+ ProtectionMode = *(PULONG)KeyValuePartialInfo->Data;
+ }
+
+ /* Close the handle */
+ NtClose(hKey);
+ }
+
+ /* Check the Protection Mode */
+ if (ProtectionMode & 3)
+ {
+ /* Calculate SID Lengths */
+ SidLength = RtlLengthSid(CreatorSid) + RtlLengthSid(SystemSid) +
+ RtlLengthSid(AdminSid);
+ AclLength = sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) + SidLength;
+
+ /* Allocate memory for the DACL */
+ Dacl = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, AclLength);
+ ASSERT(Dacl != NULL);
+
+ /* Build the ACL and add 3 ACEs */
+ Status = RtlCreateAcl(Dacl, AclLength, ACL_REVISION2);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, SystemSid);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, AdminSid);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, CreatorSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Edit the ACEs to make them inheritable */
+ Status = RtlGetAce(Dacl, 0, (PVOID*)&Ace);
+ ASSERT(NT_SUCCESS(Status));
+ Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
+ Status = RtlGetAce(Dacl, 1, (PVOID*)&Ace);
+ ASSERT(NT_SUCCESS(Status));
+ Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
+ Status = RtlGetAce(Dacl, 2, (PVOID*)&Ace);
+ ASSERT(NT_SUCCESS(Status));
+ Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
+
+ /* Set this DACL with the SD */
+ Status = RtlSetDaclSecurityDescriptor(DosDevicesSd, TRUE, Dacl, FALSE);
+ ASSERT(NT_SUCCESS(Status));
+ goto Quickie;
+ }
+ else
+ {
+ /* Calculate SID Lengths */
+ SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(SystemSid);
+ AclLength = sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) + SidLength;
+
+ /* Allocate memory for the DACL */
+ Dacl = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, AclLength);
+ ASSERT(Dacl != NULL);
+
+ /* Build the ACL and add 3 ACEs */
+ Status = RtlCreateAcl(Dacl, AclLength, ACL_REVISION2);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE, WorldSid);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, SystemSid);
+ ASSERT(NT_SUCCESS(Status));
+ Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, WorldSid);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Edit the last ACE to make it inheritable */
+ Status = RtlGetAce(Dacl, 2, (PVOID*)&Ace);
+ ASSERT(NT_SUCCESS(Status));
+ Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
+
+ /* Set this DACL with the SD */
+ Status = RtlSetDaclSecurityDescriptor(DosDevicesSd, TRUE, Dacl, FALSE);
+ ASSERT(NT_SUCCESS(Status));
+ goto Quickie;
+ }
+
+/* FIXME: failure cases! Fail: */
+ /* Free the memory */
+ RtlFreeHeap(CsrHeap, 0, Dacl);
+
+/* FIXME: semi-failure cases! Quickie: */
+Quickie:
+ /* Free the SIDs */
+ RtlFreeSid(SystemSid);
+ RtlFreeSid(WorldSid);
+ RtlFreeSid(AdminSid);
+ RtlFreeSid(CreatorSid);
+
+ /* Return */
+ return Status;
+}
+
+/*++
+ * @name FreeDosDevicesProtection
+ *
+ * The FreeDosDevicesProtection frees the security descriptor that was created
+ * by GetDosDevicesProtection
+ *
+ * @param DosDevicesSd
+ * Pointer to the security descriptor to free.
+
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+FreeDosDevicesProtection(IN PSECURITY_DESCRIPTOR DosDevicesSd)
+{
+ PACL Dacl;
+ BOOLEAN Present, Default;
+ NTSTATUS Status;
+
+ /* Get the DACL corresponding to this SD */
+ Status = RtlGetDaclSecurityDescriptor(DosDevicesSd, &Present, &Dacl, &Default);
+ ASSERT(NT_SUCCESS(Status));
+ ASSERT(Present);
+ ASSERT(Dacl != NULL);
+
+ /* Free it */
+ if ((NT_SUCCESS(Status)) && (Dacl)) RtlFreeHeap(CsrHeap, 0, Dacl);
+}
+
+/*++
+ * @name CsrCreateSessionObjectDirectory
+ *
+ * The CsrCreateSessionObjectDirectory routine creates the BaseNamedObjects,
+ * Session and Dos Devices directories for the specified session.
+ *
+ * @param Session
+ * Session ID for which to create the directories.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrCreateSessionObjectDirectory(IN ULONG Session)
+{
+ WCHAR SessionBuffer[512], BnoBuffer[512];
+ UNICODE_STRING SessionString, BnoString;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE BnoHandle;
+ SECURITY_DESCRIPTOR DosDevicesSd;
+ NTSTATUS Status;
+
+ /* Generate the Session BNOLINKS Directory name */
+ swprintf(SessionBuffer, L"%ws\\BNOLINKS", SESSION_ROOT);
+ RtlInitUnicodeString(&SessionString, SessionBuffer);
+
+ /* Create it */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &SessionString,
+ OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtCreateDirectoryObject(&BNOLinksDirectory,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: NtCreateDirectoryObject failed in "
+ "CsrCreateSessionObjectDirectory - status = %lx\n", Status);
+ return Status;
+ }
+
+ /* Now add the Session ID */
+ swprintf(SessionBuffer, L"%ld", Session);
+ RtlInitUnicodeString(&SessionString, SessionBuffer);
+
+ /* Check if this is the first Session */
+ if (Session)
+ {
+ /* Not the first, so the name will be slighly more complex */
+ swprintf(BnoBuffer, L"%ws\\%ld\\BaseNamedObjects", SESSION_ROOT, Session);
+ RtlInitUnicodeString(&BnoString, BnoBuffer);
+ }
+ else
+ {
+ /* Use the direct name */
+ RtlInitUnicodeString(&BnoString, L"\\BaseNamedObjects");
+ }
+
+ /* Create the symlink */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &SessionString,
+ OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
+ BNOLinksDirectory,
+ NULL);
+ Status = NtCreateSymbolicLinkObject(&BnoHandle,
+ SYMBOLIC_LINK_ALL_ACCESS,
+ &ObjectAttributes,
+ &BnoString);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: NtCreateSymbolicLinkObject failed in "
+ "CsrCreateSessionObjectDirectory - status = %lx\n", Status);
+ return Status;
+ }
+
+ /* Create the \DosDevices Security Descriptor */
+ Status = GetDosDevicesProtection(&DosDevicesSd);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Now create a directory for this session */
+ swprintf(SessionBuffer, L"%ws\\%ld", SESSION_ROOT, Session);
+ RtlInitUnicodeString(&SessionString, SessionBuffer);
+
+ /* Create the directory */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &SessionString,
+ OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
+ 0,
+ &DosDevicesSd);
+ Status = NtCreateDirectoryObject(&SessionObjectDirectory,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: NtCreateDirectoryObject failed in "
+ "CsrCreateSessionObjectDirectory - status = %lx\n", Status);
+ FreeDosDevicesProtection(&DosDevicesSd);
+ return Status;
+ }
+
+ /* Next, create a directory for this session's DOS Devices */
+ RtlInitUnicodeString(&SessionString, L"DosDevices");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &SessionString,
+ OBJ_CASE_INSENSITIVE,
+ SessionObjectDirectory,
+ &DosDevicesSd);
+ Status = NtCreateDirectoryObject(&DosDevicesDirectory,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: NtCreateDirectoryObject failed in "
+ "CsrCreateSessionObjectDirectory - status = %lx\n", Status);
+ }
+
+ /* Release the Security Descriptor */
+ FreeDosDevicesProtection(&DosDevicesSd);
+
+ /* Return */
+ return Status;
+}
+
+/*++
+ * @name CsrParseServerCommandLine
+ *
+ * The CsrParseServerCommandLine routine parses the CSRSS command-line in the
+ * registry and performs operations for each entry found.
+ *
+ * @param ArgumentCount
+ * Number of arguments on the command line.
+ *
+ * @param Arguments
+ * Array of arguments.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+FASTCALL
+CsrParseServerCommandLine(IN ULONG ArgumentCount,
+ IN PCHAR Arguments[])
+{
+ NTSTATUS Status;
+ PCHAR ParameterName = NULL, ParameterValue = NULL, EntryPoint, ServerString;
+ ULONG i, DllIndex;
+ ANSI_STRING AnsiString;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+
+ /* Set the Defaults */
+ CsrTotalPerProcessDataLength = 0;
+ CsrObjectDirectory = NULL;
+ CsrMaxApiRequestThreads = 16;
+
+ /* Save our Session ID, and create a Directory for it */
+ SessionId = NtCurrentPeb()->SessionId;
+ Status = CsrCreateSessionObjectDirectory(SessionId);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: CsrCreateSessionObjectDirectory failed (%lx)\n",
+ Status);
+
+ /* It's not fatal if the session ID isn't zero */
+ if (SessionId) return Status;
+ ASSERT(NT_SUCCESS(Status));
+ }
+
+ /* Loop through every argument */
+ for (i = 1; i < ArgumentCount; i++)
+ {
+ /* Split Name and Value */
+ ParameterName = Arguments[i];
+ ParameterValue = NULL;
+ ParameterValue = strchr(ParameterName, '=');
+ if (ParameterValue) *ParameterValue++ = ANSI_NULL;
+
+ /* Check for Object Directory */
+ if (!_stricmp(ParameterName, "ObjectDirectory"))
+ {
+ /* Check if a session ID is specified */
+ if (SessionId)
+ {
+ DPRINT1("Sessions not yet implemented\n");
+ ASSERT(SessionId);
+ }
+
+ /* Initialize the directory name */
+ RtlInitAnsiString(&AnsiString, ParameterValue);
+ Status = RtlAnsiStringToUnicodeString(&CsrDirectoryName,
+ &AnsiString,
+ TRUE);
+ ASSERT(NT_SUCCESS(Status) || SessionId != 0);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Create it */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &CsrDirectoryName,
+ OBJ_OPENIF | OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
+ NULL,
+ NULL);
+ Status = NtCreateDirectoryObject(&CsrObjectDirectory,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Secure it */
+ Status = CsrSetDirectorySecurity(CsrObjectDirectory);
+ if (!NT_SUCCESS(Status)) return Status;
+ }
+ else if (!_stricmp(ParameterName, "SubSystemType"))
+ {
+ /* Ignored */
+ }
+ else if (!_stricmp(ParameterName, "MaxRequestThreads"))
+ {
+ Status = RtlCharToInteger(ParameterValue,
+ 0,
+ &CsrMaxApiRequestThreads);
+ }
+ else if (!_stricmp(ParameterName, "RequestThreads"))
+ {
+ /* Ignored */
+ Status = STATUS_SUCCESS;
+ }
+ else if (!_stricmp(ParameterName, "ProfileControl"))
+ {
+ /* Ignored */
+ }
+ else if (!_stricmp(ParameterName, "SharedSection"))
+ {
+ /* Create the Section */
+ Status = CsrSrvCreateSharedSection(ParameterValue);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: *** Invalid syntax for %s=%s (Status == %X)\n",
+ ParameterName, ParameterValue, Status);
+ return Status;
+ }
+
+ /* Load us */
+ Status = CsrLoadServerDll("CSRSS", NULL, CSR_SRV_SERVER);
+ }
+ else if (!_stricmp(ParameterName, "ServerDLL"))
+ {
+ /* Loop the command line */
+ EntryPoint = NULL;
+ Status = STATUS_INVALID_PARAMETER;
+ ServerString = ParameterValue;
+ while (*ServerString)
+ {
+ /* Check for the Entry Point */
+ if ((*ServerString == ':') && (!EntryPoint))
+ {
+ /* Found it. Add a nullchar and save it */
+ *ServerString++ = ANSI_NULL;
+ EntryPoint = ServerString;
+ }
+
+ /* Check for the Dll Index */
+ if (*ServerString++ == ',') break;
+ }
+
+ /* Did we find something to load? */
+ if (!*ServerString)
+ {
+ DPRINT1("CSRSS: *** Invalid syntax for ServerDll=%s (Status == %X)\n",
+ ParameterValue, Status);
+ return Status;
+ }
+
+ /* Convert it to a ULONG */
+ Status = RtlCharToInteger(ServerString, 10, &DllIndex);
+
+ /* Add a null char if it was valid */
+ if (NT_SUCCESS(Status)) ServerString[-1] = ANSI_NULL;
+
+ /* Load it */
+ if (CsrDebug & 1) DPRINT1("CSRSS: Loading ServerDll=%s:%s\n", ParameterValue, EntryPoint);
+
+ /* Hackito ergo sum */
+ Status = STATUS_SUCCESS;
+ if (strstr(ParameterValue, "basesrv"))
+ {
+ DPRINT1("Fake basesrv init\n");
+ BasepFakeStaticServerData();
+ }
+// else
+// {
+// Status = CsrLoadServerDll(ParameterValue, EntryPoint, 2);
+// }
+ // Status = CsrLoadServerDll(ParameterValue, EntryPoint, DllIndex);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: *** Failed loading ServerDll=%s (Status == 0x%x)\n",
+ ParameterValue, Status);
+ return Status;
+ }
+ }
+ else if (!_stricmp(ParameterName, "Windows"))
+ {
+ /* Ignored */
+ }
+ else
+ {
+ /* Invalid parameter on the command line */
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ /* Return status */
+ return Status;
+}
+
+/*++
+ * @name CsrCreateLocalSystemSD
+ *
+ * The CsrCreateLocalSystemSD routine creates a Security Descriptor for
+ * the local account with PORT_ALL_ACCESS.
+ *
+ * @param LocalSystemSd
+ * Pointer to a pointer to the security descriptor to create.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrCreateLocalSystemSD(OUT PSECURITY_DESCRIPTOR *LocalSystemSd)
+{
+ SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
+ PSID SystemSid;
+ ULONG Length;
+ PSECURITY_DESCRIPTOR SystemSd;
+ PACL Dacl;
+ NTSTATUS Status;
+
+ /* Initialize the System SID */
+ RtlAllocateAndInitializeSid(&NtSidAuthority, 1,
+ SECURITY_LOCAL_SYSTEM_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &SystemSid);
+
+ /* Get the length of the SID */
+ Length = RtlLengthSid(SystemSid) + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
+
+ /* Allocate a buffer for the Security Descriptor, with SID and DACL */
+ SystemSd = RtlAllocateHeap(CsrHeap, 0, SECURITY_DESCRIPTOR_MIN_LENGTH + Length);
+
+ /* Set the pointer to the DACL */
+ Dacl = (PACL)((ULONG_PTR)SystemSd + SECURITY_DESCRIPTOR_MIN_LENGTH);
+
+ /* Now create the SD itself */
+ Status = RtlCreateSecurityDescriptor(SystemSd, SECURITY_DESCRIPTOR_REVISION);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ RtlFreeHeap(CsrHeap, 0, SystemSd);
+ return Status;
+ }
+
+ /* Create the DACL for it */
+ RtlCreateAcl(Dacl, Length, ACL_REVISION2);
+
+ /* Create the ACE */
+ Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, PORT_ALL_ACCESS, SystemSid);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ RtlFreeHeap(CsrHeap, 0, SystemSd);
+ return Status;
+ }
+
+ /* Clear the DACL in the SD */
+ Status = RtlSetDaclSecurityDescriptor(SystemSd, TRUE, Dacl, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ RtlFreeHeap(CsrHeap, 0, SystemSd);
+ return Status;
+ }
+
+ /* Free the SID and return*/
+ RtlFreeSid(SystemSid);
+ *LocalSystemSd = SystemSd;
+ return Status;
+}
+
+/*++
+ * @name CsrSbApiPortInitialize
+ *
+ * The CsrSbApiPortInitialize routine initializes the LPC Port used for
+ * communications with the Session Manager (SM) and initializes the static
+ * thread that will handle connection requests and APIs.
+ *
+ * @param None
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSbApiPortInitialize(VOID)
+{
+ ULONG Size;
+ PSECURITY_DESCRIPTOR PortSd;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ NTSTATUS Status;
+ HANDLE hRequestThread;
+ CLIENT_ID ClientId;
+
+ /* Calculate how much space we'll need for the Port Name */
+ Size = CsrDirectoryName.Length + sizeof(SB_PORT_NAME) + sizeof(WCHAR);
+
+ /* Create the buffer for it */
+ CsrSbApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
+ if (!CsrSbApiPortName.Buffer) return STATUS_NO_MEMORY;
+
+ /* Setup the rest of the empty string */
+ CsrSbApiPortName.Length = 0;
+ CsrSbApiPortName.MaximumLength = (USHORT)Size;
+
+ /* Now append the full port name */
+ RtlAppendUnicodeStringToString(&CsrSbApiPortName, &CsrDirectoryName);
+ RtlAppendUnicodeToString(&CsrSbApiPortName, UNICODE_PATH_SEP);
+ RtlAppendUnicodeToString(&CsrSbApiPortName, SB_PORT_NAME);
+ if (CsrDebug & 2) DPRINT1("CSRSS: Creating %wZ port and associated thread\n", &CsrSbApiPortName);
+
+ /* Create Security Descriptor for this Port */
+ Status = CsrCreateLocalSystemSD(&PortSd);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Initialize the Attributes */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &CsrSbApiPortName,
+ 0,
+ NULL,
+ PortSd);
+
+ /* Create the Port Object */
+ Status = NtCreatePort(&CsrSbApiPort,
+ &ObjectAttributes,
+ sizeof(SB_CONNECTION_INFO),
+ sizeof(SB_API_MSG),
+ 32 * sizeof(SB_API_MSG));
+ if (PortSd) RtlFreeHeap(CsrHeap, 0, PortSd);
+
+ if (NT_SUCCESS(Status))
+ {
+ /* Create the Thread to handle the API Requests */
+ Status = RtlCreateUserThread(NtCurrentProcess(),
+ NULL,
+ TRUE,
+ 0,
+ 0,
+ 0,
+ (PVOID)CsrSbApiRequestThread,
+ NULL,
+ &hRequestThread,
+ &ClientId);
+ if (NT_SUCCESS(Status))
+ {
+ /* Add it as a Static Server Thread */
+ CsrSbApiRequestThreadPtr = CsrAddStaticServerThread(hRequestThread,
+ &ClientId,
+ 0);
+
+ /* Activate it */
+ Status = NtResumeThread(hRequestThread, NULL);
+ }
+ }
+
+ return Status;
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+/*++
+ * @name CsrServerInitialization
+ * @implemented NT4
+ *
+ * The CsrServerInitialization routine is the native (not Server) entrypoint
+ * of this Server DLL. It serves as the entrypoint for csrss.
+ *
+ * @param ArgumentCount
+ * Number of arguments on the command line.
+ *
+ * @param Arguments
+ * Array of arguments from the command line.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrServerInitialization(IN ULONG ArgumentCount,
+ IN PCHAR Arguments[])
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ DPRINT("CSRSRV: %s called\n", __FUNCTION__);
+
+ /* Create the Init Event */
+ Status = NtCreateEvent(&CsrInitializationEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: NtCreateEvent failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Cache System Basic Information so we don't always request it */
+ Status = NtQuerySystemInformation(SystemBasicInformation,
+ &CsrNtSysInfo,
+ sizeof(SYSTEM_BASIC_INFORMATION),
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: NtQuerySystemInformation failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Save our Heap */
+ CsrHeap = RtlGetProcessHeap();
+
+ /* Set our Security Descriptor to protect the process */
+ Status = CsrSetProcessSecurity();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: CsrSetProcessSecurity failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Set up Session Support */
+ Status = CsrInitializeNtSessionList();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: CsrInitializeSessions failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Set up Process Support */
+ Status = CsrInitializeProcessStructure();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: CsrInitializeProcessStructure failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Parse the command line */
+ Status = CsrParseServerCommandLine(ArgumentCount, Arguments);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: CsrParseServerCommandLine failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ Status = CsrApiRegisterDefinitions(NativeDefinitions);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV failed in %s with status %lx\n", "CsrApiRegisterDefinitions", Status);
+ }
+
+ /* Now initialize our API Port */
+ Status = CsrApiPortInitialize();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: CsrApiPortInitialize failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Initialize Win32csr */
+ Status = CsrLoadServerDll("win32csr", "Win32CsrInitialization", 2);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV failed in %s with status %lx\n", "CsrLoadServerDll", Status);
+ }
+
+ /* Initialize the API Port for SM communication */
+ Status = CsrSbApiPortInitialize();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: CsrSbApiPortInitialize failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* We're all set! Connect to SM! */
+ Status = SmConnectToSm(&CsrSbApiPortName,
+ CsrSbApiPort,
+ IMAGE_SUBSYSTEM_WINDOWS_GUI,
+ &CsrSmApiPort);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: SmConnectToSm failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Finito! Signal the event */
+ Status = NtSetEvent(CsrInitializationEvent, NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: NtSetEvent failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Close the event handle now */
+ NtClose(CsrInitializationEvent);
+
+ /* Have us handle Hard Errors */
+ Status = NtSetDefaultHardErrorPort(CsrApiPort);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSRV:%s: NtSetDefaultHardErrorPort failed (Status=%08lx)\n",
+ __FUNCTION__, Status);
+ return Status;
+ }
+
+ /* Return status */
+ return Status;
+}
+
+/*++
+ * @name CsrPopulateDosDevices
+ * @unimplemented NT5.1
+ *
+ * The CsrPopulateDosDevices routine uses the DOS Device Map from the Kernel
+ * to populate the Dos Devices Object Directory for the session.
+ *
+ * @param None.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrPopulateDosDevices(VOID)
+{
+ DPRINT1("Deprecated API\n");
+ return;
+}
+
+BOOL
+NTAPI
+DllMain(IN HANDLE hDll,
+ IN DWORD dwReason,
+ IN LPVOID lpReserved)
+{
+ /* We don't do much */
+ UNREFERENCED_PARAMETER(hDll);
+ UNREFERENCED_PARAMETER(dwReason);
+ UNREFERENCED_PARAMETER(lpReserved);
+ return TRUE;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CSR Sub System
+ * FILE: subsystems/win32/csrss/csrsrv/procsup.c
+ * PURPOSE: CSR Process Management
+ * PROGRAMMERS: ReactOS Portable Systems Group
+ * Alex Ionescu
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <srv.h>
+
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS ********************************************************************/
+
+RTL_CRITICAL_SECTION ProcessDataLock;
+PCSR_PROCESS CsrRootProcess = NULL;
+SECURITY_QUALITY_OF_SERVICE CsrSecurityQos =
+{
+ sizeof(SECURITY_QUALITY_OF_SERVICE),
+ SecurityImpersonation,
+ SECURITY_STATIC_TRACKING,
+ FALSE
+};
+ULONG CsrProcessSequenceCount = 5;
+extern ULONG CsrTotalPerProcessDataLength;
+
+/* FUNCTIONS ******************************************************************/
+
+VOID
+NTAPI
+CsrSetToNormalPriority(VOID)
+{
+ KPRIORITY BasePriority = (8 + 1) + 4;
+
+ /* Set the Priority */
+ NtSetInformationProcess(NtCurrentProcess(),
+ ProcessBasePriority,
+ &BasePriority,
+ sizeof(KPRIORITY));
+}
+
+VOID
+NTAPI
+CsrSetToShutdownPriority(VOID)
+{
+ KPRIORITY SetBasePriority = (8 + 1) + 6;
+ BOOLEAN Old;
+
+ /* Get the shutdown privilege */
+ if (NT_SUCCESS(RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
+ TRUE,
+ FALSE,
+ &Old)))
+ {
+ /* Set the Priority */
+ NtSetInformationProcess(NtCurrentProcess(),
+ ProcessBasePriority,
+ &SetBasePriority,
+ sizeof(KPRIORITY));
+ }
+}
+
+/*++
+ * @name CsrGetProcessLuid
+ * @implemented NT4
+ *
+ * Do nothing for 500ms.
+ *
+ * @param hProcess
+ * Optional handle to the process whose LUID should be returned.
+ *
+ * @param Luid
+ * Pointer to a LUID Pointer which will receive the CSR Process' LUID
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks If hProcess is not supplied, then the current thread's token will
+ * be used. If that too is missing, then the current process' token
+ * will be used.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrGetProcessLuid(HANDLE hProcess OPTIONAL,
+ PLUID Luid)
+{
+ HANDLE hToken = NULL;
+ NTSTATUS Status;
+ ULONG Length;
+ PTOKEN_STATISTICS TokenStats;
+
+ /* Check if we have a handle to a CSR Process */
+ if (!hProcess)
+ {
+ /* We don't, so try opening the Thread's Token */
+ Status = NtOpenThreadToken(NtCurrentThread(),
+ TOKEN_QUERY,
+ FALSE,
+ &hToken);
+
+ /* Check for success */
+ if (!NT_SUCCESS(Status))
+ {
+ /* If we got some other failure, then return and quit */
+ if (Status != STATUS_NO_TOKEN) return Status;
+
+ /* We don't have a Thread Token, use a Process Token */
+ hProcess = NtCurrentProcess();
+ hToken = NULL;
+ }
+ }
+
+ /* Check if we have a token by now */
+ if (!hToken)
+ {
+ /* No token yet, so open the Process Token */
+ Status = NtOpenProcessToken(hProcess,
+ TOKEN_QUERY,
+ &hToken);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Still no token, return the error */
+ return Status;
+ }
+ }
+
+ /* Now get the size we'll need for the Token Information */
+ Status = NtQueryInformationToken(hToken,
+ TokenStatistics,
+ NULL,
+ 0,
+ &Length);
+
+ /* Allocate memory for the Token Info */
+ if (!(TokenStats = RtlAllocateHeap(CsrHeap, 0, Length)))
+ {
+ /* Fail and close the token */
+ NtClose(hToken);
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Now query the information */
+ Status = NtQueryInformationToken(hToken,
+ TokenStatistics,
+ TokenStats,
+ Length,
+ &Length);
+
+ /* Close the handle */
+ NtClose(hToken);
+
+ /* Check for success */
+ if (NT_SUCCESS(Status))
+ {
+ /* Return the LUID */
+ *Luid = TokenStats->AuthenticationId;
+ }
+
+ /* Free the query information */
+ RtlFreeHeap(CsrHeap, 0, TokenStats);
+
+ /* Return the Status */
+ return Status;
+}
+
+/*++
+ * @name CsrImpersonateClient
+ * @implemented NT4
+ *
+ * The CsrImpersonateClient will impersonate the given CSR Thread.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread to impersonate.
+ *
+ * @return TRUE if impersionation suceeded, false otherwise.
+ *
+ * @remarks Impersonation can be recursive.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrImpersonateClient(IN PCSR_THREAD CsrThread)
+{
+ NTSTATUS Status;
+ PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
+
+ /* Use the current thread if none given */
+ if (!CsrThread) CsrThread = CurrentThread;
+
+ /* Still no thread, something is wrong */
+ if (!CsrThread)
+ {
+ /* Failure */
+ return FALSE;
+ }
+
+ /* Make the call */
+ Status = NtImpersonateThread(NtCurrentThread(),
+ CsrThread->ThreadHandle,
+ &CsrSecurityQos);
+
+ if (!NT_SUCCESS(Status))
+ {
+ /* Failure */
+/*
+ DPRINT1("CSRSS: Can't impersonate client thread - Status = %lx\n", Status);
+ if (Status != STATUS_BAD_IMPERSONATION_LEVEL) DbgBreakPoint();
+*/
+ return FALSE;
+ }
+
+ /* Increase the impersonation count for the current thread */
+ if (CurrentThread) ++CurrentThread->ImpersonationCount;
+
+ /* Return Success */
+ return TRUE;
+}
+
+/*++
+ * @name CsrRevertToSelf
+ * @implemented NT4
+ *
+ * The CsrRevertToSelf routine will attempt to remove an active impersonation.
+ *
+ * @param None.
+ *
+ * @return TRUE if the reversion was succesful, false otherwise.
+ *
+ * @remarks Impersonation can be recursive; as such, the impersonation token
+ * will only be deleted once the CSR Thread's impersonaton count
+ * has reached zero.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrRevertToSelf(VOID)
+{
+ NTSTATUS Status;
+ PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
+ HANDLE ImpersonationToken = NULL;
+
+ /* Check if we have a Current Thread */
+ if (CurrentThread)
+ {
+ /* Make sure impersonation is on */
+ if (!CurrentThread->ImpersonationCount)
+ {
+ // DPRINT1("CSRSS: CsrRevertToSelf called while not impersonating\n");
+ return FALSE;
+ }
+ else if (--CurrentThread->ImpersonationCount > 0)
+ {
+ /* Success; impersonation count decreased but still not zero */
+ return TRUE;
+ }
+ }
+
+ /* Impersonation has been totally removed, revert to ourselves */
+ Status = NtSetInformationThread(NtCurrentThread(),
+ ThreadImpersonationToken,
+ &ImpersonationToken,
+ sizeof(HANDLE));
+
+ /* Return TRUE or FALSE */
+ return NT_SUCCESS(Status);
+}
+
+/*++
+ * @name FindProcessForShutdown
+ *
+ * The FindProcessForShutdown routine returns a CSR Process which is ready
+ * to be shutdown, and sets the appropriate shutdown flags for it.
+ *
+ * @param CallerLuid
+ * Pointer to the LUID of the CSR Process calling this routine.
+ *
+ * @return Pointer to a CSR Process which is ready to be shutdown.
+ *
+ * @remarks None.
+ *
+ *--*/
+PCSR_PROCESS
+NTAPI
+FindProcessForShutdown(IN PLUID CallerLuid)
+{
+ PCSR_PROCESS CsrProcess, ReturnCsrProcess = NULL;
+ // PCSR_THREAD CsrThread;
+ NTSTATUS Status;
+ ULONG Level = 0;
+ LUID ProcessLuid;
+ LUID SystemLuid = SYSTEM_LUID;
+ // BOOLEAN IsSystemLuid = FALSE, IsOurLuid = FALSE;
+ PLIST_ENTRY NextEntry;
+
+ /* Set the List Pointers */
+ NextEntry = CsrRootProcess->ListLink.Flink;
+ while (NextEntry != &CsrRootProcess->ListLink)
+ {
+ /* Get the process */
+ CsrProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink);
+
+ /* Move to the next entry */
+ NextEntry = NextEntry->Flink;
+
+ /* Skip this process if it's already been processed */
+ if (CsrProcess->Flags & CsrProcessSkipShutdown) continue;
+
+ /* Get the LUID of this Process */
+ Status = CsrGetProcessLuid(CsrProcess->ProcessHandle, &ProcessLuid);
+
+ /* Check if we didn't get access to the LUID */
+ if (Status == STATUS_ACCESS_DENIED)
+ {
+ /* FIXME:Check if we have any threads */
+/*
+ if (CsrProcess->ThreadCount)
+ {
+ /\* Impersonate one of the threads and retry *\/
+ CsrThread = CONTAINING_RECORD(CsrProcess->ThreadList.Flink,
+ CSR_THREAD,
+ Link);
+ CsrImpersonateClient(CsrThread);
+ Status = CsrGetProcessLuid(NULL, &ProcessLuid);
+ CsrRevertToSelf();
+ }
+*/
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ /* We didn't have access, so skip it */
+ CsrProcess->Flags |= CsrProcessSkipShutdown;
+ continue;
+ }
+
+ /* Check if this is the System LUID */
+ if ((/*IsSystemLuid =*/ RtlEqualLuid(&ProcessLuid, &SystemLuid)))
+ {
+ /* Mark this process */
+ CsrProcess->ShutdownFlags |= CsrShutdownSystem;
+ }
+ else if (!(/*IsOurLuid =*/ RtlEqualLuid(&ProcessLuid, CallerLuid)))
+ {
+ /* Our LUID doesn't match with the caller's */
+ CsrProcess->ShutdownFlags |= CsrShutdownOther;
+ }
+
+ /* Check if we're past the previous level */
+ if (CsrProcess->ShutdownLevel > Level /* || !ReturnCsrProcess */)
+ {
+ /* Update the level */
+ Level = CsrProcess->ShutdownLevel;
+
+ /* Set the final process */
+ ReturnCsrProcess = CsrProcess;
+ }
+ }
+
+ /* Check if we found a process */
+ if (ReturnCsrProcess)
+ {
+ /* Skip this one next time */
+ ReturnCsrProcess->Flags |= CsrProcessSkipShutdown;
+ }
+
+ return ReturnCsrProcess;
+}
+
+/* This is really "CsrShutdownProcess", mostly */
+NTSTATUS
+WINAPI
+CsrEnumProcesses(IN CSRSS_ENUM_PROCESS_PROC EnumProc,
+ IN PVOID Context)
+{
+ PVOID* RealContext = (PVOID*)Context;
+ PLUID CallerLuid = RealContext[0];
+ PCSR_PROCESS CsrProcess = NULL;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ BOOLEAN FirstTry;
+ PLIST_ENTRY NextEntry;
+ ULONG Result = 0;
+
+ /* Acquire process lock */
+ CsrAcquireProcessLock();
+
+ /* Get the list pointers */
+ NextEntry = CsrRootProcess->ListLink.Flink;
+ while (NextEntry != &CsrRootProcess->ListLink)
+ {
+ /* Get the Process */
+ CsrProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink);
+
+ /* Remove the skip flag, set shutdown flags to 0*/
+ CsrProcess->Flags &= ~CsrProcessSkipShutdown;
+ CsrProcess->ShutdownFlags = 0;
+
+ /* Move to the next */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* Set shudown Priority */
+ CsrSetToShutdownPriority();
+
+ /* Loop all processes */
+ //DPRINT1("Enumerating for LUID: %lx %lx\n", CallerLuid->HighPart, CallerLuid->LowPart);
+
+ /* Start looping */
+ while (TRUE)
+ {
+ /* Find the next process to shutdown */
+ FirstTry = TRUE;
+ if (!(CsrProcess = FindProcessForShutdown(CallerLuid)))
+ {
+ /* Done, quit */
+ CsrReleaseProcessLock();
+ Status = STATUS_SUCCESS;
+ goto Quickie;
+ }
+
+LoopAgain:
+ /* Release the lock, make the callback, and acquire it back */
+ //DPRINT1("Found process: %lx\n", CsrProcess->ClientId.UniqueProcess);
+ CsrReleaseProcessLock();
+ Result = (ULONG)EnumProc(CsrProcess, (PVOID)((ULONG_PTR)Context | FirstTry));
+ CsrAcquireProcessLock();
+
+ /* Check the result */
+ //DPRINT1("Result: %d\n", Result);
+ if (Result == CsrShutdownCsrProcess)
+ {
+ /* The callback unlocked the process */
+ break;
+ }
+ else if (Result == CsrShutdownNonCsrProcess)
+ {
+ /* A non-CSR process, the callback didn't touch it */
+ //continue;
+ }
+ else if (Result == CsrShutdownCancelled)
+ {
+ /* Shutdown was cancelled, unlock and exit */
+ CsrReleaseProcessLock();
+ Status = STATUS_CANCELLED;
+ goto Quickie;
+ }
+
+ /* No matches during the first try, so loop again */
+ if (FirstTry && Result == CsrShutdownNonCsrProcess)
+ {
+ FirstTry = FALSE;
+ goto LoopAgain;
+ }
+ }
+
+Quickie:
+ /* Return to normal priority */
+ CsrSetToNormalPriority();
+ return Status;
+}
+
+/*++
+ * @name CsrProcessRefcountZero
+ *
+ * The CsrProcessRefcountZero routine is executed when a CSR Process has lost
+ * all its active references. It removes and de-allocates the CSR Process.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process that is to be deleted.
+ *
+ * @return None.
+ *
+ * @remarks Do not call this routine. It is reserved for the internal
+ * thread management routines when a CSR Process has lost all
+ * its references.
+ *
+ * This routine is called with the Process Lock held.
+ *
+ *--*/
+VOID
+NTAPI
+CsrProcessRefcountZero(IN PCSR_PROCESS CsrProcess)
+{
+ ASSERT(ProcessStructureListLocked());
+
+ /* Remove the Process from the list */
+ CsrRemoveProcess(CsrProcess);
+
+ /* Check if there's a session */
+ if (CsrProcess->NtSession)
+ {
+ /* Dereference the Session */
+ CsrDereferenceNtSession(CsrProcess->NtSession, 0);
+ }
+
+ /* Close the Client Port if there is one */
+ if (CsrProcess->ClientPort) NtClose(CsrProcess->ClientPort);
+
+ /* Close the process handle */
+ NtClose(CsrProcess->ProcessHandle);
+
+ /* Free the Proces Object */
+ CsrDeallocateProcess(CsrProcess);
+}
+
+/*++
+ * @name CsrLockedDereferenceProcess
+ *
+ * The CsrLockedDereferenceProcess dereferences a CSR Process while the
+ * Process Lock is already being held.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process to be dereferenced.
+ *
+ * @return None.
+ *
+ * @remarks This routine will return with the Process Lock held.
+ *
+ *--*/
+VOID
+NTAPI
+CsrLockedDereferenceProcess(PCSR_PROCESS CsrProcess)
+{
+ LONG LockCount;
+
+ /* Decrease reference count */
+ LockCount = --CsrProcess->ReferenceCount;
+ ASSERT(LockCount >= 0);
+ if (!LockCount)
+ {
+ /* Call the generic cleanup code */
+ DPRINT1("Should kill process: %p\n", CsrProcess);
+ CsrProcessRefcountZero(CsrProcess);
+ CsrAcquireProcessLock();
+ }
+}
+
+/*++
+ * @name CsrDereferenceProcess
+ * @implemented NT4
+ *
+ * The CsrDereferenceProcess routine removes a reference from a CSR Process.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Process to dereference.
+ *
+ * @return None.
+ *
+ * @remarks If the reference count has reached zero (ie: the CSR Process has
+ * no more active references), it will be deleted.
+ *
+ *--*/
+VOID
+NTAPI
+CsrDereferenceProcess(IN PCSR_PROCESS CsrProcess)
+{
+ LONG LockCount;
+
+ /* Acquire process lock */
+ CsrAcquireProcessLock();
+
+ /* Decrease reference count */
+ LockCount = --CsrProcess->ReferenceCount;
+ ASSERT(LockCount >= 0);
+ if (!LockCount)
+ {
+ /* Call the generic cleanup code */
+ CsrProcessRefcountZero(CsrProcess);
+ }
+ else
+ {
+ /* Just release the lock */
+ CsrReleaseProcessLock();
+ }
+}
+
+/*++
+ * @name CsrDestroyProcess
+ * @implemented NT4
+ *
+ * The CsrDestroyProcess routine destroys the CSR Process corresponding to
+ * a given Client ID.
+ *
+ * @param Cid
+ * Pointer to the Client ID Structure corresponding to the CSR
+ * Process which is about to be destroyed.
+ *
+ * @param ExitStatus
+ * Unused.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING
+ * if the CSR Process is already terminating.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrDestroyProcess(IN PCLIENT_ID Cid,
+ IN NTSTATUS ExitStatus)
+{
+ PCSR_THREAD CsrThread;
+ PCSR_PROCESS CsrProcess;
+ CLIENT_ID ClientId = *Cid;
+ PLIST_ENTRY NextEntry;
+
+ /* Acquire lock */
+ CsrAcquireProcessLock();
+
+ /* Find the thread */
+ CsrThread = CsrLocateThreadByClientId(&CsrProcess, &ClientId);
+
+ /* Make sure we got one back, and that it's not already gone */
+ if (!(CsrThread) || (CsrProcess->Flags & CsrProcessTerminating))
+ {
+ /* Release the lock and return failure */
+ CsrReleaseProcessLock();
+ return STATUS_THREAD_IS_TERMINATING;
+ }
+
+ /* Set the terminated flag */
+ CsrProcess->Flags |= CsrProcessTerminating;
+
+ /* Get the List Pointers */
+ NextEntry = CsrProcess->ThreadList.Flink;
+ while (NextEntry != &CsrProcess->ThreadList)
+ {
+ /* Get the current thread entry */
+ CsrThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
+
+ /* Make sure the thread isn't already dead */
+ if (CsrThread->Flags & CsrThreadTerminated)
+ {
+ NextEntry = NextEntry->Flink;
+ continue;
+ }
+
+ /* Set the Terminated flag */
+ CsrThread->Flags |= CsrThreadTerminated;
+
+ /* Acquire the Wait Lock */
+ CsrAcquireWaitLock();
+
+ /* Do we have an active wait block? */
+ if (CsrThread->WaitBlock)
+ {
+ /* Notify waiters of termination */
+ CsrNotifyWaitBlock(CsrThread->WaitBlock,
+ NULL,
+ NULL,
+ NULL,
+ CsrProcessTerminating,
+ TRUE);
+ }
+
+ /* Release the Wait Lock */
+ CsrReleaseWaitLock();
+
+ /* Dereference the thread */
+ CsrLockedDereferenceThread(CsrThread);
+ NextEntry = CsrProcess->ThreadList.Flink;
+ }
+
+ /* Release the Process Lock and return success */
+ CsrReleaseProcessLock();
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrCreateProcess
+ * @implemented NT4
+ *
+ * Do nothing for 500ms.
+ *
+ * @param ArgumentCount
+ * Description of the parameter. Wrapped to more lines on ~70th
+ * column.
+ *
+ * @param Arguments
+ * Description of the parameter. Wrapped to more lines on ~70th
+ * column.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrCreateProcess(IN HANDLE hProcess,
+ IN HANDLE hThread,
+ IN PCLIENT_ID ClientId,
+ IN PCSR_NT_SESSION NtSession,
+ IN ULONG Flags,
+ IN PCLIENT_ID DebugCid)
+{
+ PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
+ CLIENT_ID CurrentCid;
+ PCSR_PROCESS CurrentProcess;
+// PVOID ProcessData;
+// ULONG i;
+ PCSR_PROCESS CsrProcess;
+ NTSTATUS Status;
+ PCSR_THREAD CsrThread;
+ KERNEL_USER_TIMES KernelTimes;
+
+ /* Get the current CID and lock Processes */
+ CurrentCid = CurrentThread->ClientId;
+ CsrAcquireProcessLock();
+
+ /* Get the current CSR Thread */
+ CurrentThread = CsrLocateThreadByClientId(&CurrentProcess, &CurrentCid);
+ if (!CurrentThread)
+ {
+ /* We've failed to locate the thread */
+ CsrReleaseProcessLock();
+ return STATUS_THREAD_IS_TERMINATING;
+ }
+
+ /* Allocate a new Process Object */
+ CsrProcess = CsrAllocateProcess();
+ if (!CsrProcess)
+ {
+ /* Couldn't allocate Process */
+ CsrReleaseProcessLock();
+ return STATUS_NO_MEMORY;
+ }
+
+#if 0
+ /* Inherit the Process Data */
+ CurrentProcess = CurrentThread->Process;
+ ProcessData = &CurrentProcess->ServerData[CSR_SERVER_DLL_MAX];
+ for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+ {
+ /* Check if the DLL is Loaded and has Per Process Data */
+ if ((CsrLoadedServerDll[i]) && (CsrLoadedServerDll[i]->SizeOfProcessData))
+ {
+ /* Set the pointer */
+ CsrProcess->ServerData[i] = ProcessData;
+
+ /* Copy the Data */
+ RtlMoveMemory(ProcessData,
+ CurrentProcess->ServerData[i],
+ CsrLoadedServerDll[i]->SizeOfProcessData);
+
+ /* Update next data pointer */
+ ProcessData = (PVOID)((ULONG_PTR)ProcessData +
+ CsrLoadedServerDll[i]->SizeOfProcessData);
+ }
+ else
+ {
+ /* No data for this Server */
+ CsrProcess->ServerData[i] = NULL;
+ }
+ }
+#endif
+
+ /* Set the Exception port to us */
+ Status = NtSetInformationProcess(hProcess,
+ ProcessExceptionPort,
+ &CsrApiPort,
+ sizeof(HANDLE));
+ if (!NT_SUCCESS(Status))
+ {
+ /* Failed */
+ CsrDeallocateProcess(CsrProcess);
+ CsrReleaseProcessLock();
+ return STATUS_NO_MEMORY;
+ }
+
+ /* If Check if CreateProcess got CREATE_NEW_PROCESS_GROUP */
+ if (!(Flags & CsrProcessCreateNewGroup))
+ {
+ /* Create new data */
+ CsrProcess->ProcessGroupId = HandleToUlong(ClientId->UniqueProcess);
+ CsrProcess->ProcessGroupSequence = CsrProcess->SequenceNumber;
+ }
+ else
+ {
+ /* Copy it from the current process */
+ CsrProcess->ProcessGroupId = CurrentProcess->ProcessGroupId;
+ CsrProcess->ProcessGroupSequence = CurrentProcess->ProcessGroupSequence;
+ }
+
+ /* Check if this is a console process */
+ if (Flags & CsrProcessIsConsoleApp) CsrProcess->Flags |= CsrProcessIsConsoleApp;
+
+ /* Mask out non-debug flags */
+ Flags &= ~(CsrProcessIsConsoleApp | CsrProcessCreateNewGroup | CsrProcessPriorityFlags);
+
+ /* Check if every process will be debugged */
+ if (!(Flags) && (CurrentProcess->DebugFlags & CsrDebugProcessChildren))
+ {
+ /* Pass it on to the current process */
+ CsrProcess->DebugFlags = CsrDebugProcessChildren;
+ CsrProcess->DebugCid = CurrentProcess->DebugCid;
+ }
+
+ /* Check if Debugging was used on this process */
+ if ((Flags & (CsrDebugOnlyThisProcess | CsrDebugProcessChildren)) && (DebugCid))
+ {
+ /* Save the debug flag used */
+ CsrProcess->DebugFlags = Flags;
+
+ /* Save the CID */
+ CsrProcess->DebugCid = *DebugCid;
+ }
+
+ /* Check if we debugging is enabled */
+ if (CsrProcess->DebugFlags)
+ {
+ /* Set the Debug Port to us */
+ Status = NtSetInformationProcess(hProcess,
+ ProcessDebugPort,
+ &CsrApiPort,
+ sizeof(HANDLE));
+ ASSERT(NT_SUCCESS(Status));
+ if (!NT_SUCCESS(Status))
+ {
+ /* Failed */
+ CsrDeallocateProcess(CsrProcess);
+ CsrReleaseProcessLock();
+ return STATUS_NO_MEMORY;
+ }
+ }
+
+ /* Get the Thread Create Time */
+ Status = NtQueryInformationThread(hThread,
+ ThreadTimes,
+ (PVOID)&KernelTimes,
+ sizeof(KernelTimes),
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Failed */
+ CsrDeallocateProcess(CsrProcess);
+ CsrReleaseProcessLock();
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Allocate a CSR Thread Structure */
+ CsrThread = CsrAllocateThread(CsrProcess);
+ if (!CsrThread)
+ {
+ /* Failed */
+ CsrDeallocateProcess(CsrProcess);
+ CsrReleaseProcessLock();
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Save the data we have */
+ CsrThread->CreateTime = KernelTimes.CreateTime;
+ CsrThread->ClientId = *ClientId;
+ CsrThread->ThreadHandle = hThread;
+ ProtectHandle(hThread);
+ CsrThread->Flags = 0;
+
+ /* Insert the Thread into the Process */
+ CsrInsertThread(CsrProcess, CsrThread);
+
+ /* Reference the session */
+ CsrReferenceNtSession(NtSession);
+ CsrProcess->NtSession = NtSession;
+
+ /* Setup Process Data */
+ CsrProcess->ClientId = *ClientId;
+ CsrProcess->ProcessHandle = hProcess;
+ CsrProcess->ShutdownLevel = 0x280;
+
+ /* Set the Priority to Background */
+ CsrSetBackgroundPriority(CsrProcess);
+
+ /* Insert the Process */
+ CsrInsertProcess(NULL, CurrentProcess, CsrProcess);
+
+ /* Release lock and return */
+ CsrReleaseProcessLock();
+ return Status;
+}
+
+/*++
+ * @name CsrUnlockProcess
+ * @implemented NT4
+ *
+ * The CsrUnlockProcess undoes a previous CsrLockProcessByClientId operation.
+ *
+ * @param CsrProcess
+ * Pointer to a previously locked CSR Process.
+ *
+ * @return STATUS_SUCCESS.
+ *
+ * @remarks This routine must be called with the Process Lock held.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrUnlockProcess(IN PCSR_PROCESS CsrProcess)
+{
+ /* Dereference the process */
+ CsrLockedDereferenceProcess(CsrProcess);
+
+ /* Release the lock and return */
+ CsrReleaseProcessLock();
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrSetBackgroundPriority
+ * @implemented NT4
+ *
+ * The CsrSetBackgroundPriority routine sets the priority for the given CSR
+ * Process as a Background priority.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process whose priority will be modified.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrSetBackgroundPriority(IN PCSR_PROCESS CsrProcess)
+{
+ PROCESS_PRIORITY_CLASS PriorityClass;
+
+ /* Set the Foreground bit off */
+ PriorityClass.Foreground = FALSE;
+
+ /* Set the new Priority */
+ NtSetInformationProcess(CsrProcess->ProcessHandle,
+ ProcessPriorityClass,
+ &PriorityClass,
+ sizeof(PriorityClass));
+}
+
+/*++
+ * @name CsrAllocateProcess
+ * @implemented NT4
+ *
+ * The CsrAllocateProcess routine allocates a new CSR Process object.
+ *
+ * @return Pointer to the newly allocated CSR Process.
+ *
+ * @remarks None.
+ *
+ *--*/
+PCSR_PROCESS
+NTAPI
+CsrAllocateProcess(VOID)
+{
+ PCSR_PROCESS CsrProcess;
+ ULONG TotalSize;
+
+ /* Calculate the amount of memory this should take */
+ TotalSize = sizeof(CSR_PROCESS) +
+ (CSR_SERVER_DLL_MAX * sizeof(PVOID)) +
+ CsrTotalPerProcessDataLength;
+
+ /* Allocate a Process */
+ CsrProcess = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, TotalSize);
+ if (!CsrProcess) return NULL;
+
+ /* Handle the Sequence Number and protect against overflow */
+ CsrProcess->SequenceNumber = CsrProcessSequenceCount++;
+ if (CsrProcessSequenceCount < 5) CsrProcessSequenceCount = 5;
+
+ /* Increase the reference count */
+ CsrProcess->ReferenceCount++;
+
+ /* Initialize the Thread List */
+ InitializeListHead(&CsrProcess->ThreadList);
+
+ /* Return the Process */
+ return CsrProcess;
+}
+
+/*++
+ * @name CsrLockedReferenceProcess
+ *
+ * The CsrLockedReferenceProcess references a CSR Process while the
+ * Process Lock is already being held.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process to be referenced.
+ *
+ * @return None.
+ *
+ * @remarks This routine will return with the Process Lock held.
+ *
+ *--*/
+VOID
+NTAPI
+CsrLockedReferenceProcess(IN PCSR_PROCESS CsrProcess)
+{
+ /* Increment the reference count */
+ ++CsrProcess->ReferenceCount;
+}
+
+/*++
+ * @name CsrInitializeProcessStructure
+ * @implemented NT4
+ *
+ * The CsrInitializeProcessStructure routine sets up support for CSR Processes
+ * and CSR Threads.
+ *
+ * @param None.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrInitializeProcessStructure(VOID)
+{
+ NTSTATUS Status;
+ ULONG i;
+
+ /* Initialize the Lock */
+ Status = RtlInitializeCriticalSection(&ProcessDataLock);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Set up the Root Process */
+ CsrRootProcess = CsrAllocateProcess();
+ if (!CsrRootProcess) return STATUS_NO_MEMORY;
+
+ /* Set up the minimal information for it */
+ InitializeListHead(&CsrRootProcess->ListLink);
+ CsrRootProcess->ProcessHandle = (HANDLE)-1;
+ CsrRootProcess->ClientId = NtCurrentTeb()->ClientId;
+
+ /* Initialize the Thread Hash List */
+ for (i = 0; i < 256; i++) InitializeListHead(&CsrThreadHashTable[i]);
+
+ /* Initialize the Wait Lock */
+ return RtlInitializeCriticalSection(&CsrWaitListsLock);
+}
+
+/*++
+ * @name CsrDeallocateProcess
+ *
+ * The CsrDeallocateProcess frees the memory associated with a CSR Process.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process to be freed.
+ *
+ * @return None.
+ *
+ * @remarks Do not call this routine. It is reserved for the internal
+ * thread management routines when a CSR Process has been cleanly
+ * dereferenced and killed.
+ *
+ *--*/
+VOID
+NTAPI
+CsrDeallocateProcess(IN PCSR_PROCESS CsrProcess)
+{
+ /* Free the process object from the heap */
+ RtlFreeHeap(CsrHeap, 0, CsrProcess);
+}
+
+/*++
+ * @name CsrRemoveProcess
+ *
+ * The CsrRemoveProcess function undoes a CsrInsertProcess operation and
+ * removes the CSR Process from the Process List and notifies Server DLLs
+ * of this removal.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process to remove.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrRemoveProcess(IN PCSR_PROCESS CsrProcess)
+{
+ PCSR_SERVER_DLL ServerDll;
+ ULONG i;
+ ASSERT(ProcessStructureListLocked());
+
+ /* Remove us from the Process List */
+ RemoveEntryList(&CsrProcess->ListLink);
+
+ /* Release the lock */
+ CsrReleaseProcessLock();
+
+ /* Loop every Server DLL */
+ for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+ {
+ /* Get the Server DLL */
+ ServerDll = CsrLoadedServerDll[i];
+
+ /* Check if it's valid and if it has a Disconnect Callback */
+ if ((ServerDll) && (ServerDll->DisconnectCallback))
+ {
+ /* Call it */
+ ServerDll->DisconnectCallback(CsrProcess);
+ }
+ }
+}
+
+/*++
+ * @name CsrInsertProcess
+ *
+ * The CsrInsertProcess routine inserts a CSR Process into the Process List
+ * and notifies Server DLLs of the creation of a new CSR Process.
+ *
+ * @param Parent
+ * Optional pointer to the CSR Process creating this CSR Process.
+ *
+ * @param CurrentProcess
+ * Optional pointer to the current CSR Process.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process which is to be inserted.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrInsertProcess(IN PCSR_PROCESS Parent OPTIONAL,
+ IN PCSR_PROCESS CurrentProcess OPTIONAL,
+ IN PCSR_PROCESS CsrProcess)
+{
+#if 0
+ PCSR_SERVER_DLL ServerDll;
+ ULONG i;
+#endif
+ ASSERT(ProcessStructureListLocked());
+
+ /* Set the parent */
+ CsrProcess->Parent = Parent;
+
+ /* Insert it into the Root List */
+ InsertTailList(&CsrRootProcess->ListLink, &CsrProcess->ListLink);
+#if 0
+ /* Notify the Server DLLs */
+ for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+ {
+ /* Get the current Server DLL */
+ ServerDll = CsrLoadedServerDll[i];
+
+ /* Make sure it's valid and that it has callback */
+ if ((ServerDll) && (ServerDll->NewProcessCallback))
+ {
+ ServerDll->NewProcessCallback(CurrentProcess, CsrProcess);
+ }
+ }
+#endif
+}
+
+/*++
+ * @name CsrLockProcessByClientId
+ * @implemented NT4
+ *
+ * The CsrLockProcessByClientId routine locks the CSR Process corresponding
+ * to the given Process ID and optionally returns it.
+ *
+ * @param Pid
+ * Process ID corresponding to the CSR Process which will be locked.
+ *
+ * @param CsrProcess
+ * Optional pointer to a CSR Process pointer which will hold the
+ * CSR Process corresponding to the given Process ID.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks Locking a CSR Process is defined as acquiring an extra
+ * reference to it and returning with the Process Lock held.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrLockProcessByClientId(IN HANDLE Pid,
+ OUT PCSR_PROCESS *CsrProcess)
+{
+ PLIST_ENTRY NextEntry;
+ PCSR_PROCESS CurrentProcess = NULL;
+ NTSTATUS Status;
+
+ /* Acquire the lock */
+ CsrAcquireProcessLock();
+
+ /* Assume failure */
+ ASSERT(CsrProcess != NULL);
+ *CsrProcess = NULL;
+
+ /* Setup the List Pointers */
+ NextEntry = &CsrRootProcess->ListLink;
+ do
+ {
+ /* Get the Process */
+ CurrentProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink);
+
+ /* Check for PID Match */
+ if (CurrentProcess->ClientId.UniqueProcess == Pid)
+ {
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ /* Next entry */
+ NextEntry = NextEntry->Flink;
+ } while (NextEntry != &CsrRootProcess->ListLink);
+
+ /* Check if we didn't find it in the list */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Nothing found, release the lock */
+ CsrReleaseProcessLock();
+ }
+ else
+ {
+ /* Lock the found process and return it */
+ CsrLockedReferenceProcess(CurrentProcess);
+ *CsrProcess = CurrentProcess;
+ }
+
+ /* Return the result */
+ return Status;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CSR Sub System
+ * FILE: subsystems/win32/csrss/csrsrv/server.c
+ * PURPOSE: CSR Server DLL Server Functions
+ * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
+ */
+
+/* INCLUDES ******************************************************************/
+#include "srv.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* DATA **********************************************************************/
+
+PCSR_API_ROUTINE CsrServerApiDispatchTable[5] =
+{
+ CsrSrvClientConnect,
+ CsrSrvUnusedFunction,
+ CsrSrvUnusedFunction,
+ CsrSrvIdentifyAlertableThread,
+ CsrSrvSetPriorityClass
+};
+
+BOOLEAN CsrServerApiServerValidTable[5] =
+{
+ TRUE,
+ FALSE,
+ TRUE,
+ TRUE,
+ TRUE
+};
+
+PCHAR CsrServerApiNameTable[5] =
+{
+ "ClientConnect",
+ "ThreadConnect",
+ "ProfileControl",
+ "IdentifyAlertableThread",
+ "SetPriorityClass"
+};
+
+PCSR_SERVER_DLL CsrLoadedServerDll[CSR_SERVER_DLL_MAX];
+PVOID CsrSrvSharedSectionHeap;
+PVOID CsrSrvSharedSectionBase;
+PVOID *CsrSrvSharedStaticServerData;
+ULONG CsrSrvSharedSectionSize;
+HANDLE CsrSrvSharedSection;
+
+/* PRIVATE FUNCTIONS**********************************************************/
+
+/*++
+ * @name CsrServerDllInitialization
+ * @implemented NT4
+ *
+ * The CsrServerDllInitialization is the initialization routine for
+ * the this Server DLL.
+ *
+ * @param LoadedServerDll
+ * Pointer to the CSR Server DLL structure representing this Server DLL.
+ *
+ * @return STATUS_SUCCESS.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrServerDllInitialization(IN PCSR_SERVER_DLL LoadedServerDll)
+{
+ /* Setup the DLL Object */
+ LoadedServerDll->ApiBase = 0;
+ LoadedServerDll->HighestApiSupported = CsrpMaxApiNumber;
+ LoadedServerDll->DispatchTable = CsrServerApiDispatchTable;
+ LoadedServerDll->ValidTable = CsrServerApiServerValidTable;
+ LoadedServerDll->NameTable = CsrServerApiNameTable;
+ LoadedServerDll->SizeOfProcessData = 0;
+ LoadedServerDll->ConnectCallback = NULL;
+ LoadedServerDll->DisconnectCallback = NULL;
+
+ /* All done */
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrLoadServerDll
+ * @implemented NT4
+ *
+ * The CsrLoadServerDll routine loads a CSR Server DLL and calls its entrypoint
+ *
+ * @param DllString
+ * Pointer to the CSR Server DLL to load and call.
+ *
+ * @param EntryPoint
+ * Pointer to the name of the server's initialization function. If
+ * this parameter is NULL, the default ServerDllInitialize will be
+ * assumed.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrLoadServerDll(IN PCHAR DllString,
+ IN PCHAR EntryPoint OPTIONAL,
+ IN ULONG ServerId)
+{
+ NTSTATUS Status;
+ ANSI_STRING DllName;
+ UNICODE_STRING TempString, ErrorString;
+ ULONG_PTR Parameters[2];
+ HANDLE hServerDll = NULL;
+ ULONG Size;
+ PCSR_SERVER_DLL ServerDll;
+ STRING EntryPointString;
+ PCSR_SERVER_DLL_INIT_CALLBACK ServerDllInitProcedure;
+ ULONG Response;
+
+ /* Check if it's beyond the maximum we support */
+ if (ServerId >= CSR_SERVER_DLL_MAX) return STATUS_TOO_MANY_NAMES;
+
+ /* Check if it's already been loaded */
+ if (CsrLoadedServerDll[ServerId]) return STATUS_INVALID_PARAMETER;
+
+ /* Convert the name to Unicode */
+ ASSERT(DllString != NULL);
+ RtlInitAnsiString(&DllName, DllString);
+ Status = RtlAnsiStringToUnicodeString(&TempString, &DllName, TRUE);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* If we are loading ourselves, don't actually load us */
+ if (ServerId != CSR_SRV_SERVER)
+ {
+ /* Load the DLL */
+ Status = LdrLoadDll(NULL, 0, &TempString, &hServerDll);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Setup error parameters */
+ Parameters[0] = (ULONG_PTR)&TempString;
+ Parameters[1] = (ULONG_PTR)&ErrorString;
+ RtlInitUnicodeString(&ErrorString, L"Default Load Path");
+
+ /* Send a hard error */
+ NtRaiseHardError(Status,
+ 2,
+ 3,
+ Parameters,
+ OptionOk,
+ &Response);
+ }
+
+ /* Get rid of the string */
+ RtlFreeUnicodeString(&TempString);
+ if (!NT_SUCCESS(Status)) return Status;
+ }
+
+ /* Allocate a CSR DLL Object */
+ Size = sizeof(CSR_SERVER_DLL) + DllName.MaximumLength;
+ ServerDll = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, Size);
+ if (!ServerDll)
+ {
+ if (hServerDll) LdrUnloadDll(hServerDll);
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Set up the Object */
+ ServerDll->Length = Size;
+ ServerDll->SharedSection = CsrSrvSharedSectionHeap;
+ ServerDll->Event = CsrInitializationEvent;
+ ServerDll->Name.Length = DllName.Length;
+ ServerDll->Name.MaximumLength = DllName.MaximumLength;
+ ServerDll->Name.Buffer = (PCHAR)(ServerDll + 1);
+ if (DllName.Length)
+ {
+ strncpy(ServerDll->Name.Buffer, DllName.Buffer, DllName.Length);
+ }
+ ServerDll->ServerId = ServerId;
+ ServerDll->ServerHandle = hServerDll;
+
+ /* Now get the entrypoint */
+ if (hServerDll)
+ {
+ /* Initialize a string for the entrypoint, or use the default */
+ RtlInitAnsiString(&EntryPointString,
+ !(EntryPoint) ? "ServerDllInitialization" :
+ EntryPoint);
+
+ /* Get a pointer to it */
+ Status = LdrGetProcedureAddress(hServerDll,
+ &EntryPointString,
+ 0,
+ (PVOID)&ServerDllInitProcedure);
+ }
+ else
+ {
+ /* No handle, so we are loading ourselves */
+ ServerDllInitProcedure = CsrServerDllInitialization;
+ Status = STATUS_SUCCESS;
+ }
+
+ /* Check if we got the pointer, and call it */
+ if (NT_SUCCESS(Status))
+ {
+ /* Get the result from the Server DLL */
+ Status = ServerDllInitProcedure(ServerDll);
+
+ /* Check for Success */
+ if (NT_SUCCESS(Status))
+ {
+ /*
+ * Add this Server's Per-Process Data Size to the total that each
+ * process will need.
+ */
+ CsrTotalPerProcessDataLength += ServerDll->SizeOfProcessData;
+
+ /* Save the pointer in our list */
+ CsrLoadedServerDll[ServerDll->ServerId] = ServerDll;
+
+ /* Does it use our generic heap? */
+ if (ServerDll->SharedSection != CsrSrvSharedSectionHeap)
+ {
+ /* No, save the pointer to its shared section in our list */
+ CsrSrvSharedStaticServerData[ServerDll->ServerId] = ServerDll->SharedSection;
+ }
+
+ /* ReactOS Specific hax */
+ if (ServerDll->HighestApiSupported == 0xDEADBABE)
+ {
+ Status = CsrApiRegisterDefinitions((PVOID)ServerDll->DispatchTable);
+ }
+ }
+ else
+ {
+ /* Use shared failure code */
+ goto LoadFailed;
+ }
+ }
+ else
+ {
+LoadFailed:
+ /* Server Init failed, unload it */
+ if (hServerDll) LdrUnloadDll(hServerDll);
+
+ /* Delete the Object */
+ RtlFreeHeap(CsrHeap, 0, ServerDll);
+ }
+
+ /* Return to caller */
+ return Status;
+}
+
+/*++
+ * @name CsrSrvClientConnect
+ *
+ * The CsrSrvClientConnect CSR API handles a new connection to a server DLL.
+ *
+ * @param ApiMessage
+ * Pointer to the CSR API Message for this request.
+ *
+ * @param Reply
+ * Optional reply to this request.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_INVALID_PARAMETER
+ * or STATUS_TOO_MANY_NAMES in case of failure.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSrvClientConnect(IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply OPTIONAL)
+{
+ /* Hack */
+ return STATUS_SUCCESS;
+#if 0
+ NTSTATUS Status;
+ PCSR_CLIENT_CONNECT ClientConnect;
+ PCSR_SERVER_DLL ServerDll;
+ PCSR_PROCESS CurrentProcess = ((PCSR_THREAD)NtCurrentTeb()->CsrClientThread)->Process;
+
+ /* Load the Message, set default reply */
+ ClientConnect = (PCSR_CLIENT_CONNECT)&ApiMessage->CsrClientConnect;
+ *Reply = 0;
+
+ /* Validate the ServerID */
+ if (ClientConnect->ServerId >= CSR_SERVER_DLL_MAX)
+ {
+ return STATUS_TOO_MANY_NAMES;
+ }
+ else if (!CsrLoadedServerDll[ClientConnect->ServerId])
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Validate the Message Buffer */
+ if (!(CsrValidateMessageBuffer(ApiMessage,
+ ClientConnect->ConnectionInfo,
+ ClientConnect->ConnectionInfoSize,
+ 1)))
+ {
+ /* Fail due to buffer overflow or other invalid buffer */
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Load the Server DLL */
+ ServerDll = CsrLoadedServerDll[ClientConnect->ServerId];
+
+ /* Check if it has a Connect Callback */
+ if (ServerDll->ConnectCallback)
+ {
+ /* Call the callback */
+ Status = ServerDll->ConnectCallback(CurrentProcess,
+ ClientConnect->ConnectionInfo,
+ &ClientConnect->ConnectionInfoSize);
+ }
+ else
+ {
+ /* Assume success */
+ Status = STATUS_SUCCESS;
+ }
+
+ /* Return status */
+ return Status;
+#endif
+}
+
+/*++
+ * @name CsrSrvCreateSharedSection
+ *
+ * The CsrSrvCreateSharedSection creates the Shared Section that all CSR Server
+ * DLLs and Clients can use to share data.
+ *
+ * @param ParameterValue
+ * Specially formatted string from our registry command-line which
+ * specifies various arguments for the shared section.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSrvCreateSharedSection(IN PCHAR ParameterValue)
+{
+ PCHAR SizeValue = ParameterValue;
+ ULONG Size;
+ NTSTATUS Status;
+ LARGE_INTEGER SectionSize;
+ ULONG ViewSize = 0;
+ PPEB Peb = NtCurrentPeb();
+
+ /* If there's no parameter, fail */
+ if (!ParameterValue) return STATUS_INVALID_PARAMETER;
+
+ /* Find the first comma, and null terminate */
+ while (*SizeValue)
+ {
+ if (*SizeValue == ',')
+ {
+ *SizeValue++ = ANSI_NULL;
+ break;
+ }
+ else
+ {
+ SizeValue++;
+ }
+ }
+
+ /* Make sure it's valid */
+ if (!*SizeValue) return STATUS_INVALID_PARAMETER;
+
+ /* Convert it to an integer */
+ Status = RtlCharToInteger(SizeValue, 0, &Size);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Multiply by 1024 entries and round to page size */
+ CsrSrvSharedSectionSize = ROUND_UP(Size * 1024, CsrNtSysInfo.PageSize);
+
+ /* Create the Secion */
+ SectionSize.LowPart = CsrSrvSharedSectionSize;
+ SectionSize.HighPart = 0;
+ Status = NtCreateSection(&CsrSrvSharedSection,
+ SECTION_ALL_ACCESS,
+ NULL,
+ &SectionSize,
+ PAGE_EXECUTE_READWRITE,
+ SEC_BASED | SEC_RESERVE,
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Map the section */
+ Status = NtMapViewOfSection(CsrSrvSharedSection,
+ NtCurrentProcess(),
+ &CsrSrvSharedSectionBase,
+ 0,
+ 0,
+ NULL,
+ &ViewSize,
+ ViewUnmap,
+ MEM_TOP_DOWN,
+ PAGE_EXECUTE_READWRITE);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ NtClose(CsrSrvSharedSection);
+ return Status;
+ }
+
+ /* FIXME: Write the value to registry */
+
+ /* The Heap is the same place as the Base */
+ CsrSrvSharedSectionHeap = CsrSrvSharedSectionBase;
+
+ /* Create the heap */
+ if (!(RtlCreateHeap(HEAP_ZERO_MEMORY | HEAP_CLASS_7,
+ CsrSrvSharedSectionHeap,
+ CsrSrvSharedSectionSize,
+ PAGE_SIZE,
+ 0,
+ 0)))
+ {
+ /* Failure, unmap section and return */
+ NtUnmapViewOfSection(NtCurrentProcess(), CsrSrvSharedSectionBase);
+ NtClose(CsrSrvSharedSection);
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Now allocate space from the heap for the Shared Data */
+ CsrSrvSharedStaticServerData = RtlAllocateHeap(CsrSrvSharedSectionHeap,
+ 0,
+ CSR_SERVER_DLL_MAX *
+ sizeof(PVOID));
+ if (!CsrSrvSharedStaticServerData) return STATUS_NO_MEMORY;
+
+ /* Write the values to the PEB */
+ Peb->ReadOnlySharedMemoryBase = CsrSrvSharedSectionBase;
+ Peb->ReadOnlySharedMemoryHeap = CsrSrvSharedSectionHeap;
+ Peb->ReadOnlyStaticServerData = CsrSrvSharedStaticServerData;
+
+ /* Return */
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrSrvAttachSharedSection
+ *
+ * The CsrSrvAttachSharedSection maps the CSR Shared Section into a new
+ * CSR Process' address space, and returns the pointers to the section
+ * through the Connection Info structure.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process that is attempting a connection.
+ *
+ * @param ConnectInfo
+ * Pointer to the CSR Connection Info structure for the incoming
+ * connection.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSrvAttachSharedSection(IN PCSR_PROCESS CsrProcess OPTIONAL,
+ OUT PCSR_CONNECTION_INFO ConnectInfo)
+{
+ NTSTATUS Status;
+ ULONG ViewSize = 0;
+
+ /* Check if we have a process */
+ if (CsrProcess)
+ {
+ /* Map the section into this process */
+ DPRINT("CSR Process Handle: %p. CSR Process: %p\n", CsrProcess->ProcessHandle, CsrProcess);
+ Status = NtMapViewOfSection(CsrSrvSharedSection,
+ CsrProcess->ProcessHandle,
+ &CsrSrvSharedSectionBase,
+ 0,
+ 0,
+ NULL,
+ &ViewSize,
+ ViewUnmap,
+ SEC_NO_CHANGE,
+ PAGE_EXECUTE_READ);
+ if (!NT_SUCCESS(Status)) return Status;
+ }
+
+ /* Write the values in the Connection Info structure */
+ ConnectInfo->SharedSectionBase = CsrSrvSharedSectionBase;
+ ConnectInfo->SharedSectionHeap = CsrSrvSharedSectionHeap;
+ ConnectInfo->SharedSectionData = CsrSrvSharedStaticServerData;
+
+ /* Return success */
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrSrvIdentifyAlertableThread
+ * @implemented NT4
+ *
+ * The CsrSrvIdentifyAlertableThread CSR API marks a CSR Thread as alertable.
+ *
+ * @param ApiMessage
+ * Pointer to the CSR API Message for this request.
+ *
+ * @param Reply
+ * Pointer to an optional reply to this request.
+ *
+ * @return STATUS_SUCCESS.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSrvIdentifyAlertableThread(IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply)
+{
+ PCSR_THREAD CsrThread = NtCurrentTeb()->CsrClientThread;
+
+ /* Set the alertable flag */
+ CsrThread->Flags |= CsrThreadAltertable;
+
+ /* Return success */
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrSrvSetPriorityClass
+ * @implemented NT4
+ *
+ * The CsrSrvSetPriorityClass CSR API is deprecated.
+ *
+ * @param ApiMessage
+ * Pointer to the CSR API Message for this request.
+ *
+ * @param Reply
+ * Pointer to an optional reply to this request.
+ *
+ * @return STATUS_SUCCESS.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSrvSetPriorityClass(IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply)
+{
+ /* Deprecated */
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrSrvUnusedFunction
+ * @implemented NT4
+ *
+ * The CsrSrvUnusedFunction CSR API is a stub for deprecated APIs.
+ *
+ * The CsrSrvSetPriorityClass CSR API is deprecated.
+ *
+ * @param ApiMessage
+ * Pointer to the CSR API Message for this request.
+ *
+ * @param Reply
+ * Pointer to an optional reply to this request.
+ *
+ * @return STATUS_INVALID_PARAMETER.
+ *
+ * @remarks CsrSrvSetPriorityClass does not use this stub because it must
+ * return success.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSrvUnusedFunction(IN OUT PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG Reply)
+{
+ /* Deprecated */
+ return STATUS_INVALID_PARAMETER;
+}
+
+/* PUBLIC FUNCTIONS***********************************************************/
+
+/*++
+ * @name CsrSetCallingSpooler
+ * @implemented NT4
+ *
+ * the CsrSetCallingSpooler routine is deprecated.
+ *
+ * @param Reserved
+ * Deprecated
+ *
+ * @return None.
+ *
+ * @remarks This routine was used in archaic versions of NT for Printer Drivers.
+ *
+ *--*/
+VOID
+NTAPI
+CsrSetCallingSpooler(ULONG Reserved)
+{
+ /* Deprecated */
+ return;
+}
+
+/*++
+ * @name CsrUnhandledExceptionFilter
+ * @implemented NT5
+ *
+ * The CsrUnhandledExceptionFilter routine handles all exceptions
+ * within SEH-protected blocks.
+ *
+ * @param ExceptionPointers
+ * System-defined Argument.
+ *
+ * @return EXCEPTION_EXECUTE_HANDLER.
+ *
+ * @remarks None.
+ *
+ *--*/
+LONG
+NTAPI
+CsrUnhandledExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo)
+{
+ SYSTEM_KERNEL_DEBUGGER_INFORMATION DebuggerInfo;
+ EXCEPTION_DISPOSITION Result = EXCEPTION_EXECUTE_HANDLER;
+ BOOLEAN OldValue;
+ NTSTATUS Status;
+ UNICODE_STRING ErrorSource;
+ ULONG_PTR ErrorParameters[4];
+ ULONG Response;
+
+ /* Check if a debugger is installed */
+ Status = NtQuerySystemInformation(SystemKernelDebuggerInformation,
+ &DebuggerInfo,
+ sizeof(DebuggerInfo),
+ NULL);
+
+ /* Check if this is Session 0, and the Debugger is Enabled */
+ if ((NtCurrentPeb()->SessionId) && (NT_SUCCESS(Status)) &&
+ (DebuggerInfo.KernelDebuggerEnabled))
+ {
+ /* Call the Unhandled Exception Filter */
+ if ((Result = RtlUnhandledExceptionFilter(ExceptionInfo)) !=
+ EXCEPTION_CONTINUE_EXECUTION)
+ {
+ /* We're going to raise an error. Get Shutdown Privilege first */
+ Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
+ TRUE,
+ TRUE,
+ &OldValue);
+
+ /* Use the Process token if that failed */
+ if (Status == STATUS_NO_TOKEN)
+ {
+ Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
+ TRUE,
+ FALSE,
+ &OldValue);
+ }
+
+ /* Initialize our Name String */
+ RtlInitUnicodeString(&ErrorSource, L"Windows SubSystem");
+
+ /* Set the parameters */
+ ErrorParameters[0] = (ULONG_PTR)&ErrorSource;
+ ErrorParameters[1] = ExceptionInfo->ExceptionRecord->ExceptionCode;
+ ErrorParameters[2] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress;
+ ErrorParameters[3] = (ULONG_PTR)ExceptionInfo->ContextRecord;
+
+ /* Bugcheck */
+ Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
+ 4,
+ 1,
+ ErrorParameters,
+ OptionShutdownSystem,
+ &Response);
+ }
+
+ /* Just terminate us */
+ NtTerminateProcess(NtCurrentProcess(),
+ ExceptionInfo->ExceptionRecord->ExceptionCode);
+ }
+
+ return Result;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CSR Sub System
+ * FILE: subsystems/win32/csrss/csrsrv/session.c
+ * PURPOSE: CSR Server DLL Session Implementation
+ * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "srv.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* DATA **********************************************************************/
+
+RTL_CRITICAL_SECTION CsrNtSessionLock;
+LIST_ENTRY CsrNtSessionList;
+
+PCHAR CsrServerSbApiName[5] =
+{
+ "SbCreateSession",
+ "SbTerminateSession",
+ "SbForeignSessionComplete",
+ "SbCreateProcess",
+ "Unknown Csr Sb Api Number"
+};
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+/*++
+ * @name CsrInitializeNtSessionList
+ *
+ * The CsrInitializeNtSessionList routine sets up support for CSR Sessions.
+ *
+ * @param None
+ *
+ * @return None
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrInitializeNtSessionList(VOID)
+{
+ DPRINT("CSRSRV: %s called\n", __FUNCTION__);
+
+ /* Initialize the Session List */
+ InitializeListHead(&CsrNtSessionList);
+
+ /* Initialize the Session Lock */
+ return RtlInitializeCriticalSection(&CsrNtSessionLock);
+}
+
+/*++
+ * @name CsrAllocateNtSession
+ *
+ * The CsrAllocateNtSession routine allocates a new CSR NT Session.
+ *
+ * @param SessionId
+ * Session ID of the CSR NT Session to allocate.
+ *
+ * @return Pointer to the newly allocated CSR NT Session.
+ *
+ * @remarks None.
+ *
+ *--*/
+PCSR_NT_SESSION
+NTAPI
+CsrAllocateNtSession(IN ULONG SessionId)
+{
+ PCSR_NT_SESSION NtSession;
+
+ /* Allocate an NT Session Object */
+ NtSession = RtlAllocateHeap(CsrHeap, 0, sizeof(CSR_NT_SESSION));
+ if (NtSession)
+ {
+ /* Setup the Session Object */
+ NtSession->SessionId = SessionId;
+ NtSession->ReferenceCount = 1;
+
+ /* Insert it into the Session List */
+ CsrAcquireNtSessionLock();
+ InsertHeadList(&CsrNtSessionList, &NtSession->SessionLink);
+ CsrReleaseNtSessionLock();
+ }
+ else
+ {
+ ASSERT(NtSession != NULL);
+ }
+
+ /* Return the Session (or NULL) */
+ return NtSession;
+}
+
+/*++
+ * @name CsrReferenceNtSession
+ *
+ * The CsrReferenceNtSession increases the reference count of a CSR NT Session.
+ *
+ * @param Session
+ * Pointer to the CSR NT Session to reference.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrReferenceNtSession(IN PCSR_NT_SESSION Session)
+{
+ /* Acquire the lock */
+ CsrAcquireNtSessionLock();
+
+ /* Sanity checks */
+ ASSERT(!IsListEmpty(&Session->SessionLink));
+ ASSERT(Session->SessionId != 0);
+ ASSERT(Session->ReferenceCount != 0);
+
+ /* Increase the reference count */
+ Session->ReferenceCount++;
+
+ /* Release the lock */
+ CsrReleaseNtSessionLock();
+}
+
+/*++
+ * @name CsrDereferenceNtSession
+ *
+ * The CsrDereferenceNtSession decreases the reference count of a
+ * CSR NT Session.
+ *
+ * @param Session
+ * Pointer to the CSR NT Session to reference.
+ *
+ * @param ExitStatus
+ * If this is the last reference to the session, this argument
+ * specifies the exit status.
+ *
+ * @return None.
+ *
+ * @remarks CsrDereferenceNtSession will complete the session if
+ * the last reference to it has been closed.
+ *
+ *--*/
+VOID
+NTAPI
+CsrDereferenceNtSession(IN PCSR_NT_SESSION Session,
+ IN NTSTATUS ExitStatus)
+{
+ /* Acquire the lock */
+ CsrAcquireNtSessionLock();
+
+ /* Sanity checks */
+ ASSERT(!IsListEmpty(&Session->SessionLink));
+ ASSERT(Session->SessionId != 0);
+ ASSERT(Session->ReferenceCount != 0);
+
+ /* Dereference the Session Object */
+ if (!(--Session->ReferenceCount))
+ {
+ /* Remove it from the list */
+ RemoveEntryList(&Session->SessionLink);
+
+ /* Release the lock */
+ CsrReleaseNtSessionLock();
+
+ /* Tell SM that we're done here */
+ SmSessionComplete(CsrSmApiPort, Session->SessionId, ExitStatus);
+
+ /* Free the Session Object */
+ RtlFreeHeap(CsrHeap, 0, Session);
+ }
+ else
+ {
+ /* Release the lock, the Session is still active */
+ CsrReleaseNtSessionLock();
+ }
+}
+
+/* SESSION MANAGER FUNCTIONS**************************************************/
+
+/*++
+ * @name CsrSbCreateSession
+ *
+ * The CsrSbCreateSession API is called by the Session Manager whenever a new
+ * session is created.
+ *
+ * @param ApiMessage
+ * Pointer to the Session Manager API Message.
+ *
+ * @return TRUE in case of success, FALSE otherwise.
+ *
+ * @remarks The CsrSbCreateSession routine will initialize a new CSR NT
+ * Session and allocate a new CSR Process for the subsystem process.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrSbCreateSession(IN PSB_API_MSG ApiMessage)
+{
+ PSB_CREATE_SESSION_MSG CreateSession = &ApiMessage->CreateSession;
+ HANDLE hProcess, hThread;
+ PCSR_PROCESS CsrProcess;
+ NTSTATUS Status;
+ KERNEL_USER_TIMES KernelTimes;
+ PCSR_THREAD CsrThread;
+ //PVOID ProcessData;
+ //ULONG i;
+
+ /* Save the Process and Thread Handles */
+ hProcess = CreateSession->ProcessInfo.ProcessHandle;
+ hThread = CreateSession->ProcessInfo.ThreadHandle;
+
+ /* Lock the Processes */
+ CsrAcquireProcessLock();
+
+ /* Allocate a new process */
+ CsrProcess = CsrAllocateProcess();
+ if (!CsrProcess)
+ {
+ /* Fail */
+ ApiMessage->ReturnValue = STATUS_NO_MEMORY;
+ CsrReleaseProcessLock();
+ return TRUE;
+ }
+
+ /* Set the exception port */
+ Status = NtSetInformationProcess(hProcess,
+ ProcessExceptionPort,
+ &CsrApiPort,
+ sizeof(HANDLE));
+
+ /* Check for success */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail the request */
+ CsrDeallocateProcess(CsrProcess);
+ CsrReleaseProcessLock();
+
+ /* Strange as it seems, NTSTATUSes are actually returned */
+ return (BOOLEAN)STATUS_NO_MEMORY;
+ }
+
+ /* Get the Create Time */
+ Status = NtQueryInformationThread(hThread,
+ ThreadTimes,
+ &KernelTimes,
+ sizeof(KERNEL_USER_TIMES),
+ NULL);
+
+ /* Check for success */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail the request */
+ CsrDeallocateProcess(CsrProcess);
+ CsrReleaseProcessLock();
+
+ /* Strange as it seems, NTSTATUSes are actually returned */
+ return (BOOLEAN)Status;
+ }
+
+ /* Allocate a new Thread */
+ CsrThread = CsrAllocateThread(CsrProcess);
+ if (!CsrThread)
+ {
+ /* Fail the request */
+ CsrDeallocateProcess(CsrProcess);
+ CsrReleaseProcessLock();
+
+ ApiMessage->ReturnValue = STATUS_NO_MEMORY;
+ return TRUE;
+ }
+
+ /* Setup the Thread Object */
+ CsrThread->CreateTime = KernelTimes.CreateTime;
+ CsrThread->ClientId = CreateSession->ProcessInfo.ClientId;
+ CsrThread->ThreadHandle = hThread;
+ ProtectHandle(hThread);
+ CsrThread->Flags = 0;
+
+ /* Insert it into the Process List */
+ CsrInsertThread(CsrProcess, CsrThread);
+
+ /* Setup Process Data */
+ CsrProcess->ClientId = CreateSession->ProcessInfo.ClientId;
+ CsrProcess->ProcessHandle = hProcess;
+ CsrProcess->NtSession = CsrAllocateNtSession(CreateSession->SessionId);
+
+ /* Set the Process Priority */
+ CsrSetBackgroundPriority(CsrProcess);
+#if 0
+ /* Get the first data location */
+ ProcessData = &CsrProcess->ServerData[CSR_SERVER_DLL_MAX];
+
+ /* Loop every DLL */
+ for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+ {
+ /* Check if the DLL is loaded and has Process Data */
+ if (CsrLoadedServerDll[i] && CsrLoadedServerDll[i]->SizeOfProcessData)
+ {
+ /* Write the pointer to the data */
+ CsrProcess->ServerData[i] = ProcessData;
+
+ /* Move to the next data location */
+ ProcessData = (PVOID)((ULONG_PTR)ProcessData +
+ CsrLoadedServerDll[i]->SizeOfProcessData);
+ }
+ else
+ {
+ /* Nothing for this Process */
+ CsrProcess->ServerData[i] = NULL;
+ }
+ }
+#else
+ /* HACKZ: should go in BaseSrv part of CreateCallback done in Insert below */
+ RtlInitializeCriticalSection(&CsrProcess->HandleTableLock);
+#endif
+ /* Insert the Process */
+ CsrInsertProcess(NULL, NULL, CsrProcess);
+
+ /* Activate the Thread */
+ ApiMessage->ReturnValue = NtResumeThread(hThread, NULL);
+
+ /* Release lock and return */
+ CsrReleaseProcessLock();
+ return TRUE;
+}
+
+/*++
+ * @name CsrSbForeignSessionComplete
+ *
+ * The CsrSbForeignSessionComplete API is called by the Session Manager
+ * whenever a foreign session is completed (ie: terminated).
+ *
+ * @param ApiMessage
+ * Pointer to the Session Manager API Message.
+ *
+ * @return TRUE in case of success, FALSE otherwise.
+ *
+ * @remarks The CsrSbForeignSessionComplete API is not yet implemented.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrSbForeignSessionComplete(IN PSB_API_MSG ApiMessage)
+{
+ /* Deprecated/Unimplemented in NT */
+ ApiMessage->ReturnValue = STATUS_NOT_IMPLEMENTED;
+ return TRUE;
+}
+
+/*++
+ * @name CsrSbTerminateSession
+ *
+ * The CsrSbTerminateSession API is called by the Session Manager
+ * whenever a foreign session should be destroyed.
+ *
+ * @param ApiMessage
+ * Pointer to the Session Manager API Message.
+ *
+ * @return TRUE in case of success, FALSE otherwise.
+ *
+ * @remarks The CsrSbTerminateSession API is not yet implemented.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrSbTerminateSession(IN PSB_API_MSG ApiMessage)
+{
+ ApiMessage->ReturnValue = STATUS_NOT_IMPLEMENTED;
+ return TRUE;
+}
+
+/*++
+ * @name CsrSbCreateProcess
+ *
+ * The CsrSbCreateProcess API is called by the Session Manager
+ * whenever a foreign session is created and a new process should be started.
+ *
+ * @param ApiMessage
+ * Pointer to the Session Manager API Message.
+ *
+ * @return TRUE in case of success, FALSE otherwise.
+ *
+ * @remarks The CsrSbCreateProcess API is not yet implemented.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrSbCreateProcess(IN PSB_API_MSG ApiMessage)
+{
+ ApiMessage->ReturnValue = STATUS_NOT_IMPLEMENTED;
+ return TRUE;
+}
+
+PSB_API_ROUTINE CsrServerSbApiDispatch[5] =
+{
+ CsrSbCreateSession,
+ CsrSbTerminateSession,
+ CsrSbForeignSessionComplete,
+ CsrSbCreateProcess,
+ NULL
+};
+
+/*++
+ * @name CsrSbApiHandleConnectionRequest
+ *
+ * The CsrSbApiHandleConnectionRequest routine handles and accepts a new
+ * connection request to the SM API LPC Port.
+ *
+ * @param ApiMessage
+ * Pointer to the incoming CSR API Message which contains the
+ * connection request.
+ *
+ * @return STATUS_SUCCESS in case of success, or status code which caused
+ * the routine to error.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrSbApiHandleConnectionRequest(IN PSB_API_MSG Message)
+{
+ NTSTATUS Status;
+ REMOTE_PORT_VIEW RemotePortView;
+ HANDLE hPort;
+
+ /* Set the Port View Structure Length */
+ RemotePortView.Length = sizeof(REMOTE_PORT_VIEW);
+
+ /* Accept the connection */
+ Status = NtAcceptConnectPort(&hPort,
+ NULL,
+ (PPORT_MESSAGE)Message,
+ TRUE,
+ NULL,
+ &RemotePortView);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: Sb Accept Connection failed %lx\n", Status);
+ return Status;
+ }
+
+ /* Complete the Connection */
+ Status = NtCompleteConnectPort(hPort);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: Sb Complete Connection failed %lx\n",Status);
+ }
+
+ /* Return status */
+ return Status;
+}
+
+/*++
+ * @name CsrSbApiRequestThread
+ *
+ * The CsrSbApiRequestThread routine handles incoming messages or connection
+ * requests on the SM API LPC Port.
+ *
+ * @param Parameter
+ * System-default user-defined parameter. Unused.
+ *
+ * @return The thread exit code, if the thread is terminated.
+ *
+ * @remarks Before listening on the port, the routine will first attempt
+ * to connect to the user subsystem.
+ *
+ *--*/
+VOID
+NTAPI
+CsrSbApiRequestThread(IN PVOID Parameter)
+{
+ NTSTATUS Status;
+ SB_API_MSG ReceiveMsg;
+ PSB_API_MSG ReplyMsg = NULL;
+ PVOID PortContext;
+ ULONG MessageType;
+
+ /* Start the loop */
+ while (TRUE)
+ {
+ /* Wait for a message to come in */
+ Status = NtReplyWaitReceivePort(CsrSbApiPort,
+ &PortContext,
+ &ReplyMsg->h,
+ &ReceiveMsg.h);
+
+ /* Check if we didn't get success */
+ if (Status != STATUS_SUCCESS)
+ {
+ /* If we only got a warning, keep going */
+ if (NT_SUCCESS(Status)) continue;
+
+ /* We failed big time, so start out fresh */
+ ReplyMsg = NULL;
+ DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status);
+ continue;
+ }
+
+ /* Save the message type */
+ MessageType = ReceiveMsg.h.u2.s2.Type;
+
+ /* Check if this is a connection request */
+ if (MessageType == LPC_CONNECTION_REQUEST)
+ {
+ /* Handle connection request */
+ CsrSbApiHandleConnectionRequest(&ReceiveMsg);
+
+ /* Start over */
+ ReplyMsg = NULL;
+ continue;
+ }
+
+ /* Check if the port died */
+ if (MessageType == LPC_PORT_CLOSED)
+ {
+ /* Close the handle if we have one */
+ if (PortContext) NtClose((HANDLE)PortContext);
+
+ /* Client died, start over */
+ ReplyMsg = NULL;
+ continue;
+ }
+ else if (MessageType == LPC_CLIENT_DIED)
+ {
+ /* Client died, start over */
+ ReplyMsg = NULL;
+ continue;
+ }
+
+ /*
+ * It's an API Message, check if it's within limits. If it's not, the
+ * NT Behaviour is to set this to the Maximum API.
+ */
+ if (ReceiveMsg.ApiNumber > SbpMaxApiNumber)
+ {
+ ReceiveMsg.ApiNumber = SbpMaxApiNumber;
+ DPRINT1("CSRSS: %lx is invalid Sb ApiNumber\n", ReceiveMsg.ApiNumber);
+ }
+
+ /* Reuse the message */
+ ReplyMsg = &ReceiveMsg;
+
+ /* Make sure that the message is supported */
+ if (ReceiveMsg.ApiNumber < SbpMaxApiNumber)
+ {
+ /* Call the API */
+ if (!CsrServerSbApiDispatch[ReceiveMsg.ApiNumber](&ReceiveMsg))
+ {
+ /* It failed, so return nothing */
+ ReplyMsg = NULL;
+ }
+ }
+ else
+ {
+ /* We don't support this API Number */
+ ReplyMsg->ReturnValue = STATUS_NOT_IMPLEMENTED;
+ }
+ }
+}
+
+/* EOF */
--- /dev/null
+#ifndef _SRV_H
+#define _SRV_H
+
+/* PSDK/NDK Headers */
+#define NTOS_MODE_USER
+#include <stdio.h>
+#define WIN32_NO_STATUS
+#include <windef.h>
+#include <winbase.h>
+#include <wincon.h>
+#include <winreg.h>
+#include <ndk/setypes.h>
+#include <ndk/sefuncs.h>
+#include <ndk/exfuncs.h>
+#include <ndk/cmfuncs.h>
+#include <ndk/obfuncs.h>
+#include <ndk/lpctypes.h>
+#include <ndk/lpcfuncs.h>
+#include <ndk/kefuncs.h>
+#include <ndk/dbgktypes.h>
+#include <ndk/mmfuncs.h>
+#include <ndk/umfuncs.h>
+
+/* CSR Header */
+//#include <csr/server.h>
+
+/* PSEH for SEH Support */
+#include <pseh/pseh2.h>
+
+/* Subsystem Manager Header */
+#include <sm/helper.h>
+#include <sm/smmsg.h>
+
+/* Internal CSRSS Headers */
+#include <api.h>
+#include <csrplugin.h>
+
+extern HANDLE CsrHeap;
+
+#define SM_REG_KEY \
+ L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager"
+
+#define SESSION_ROOT L"\\Sessions"
+#define GLOBAL_ROOT L"\\GLOBAL??"
+#define SYMLINK_NAME L"SymbolicLink"
+#define SB_PORT_NAME L"SbAbiPort"
+#define CSR_PORT_NAME L"ApiPort"
+#define UNICODE_PATH_SEP L"\\"
+
+/* Defines */
+#define ROUND_UP(n, align) ROUND_DOWN(((ULONG)n) + (align) - 1, (align))
+#define ROUND_DOWN(n, align) (((ULONG)n) & ~((align) - 1l))
+
+#endif
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CSR Sub System
+ * FILE: subsystems/win32/csrss/csrsrv/thredsup.c
+ * PURPOSE: CSR Server DLL Thread Implementation
+ * PROGRAMMERS: ReactOS Portable Systems Group
+ * Alex Ionescu
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <srv.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#define CsrHashThread(t) \
+ (HandleToUlong(t)&(256 - 1))
+
+/* GLOBALS ********************************************************************/
+
+LIST_ENTRY CsrThreadHashTable[256];
+
+/* FUNCTIONS ******************************************************************/
+
+/*++
+ * @name ProtectHandle
+ * @implemented NT5.2
+ *
+ * The ProtectHandle routine protects an object handle against closure.
+ *
+ * @return TRUE or FALSE.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+ProtectHandle(IN HANDLE ObjectHandle)
+{
+ NTSTATUS Status;
+ OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo;
+
+ /* Query current state */
+ Status = NtQueryObject(ObjectHandle,
+ ObjectHandleFlagInformation,
+ &HandleInfo,
+ sizeof(HandleInfo),
+ NULL);
+ if (NT_SUCCESS(Status))
+ {
+ /* Enable protect from close */
+ HandleInfo.ProtectFromClose = TRUE;
+ Status = NtSetInformationObject(ObjectHandle,
+ ObjectHandleFlagInformation,
+ &HandleInfo,
+ sizeof(HandleInfo));
+ if (NT_SUCCESS(Status)) return TRUE;
+ }
+
+ /* We failed to or set the state */
+ return FALSE;
+}
+
+/*++
+ * @name UnProtectHandle
+ * @implemented NT5.2
+ *
+ * The UnProtectHandle routine unprotects an object handle against closure.
+ *
+ * @return TRUE or FALSE.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+UnProtectHandle(IN HANDLE ObjectHandle)
+{
+ NTSTATUS Status;
+ OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo;
+
+ /* Query current state */
+ Status = NtQueryObject(ObjectHandle,
+ ObjectHandleFlagInformation,
+ &HandleInfo,
+ sizeof(HandleInfo),
+ NULL);
+ if (NT_SUCCESS(Status))
+ {
+ /* Disable protect from close */
+ HandleInfo.ProtectFromClose = FALSE;
+ Status = NtSetInformationObject(ObjectHandle,
+ ObjectHandleFlagInformation,
+ &HandleInfo,
+ sizeof(HandleInfo));
+ if (NT_SUCCESS(Status)) return TRUE;
+ }
+
+ /* We failed to or set the state */
+ return FALSE;
+}
+
+/*++
+ * @name CsrAllocateThread
+ *
+ * The CsrAllocateThread routine allocates a new CSR Thread object.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process which will contain this CSR Thread.
+ *
+ * @return Pointer to the newly allocated CSR Thread.
+ *
+ * @remarks None.
+ *
+ *--*/
+PCSR_THREAD
+NTAPI
+CsrAllocateThread(IN PCSR_PROCESS CsrProcess)
+{
+ PCSR_THREAD CsrThread;
+
+ /* Allocate the structure */
+ CsrThread = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, sizeof(CSR_THREAD));
+ if (!CsrThread) return(NULL);
+
+ /* Reference the Thread and Process */
+ CsrThread->ReferenceCount++;
+ CsrProcess->ReferenceCount++;
+
+ /* Set the Parent Process */
+ CsrThread->Process = CsrProcess;
+
+ /* Return Thread */
+ return CsrThread;
+}
+
+/*++
+ * @name CsrLockedReferenceThread
+ *
+ * The CsrLockedReferenceThread references a CSR Thread while the
+ * Process Lock is already being held.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread to be referenced.
+ *
+ * @return None.
+ *
+ * @remarks This routine will return with the Process Lock held.
+ *
+ *--*/
+VOID
+NTAPI
+CsrLockedReferenceThread(IN PCSR_THREAD CsrThread)
+{
+ /* Increment the reference count */
+ ++CsrThread->ReferenceCount;
+}
+
+/*++
+ * @name CsrLocateThreadByClientId
+ *
+ * The CsrLocateThreadByClientId routine locates the CSR Thread and,
+ * optionally, its parent CSR Process, corresponding to a Client ID.
+ *
+ * @param Process
+ * Optional pointer to a CSR Process pointer which will contain
+ * the CSR Thread's parent.
+ *
+ * @param ClientId
+ * Pointer to a Client ID structure containing the Unique Thread ID
+ * to look up.
+ *
+ * @return Pointer to the CSR Thread corresponding to this CID, or NULL if
+ * none was found.
+ *
+ * @remarks None.
+ *
+ *--*/
+PCSR_THREAD
+NTAPI
+CsrLocateThreadByClientId(OUT PCSR_PROCESS *Process OPTIONAL,
+ IN PCLIENT_ID ClientId)
+{
+ ULONG i;
+ PLIST_ENTRY ListHead, NextEntry;
+ PCSR_THREAD FoundThread;
+ // ASSERT(ProcessStructureListLocked());
+
+ /* Hash the Thread */
+ i = CsrHashThread(ClientId->UniqueThread);
+
+ /* Set the list pointers */
+ ListHead = &CsrThreadHashTable[i];
+ NextEntry = ListHead->Flink;
+
+ /* Star the loop */
+ while (NextEntry != ListHead)
+ {
+ /* Get the thread */
+ FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
+
+ /* Compare the CID */
+ if (FoundThread->ClientId.UniqueThread == ClientId->UniqueThread)
+ {
+ /* Match found, return the process */
+ *Process = FoundThread->Process;
+
+ /* Return thread too */
+// DPRINT1("Found: %p %p\n", FoundThread, FoundThread->Process);
+ return FoundThread;
+ }
+
+ /* Next */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* Nothing found */
+ return NULL;
+}
+
+/*++
+ * @name CsrLocateThreadInProcess
+ *
+ * The CsrLocateThreadInProcess routine locates the CSR Thread
+ * corresponding to a Client ID inside a specific CSR Process.
+ *
+ * @param Process
+ * Optional pointer to the CSR Process which contains the CSR Thread
+ * that will be looked up.
+ *
+ * @param ClientId
+ * Pointer to a Client ID structure containing the Unique Thread ID
+ * to look up.
+ *
+ * @return Pointer to the CSR Thread corresponding to this CID, or NULL if
+ * none was found.
+ *
+ * @remarks If the CsrProcess argument is NULL, the lookup will be done inside
+ * CsrRootProcess.
+ *
+ *--*/
+PCSR_THREAD
+NTAPI
+CsrLocateThreadInProcess(IN PCSR_PROCESS CsrProcess OPTIONAL,
+ IN PCLIENT_ID Cid)
+{
+ PLIST_ENTRY ListHead, NextEntry;
+ PCSR_THREAD FoundThread = NULL;
+
+ /* Use the Root Process if none was specified */
+ if (!CsrProcess) CsrProcess = CsrRootProcess;
+
+ /* Save the List pointers */
+// DPRINT1("Searching in: %p %d\n", CsrProcess, CsrProcess->ThreadCount);
+ ListHead = &CsrProcess->ThreadList;
+ NextEntry = ListHead->Flink;
+
+ /* Start the Loop */
+ while (NextEntry != ListHead)
+ {
+ /* Get Thread Entry */
+ FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
+
+ /* Check for TID Match */
+ if (FoundThread->ClientId.UniqueThread == Cid->UniqueThread) break;
+
+ /* Next entry */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* Return what we found */
+// DPRINT1("Found: %p\n", FoundThread);
+ return FoundThread;
+}
+
+/*++
+ * @name CsrInsertThread
+ *
+ * The CsrInsertThread routine inserts a CSR Thread into its parent's
+ * Thread List and into the Thread Hash Table.
+ *
+ * @param Process
+ * Pointer to the CSR Process containing this CSR Thread.
+ *
+ * @param Thread
+ * Pointer to the CSR Thread to be inserted.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrInsertThread(IN PCSR_PROCESS Process,
+ IN PCSR_THREAD Thread)
+{
+ ULONG i;
+ // ASSERT(ProcessStructureListLocked());
+
+ /* Insert it into the Regular List */
+ InsertTailList(&Process->ThreadList, &Thread->Link);
+
+ /* Increase Thread Count */
+ Process->ThreadCount++;
+
+ /* Hash the Thread */
+ i = CsrHashThread(Thread->ClientId.UniqueThread);
+// DPRINT1("TID %lx HASH: %lx\n", Thread->ClientId.UniqueThread, i);
+
+ /* Insert it there too */
+ InsertHeadList(&CsrThreadHashTable[i], &Thread->HashLinks);
+}
+
+/*++
+ * @name CsrDeallocateThread
+ *
+ * The CsrDeallocateThread frees the memory associated with a CSR Thread.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread to be freed.
+ *
+ * @return None.
+ *
+ * @remarks Do not call this routine. It is reserved for the internal
+ * thread management routines when a CSR Thread has been cleanly
+ * dereferenced and killed.
+ *
+ *--*/
+VOID
+NTAPI
+CsrDeallocateThread(IN PCSR_THREAD CsrThread)
+{
+ /* Free the process object from the heap */
+ // ASSERT(CsrThread->WaitBlock == NULL);
+ RtlFreeHeap(CsrHeap, 0, CsrThread);
+}
+
+/*++
+ * @name CsrRemoveThread
+ *
+ * The CsrRemoveThread function undoes a CsrInsertThread operation and
+ * removes the CSR Thread from the the Hash Table and Thread List.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread to remove.
+ *
+ * @return None.
+ *
+ * @remarks If this CSR Thread is the last one inside a CSR Process, the
+ * parent will be dereferenced and the CsrProcessLastThreadTerminated
+ * flag will be set.
+ *
+ * After executing this routine, the CSR Thread will have the
+ * CsrThreadInTermination flag set.
+ *
+ *--*/
+VOID
+NTAPI
+CsrRemoveThread(IN PCSR_THREAD CsrThread)
+{
+ ASSERT(ProcessStructureListLocked());
+
+ /* Remove it from the List */
+ RemoveEntryList(&CsrThread->Link);
+
+ /* Decreate the thread count of the process */
+ CsrThread->Process->ThreadCount--;
+
+ /* Remove it from the Hash List as well */
+ if (CsrThread->HashLinks.Flink) RemoveEntryList(&CsrThread->HashLinks);
+
+ /* Check if this is the last Thread */
+ if (!CsrThread->Process->ThreadCount)
+ {
+ /* Check if it's not already been marked for deletion */
+ if (!(CsrThread->Process->Flags & CsrProcessLastThreadTerminated))
+ {
+ /* Let everyone know this process is about to lose the thread */
+ CsrThread->Process->Flags |= CsrProcessLastThreadTerminated;
+
+ /* Reference the Process */
+ CsrLockedDereferenceProcess(CsrThread->Process);
+ }
+ }
+
+ /* Mark the thread for deletion */
+ CsrThread->Flags |= CsrThreadInTermination;
+}
+
+/*++
+ * @name CsrCreateRemoteThread
+ * @implemented NT4
+ *
+ * The CsrCreateRemoteThread routine creates a CSR Thread object for
+ * an NT Thread which is not part of the current NT Process.
+ *
+ * @param hThread
+ * Handle to an existing NT Thread to which to associate this
+ * CSR Thread.
+ *
+ * @param ClientId
+ * Pointer to the Client ID structure of the NT Thread to associate
+ * with this CSR Thread.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrCreateRemoteThread(IN HANDLE hThread,
+ IN PCLIENT_ID ClientId)
+{
+ NTSTATUS Status;
+ HANDLE ThreadHandle;
+ PCSR_THREAD CsrThread;
+ PCSR_PROCESS CsrProcess;
+ KERNEL_USER_TIMES KernelTimes;
+ DPRINT("CSRSRV: %s called\n", __FUNCTION__);
+
+ /* Get the Thread Create Time */
+ Status = NtQueryInformationThread(hThread,
+ ThreadTimes,
+ &KernelTimes,
+ sizeof(KernelTimes),
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to query thread times: %lx\n", Status);
+ return Status;
+ }
+
+ /* Lock the Owner Process */
+ Status = CsrLockProcessByClientId(&ClientId->UniqueProcess, &CsrProcess);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("No known process for %lx\n", ClientId->UniqueProcess);
+ return Status;
+ }
+
+ /* Make sure the thread didn't terminate */
+ if (KernelTimes.ExitTime.QuadPart)
+ {
+ /* Unlock the process and return */
+ CsrUnlockProcess(CsrProcess);
+ DPRINT1("Dead thread: %I64x\n", KernelTimes.ExitTime.QuadPart);
+ return STATUS_THREAD_IS_TERMINATING;
+ }
+
+ /* Allocate a CSR Thread Structure */
+ CsrThread = CsrAllocateThread(CsrProcess);
+ if (!CsrThread)
+ {
+ DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
+ CsrUnlockProcess(CsrProcess);
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Duplicate the Thread Handle */
+ Status = NtDuplicateObject(NtCurrentProcess(),
+ hThread,
+ NtCurrentProcess(),
+ &ThreadHandle,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS);
+ /* Allow failure */
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Thread duplication failed: %lx\n", Status);
+ ThreadHandle = hThread;
+ }
+
+ /* Save the data we have */
+ CsrThread->CreateTime = KernelTimes.CreateTime;
+ CsrThread->ClientId = *ClientId;
+ CsrThread->ThreadHandle = ThreadHandle;
+ ProtectHandle(ThreadHandle);
+ CsrThread->Flags = 0;
+
+ /* Insert the Thread into the Process */
+ CsrInsertThread(CsrProcess, CsrThread);
+
+ /* Release the lock and return */
+ CsrUnlockProcess(CsrProcess);
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrThreadRefcountZero
+ *
+ * The CsrThreadRefcountZero routine is executed when a CSR Thread has lost
+ * all its active references. It removes and de-allocates the CSR Thread.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread that is to be deleted.
+ *
+ * @return None.
+ *
+ * @remarks Do not call this routine. It is reserved for the internal
+ * thread management routines when a CSR Thread has lost all
+ * its references.
+ *
+ * This routine is called with the Process Lock held.
+ *
+ *--*/
+VOID
+NTAPI
+CsrThreadRefcountZero(IN PCSR_THREAD CsrThread)
+{
+ PCSR_PROCESS CsrProcess = CsrThread->Process;
+ NTSTATUS Status;
+ ASSERT(ProcessStructureListLocked());
+
+ /* Remove this thread */
+ CsrRemoveThread(CsrThread);
+
+ /* Release the Process Lock */
+ CsrReleaseProcessLock();
+
+ /* Close the NT Thread Handle */
+ if (CsrThread->ThreadHandle)
+ {
+ UnProtectHandle(CsrThread->ThreadHandle);
+ Status = NtClose(CsrThread->ThreadHandle);
+ ASSERT(NT_SUCCESS(Status));
+ }
+
+ /* De-allocate the CSR Thread Object */
+ CsrDeallocateThread(CsrThread);
+
+ /* Remove a reference from the process */
+ CsrDereferenceProcess(CsrProcess);
+}
+
+/*++
+ * @name CsrDestroyThread
+ * @implemented NT4
+ *
+ * The CsrDestroyThread routine destroys the CSR Thread corresponding to
+ * a given Thread ID.
+ *
+ * @param Cid
+ * Pointer to the Client ID Structure corresponding to the CSR
+ * Thread which is about to be destroyed.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING
+ * if the CSR Thread is already terminating.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrDestroyThread(IN PCLIENT_ID Cid)
+{
+ CLIENT_ID ClientId = *Cid;
+ PCSR_THREAD CsrThread;
+ PCSR_PROCESS CsrProcess;
+
+ /* Acquire lock */
+ CsrAcquireProcessLock();
+
+ /* Find the thread */
+ CsrThread = CsrLocateThreadByClientId(&CsrProcess,
+ &ClientId);
+
+ /* Make sure we got one back, and that it's not already gone */
+ if (!CsrThread || CsrThread->Flags & CsrThreadTerminated)
+ {
+ /* Release the lock and return failure */
+ CsrReleaseProcessLock();
+ return STATUS_THREAD_IS_TERMINATING;
+ }
+
+ /* Set the terminated flag */
+ CsrThread->Flags |= CsrThreadTerminated;
+
+ /* Acquire the Wait Lock */
+ CsrAcquireWaitLock();
+
+ /* Do we have an active wait block? */
+ if (CsrThread->WaitBlock)
+ {
+ /* Notify waiters of termination */
+ CsrNotifyWaitBlock(CsrThread->WaitBlock,
+ NULL,
+ NULL,
+ NULL,
+ CsrProcessTerminating,
+ TRUE);
+ }
+
+ /* Release the Wait Lock */
+ CsrReleaseWaitLock();
+
+ /* Dereference the thread */
+ CsrLockedDereferenceThread(CsrThread);
+
+ /* Release the Process Lock and return success */
+ CsrReleaseProcessLock();
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrLockedDereferenceThread
+ *
+ * The CsrLockedDereferenceThread dereferences a CSR Thread while the
+ * Process Lock is already being held.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread to be dereferenced.
+ *
+ * @return None.
+ *
+ * @remarks This routine will return with the Process Lock held.
+ *
+ *--*/
+VOID
+NTAPI
+CsrLockedDereferenceThread(IN PCSR_THREAD CsrThread)
+{
+ LONG LockCount;
+
+ /* Decrease reference count */
+ LockCount = --CsrThread->ReferenceCount;
+ ASSERT(LockCount >= 0);
+ if (!LockCount)
+ {
+ /* Call the generic cleanup code */
+ CsrThreadRefcountZero(CsrThread);
+ CsrAcquireProcessLock();
+ }
+}
+
+/*++
+ * @name CsrCreateThread
+ * @implemented NT4
+ *
+ * The CsrCreateThread routine creates a CSR Thread object for an NT Thread.
+ *
+ * @param CsrProcess
+ * Pointer to the CSR Process which will contain the CSR Thread.
+ *
+ * @param hThread
+ * Handle to an existing NT Thread to which to associate this
+ * CSR Thread.
+ *
+ * @param ClientId
+ * Pointer to the Client ID structure of the NT Thread to associate
+ * with this CSR Thread.
+ *
+ * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
+ * otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+CsrCreateThread(IN PCSR_PROCESS CsrProcess,
+ IN HANDLE hThread,
+ IN PCLIENT_ID ClientId)
+{
+ PCSR_THREAD CsrThread;
+ PCSR_PROCESS CurrentProcess;
+ PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
+ CLIENT_ID CurrentCid;
+ KERNEL_USER_TIMES KernelTimes;
+
+ /* Get the current thread and CID */
+ CurrentCid = CurrentThread->ClientId;
+
+ /* Acquire the Process Lock */
+ CsrAcquireProcessLock();
+
+ /* Get the current Process and make sure the Thread is valid with this CID */
+ CurrentThread = CsrLocateThreadByClientId(&CurrentProcess,
+ &CurrentCid);
+
+ /* Something is wrong if we get an empty thread back */
+ if (!CurrentThread)
+ {
+ DPRINT1("CSRSRV:%s: invalid thread!\n", __FUNCTION__);
+ CsrReleaseProcessLock();
+ return STATUS_THREAD_IS_TERMINATING;
+ }
+
+ /* Get the Thread Create Time */
+ NtQueryInformationThread(hThread,
+ ThreadTimes,
+ (PVOID)&KernelTimes,
+ sizeof(KernelTimes),
+ NULL);
+
+ /* Allocate a CSR Thread Structure */
+ if (!(CsrThread = CsrAllocateThread(CsrProcess)))
+ {
+ DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
+ CsrReleaseProcessLock();
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Save the data we have */
+ CsrThread->CreateTime = KernelTimes.CreateTime;
+ CsrThread->ClientId = *ClientId;
+ CsrThread->ThreadHandle = hThread;
+ CsrThread->Flags = 0;
+
+ /* Insert the Thread into the Process */
+ CsrInsertThread(CsrProcess, CsrThread);
+
+ /* Release the lock and return */
+ CsrReleaseProcessLock();
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name CsrAddStaticServerThread
+ * @implemented NT4
+ *
+ * The CsrAddStaticServerThread routine adds a new CSR Thread to the
+ * CSR Server Process (CsrRootProcess).
+ *
+ * @param hThread
+ * Handle to an existing NT Thread to which to associate this
+ * CSR Thread.
+ *
+ * @param ClientId
+ * Pointer to the Client ID structure of the NT Thread to associate
+ * with this CSR Thread.
+ *
+ * @param ThreadFlags
+ * Initial CSR Thread Flags to associate to this CSR Thread. Usually
+ * CsrThreadIsServerThread.
+ *
+ * @return Pointer to the newly allocated CSR Thread.
+ *
+ * @remarks None.
+ *
+ *--*/
+PCSR_THREAD
+NTAPI
+CsrAddStaticServerThread(IN HANDLE hThread,
+ IN PCLIENT_ID ClientId,
+ IN ULONG ThreadFlags)
+{
+ PCSR_THREAD CsrThread;
+
+ /* Get the Lock */
+ CsrAcquireProcessLock();
+
+ /* Allocate the Server Thread */
+ CsrThread = CsrAllocateThread(CsrRootProcess);
+ if (CsrThread)
+ {
+ /* Setup the Object */
+ CsrThread->ThreadHandle = hThread;
+ ProtectHandle(hThread);
+ CsrThread->ClientId = *ClientId;
+ CsrThread->Flags = ThreadFlags;
+
+ /* Insert it into the Thread List */
+ InsertTailList(&CsrRootProcess->ThreadList, &CsrThread->Link);
+
+ /* Increment the thread count */
+ CsrRootProcess->ThreadCount++;
+ }
+ else
+ {
+ DPRINT1("CsrAddStaticServerThread: alloc failed for thread 0x%x\n", hThread);
+ }
+
+ /* Release the Process Lock and return */
+ CsrReleaseProcessLock();
+ return CsrThread;
+}
+
+/*++
+ * @name CsrDereferenceThread
+ * @implemented NT4
+ *
+ * The CsrDereferenceThread routine removes a reference from a CSR Thread.
+ *
+ * @param CsrThread
+ * Pointer to the CSR Thread to dereference.
+ *
+ * @return None.
+ *
+ * @remarks If the reference count has reached zero (ie: the CSR Thread has
+ * no more active references), it will be deleted.
+ *
+ *--*/
+VOID
+NTAPI
+CsrDereferenceThread(IN PCSR_THREAD CsrThread)
+{
+ /* Acquire process lock */
+ CsrAcquireProcessLock();
+
+ /* Decrease reference count */
+ ASSERT(CsrThread->ReferenceCount > 0);
+ if (!(--CsrThread->ReferenceCount))
+ {
+ /* Call the generic cleanup code */
+ CsrThreadRefcountZero(CsrThread);
+ }
+ else
+ {
+ /* Just release the lock */
+ CsrReleaseProcessLock();
+ }
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CSR Sub System
+ * FILE: subsystems/win32/csrss/csrsrv/wait.c
+ * PURPOSE: CSR Server DLL Wait Implementation
+ * PROGRAMMERS: Emanuele Aliberti
+ * Alex Ionescu (alex@relsoft.net)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "srv.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* DATA **********************************************************************/
+
+RTL_CRITICAL_SECTION CsrWaitListsLock;
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+/*++
+ * @name CsrInitializeWait
+ *
+ * The CsrInitializeWait routine initializes a CSR Wait Object.
+ *
+ * @param WaitFunction
+ * Pointer to the function that will handle this wait.
+ *
+ * @param CsrWaitThread
+ * Pointer to the CSR Thread that will perform the wait.
+ *
+ * @param WaitApiMessage
+ * Pointer to the CSR API Message associated to this wait.
+ *
+ * @param WaitContext
+ * Pointer to a user-defined parameter associated to this wait.
+ *
+ * @param NewWaitBlock
+ * Pointed to the initialized CSR Wait Block for this wait.
+ *
+ * @return TRUE in case of success, FALSE otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrInitializeWait(IN CSR_WAIT_FUNCTION WaitFunction,
+ IN PCSR_THREAD CsrWaitThread,
+ IN OUT PCSR_API_MESSAGE WaitApiMessage,
+ IN PVOID WaitContext,
+ OUT PCSR_WAIT_BLOCK *NewWaitBlock)
+{
+ ULONG Size;
+ PCSR_WAIT_BLOCK WaitBlock;
+
+ /* Calculate the size of the wait block */
+ Size = sizeof(CSR_WAIT_BLOCK) -
+ sizeof(WaitBlock->WaitApiMessage) +
+ WaitApiMessage->Header.u1.s1.TotalLength;
+
+ /* Allocate the Wait Block */
+ WaitBlock = RtlAllocateHeap(CsrHeap, 0, Size);
+ if (!WaitBlock)
+ {
+ /* Fail */
+ WaitApiMessage->Status = STATUS_NO_MEMORY;
+ return FALSE;
+ }
+
+ /* Initialize it */
+ WaitBlock->Size = Size;
+ WaitBlock->WaitThread = CsrWaitThread;
+ WaitBlock->WaitContext = WaitContext;
+ WaitBlock->WaitFunction = WaitFunction;
+ WaitBlock->UserWaitList.Flink = NULL;
+ WaitBlock->UserWaitList.Blink = NULL;
+ WaitBlock->WaitList = WaitBlock->UserWaitList;
+
+ /* Copy the message */
+ RtlMoveMemory(&WaitBlock->WaitApiMessage,
+ WaitApiMessage,
+ WaitApiMessage->Header.u1.s1.TotalLength);
+
+ /* Return the block */
+ *NewWaitBlock = WaitBlock;
+ return TRUE;
+}
+
+/*++
+ * @name CsrNotifyWaitBlock
+ *
+ * The CsrNotifyWaitBlock routine calls the wait function for a registered
+ * CSR Wait Block, and replies to the attached CSR API Message, if any.
+ *
+ * @param WaitBlock
+ * Pointer to the CSR Wait Block
+ *
+ * @param WaitList
+ * Pointer to the wait list for this wait.
+ *
+ * @param WaitArgument[1-2]
+ * User-defined values to pass to the wait function.
+ *
+ * @param WaitFlags
+ * Wait flags for this wait.
+ *
+ * @param DereferenceThread
+ * Specifies whether the CSR Thread should be dereferenced at the
+ * end of this wait.
+ *
+ * @return TRUE in case of success, FALSE otherwise.
+ *
+ * @remarks After a wait block is notified, the wait function becomes invalid.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrNotifyWaitBlock(IN PCSR_WAIT_BLOCK WaitBlock,
+ IN PLIST_ENTRY WaitList,
+ IN PVOID WaitArgument1,
+ IN PVOID WaitArgument2,
+ IN ULONG WaitFlags,
+ IN BOOLEAN DereferenceThread)
+{
+ /* Call the wait function */
+ if ((WaitBlock->WaitFunction)(WaitList,
+ WaitBlock->WaitThread,
+ &WaitBlock->WaitApiMessage,
+ WaitBlock->WaitContext,
+ WaitArgument1,
+ WaitArgument2,
+ WaitFlags))
+ {
+ /* The wait is done, clear the block */
+ WaitBlock->WaitThread->WaitBlock = NULL;
+
+ /* Check for captured arguments */
+ if (WaitBlock->WaitApiMessage.CsrCaptureData)
+ {
+ /* Release them */
+ CsrReleaseCapturedArguments(&WaitBlock->WaitApiMessage);
+ }
+
+ /* Reply to the port */
+ NtReplyPort(WaitBlock->WaitThread->Process->ClientPort,
+ (PPORT_MESSAGE)&WaitBlock->WaitApiMessage);
+
+ /* Check if we should dereference the thread */
+ if (DereferenceThread)
+ {
+ /* Remove it from the Wait List */
+ if (WaitBlock->WaitList.Flink)
+ {
+ RemoveEntryList(&WaitBlock->WaitList);
+ }
+
+ /* Remove it from the User Wait List */
+ if (WaitBlock->UserWaitList.Flink)
+ {
+ RemoveEntryList(&WaitBlock->UserWaitList);
+ }
+
+ /* Dereference teh thread */
+ CsrDereferenceThread(WaitBlock->WaitThread);
+
+ /* Free the wait block */
+ RtlFreeHeap(CsrHeap, 0, WaitBlock);
+ }
+ else
+ {
+ /* The wait is complete, but the thread is being kept alive */
+ WaitBlock->WaitFunction = NULL;
+ }
+
+ /* The wait suceeded */
+ return TRUE;
+ }
+
+ /* The wait failed */
+ return FALSE;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*++
+ * @name CsrCreateWait
+ * @implemented NT4
+ *
+ * The CsrCreateWait routine creates a CSR Wait.
+ *
+ * @param WaitList
+ * Pointer to a list entry of the waits to associate.
+ *
+ * @param WaitFunction
+ * Pointer to the function that will handle this wait.
+ *
+ * @param CsrWaitThread
+ * Pointer to the CSR Thread that will perform the wait.
+ *
+ * @param WaitApiMessage
+ * Pointer to the CSR API Message associated to this wait.
+ *
+ * @param WaitContext
+ * Pointer to a user-defined parameter associated to this wait.
+ *
+ * @param UserWaitList
+ * Pointer to a list entry of the user-defined waits to associate.
+ *
+ * @return TRUE in case of success, FALSE otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrCreateWait(IN PLIST_ENTRY WaitList,
+ IN CSR_WAIT_FUNCTION WaitFunction,
+ IN PCSR_THREAD CsrWaitThread,
+ IN OUT PCSR_API_MESSAGE WaitApiMessage,
+ IN PVOID WaitContext,
+ IN PLIST_ENTRY UserWaitList OPTIONAL)
+{
+ PCSR_WAIT_BLOCK WaitBlock;
+
+ /* Initialize the wait */
+ if (!CsrInitializeWait(WaitFunction,
+ CsrWaitThread,
+ WaitApiMessage,
+ WaitContext,
+ &WaitBlock))
+ {
+ return FALSE;
+ }
+
+ /* Acquire the Wait Lock */
+ CsrAcquireWaitLock();
+
+ /* Make sure the thread wasn't destroyed */
+ if (CsrWaitThread->Flags & CsrThreadTerminated)
+ {
+ /* Fail the wait */
+ RtlFreeHeap(CsrHeap, 0, WaitBlock);
+ CsrReleaseWaitLock();
+ return FALSE;
+ }
+
+ /* Insert the wait in the queue */
+ InsertTailList(WaitList, &WaitBlock->WaitList);
+
+ /* Insert the User Wait too, if one was given */
+ if (UserWaitList) InsertTailList(UserWaitList, &WaitBlock->UserWaitList);
+
+ /* Return */
+ CsrReleaseWaitLock();
+ return TRUE;
+}
+
+/*++
+ * @name CsrDereferenceWait
+ * @implemented NT4
+ *
+ * The CsrDereferenceWait routine dereferences a CSR Wait Block.
+ *
+ * @param WaitList
+ * Pointer to the Wait List associated to the wait.
+
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrDereferenceWait(IN PLIST_ENTRY WaitList)
+{
+ PLIST_ENTRY NextEntry;
+ PCSR_WAIT_BLOCK WaitBlock;
+
+ /* Acquire the Process and Wait Locks */
+ CsrAcquireProcessLock();
+ CsrAcquireWaitLock();
+
+ /* Set the list pointers */
+ NextEntry = WaitList->Flink;
+
+ /* Start the loop */
+ while (NextEntry != WaitList)
+ {
+ /* Get the wait block */
+ WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
+
+ /* Move to the next entry */
+ NextEntry = NextEntry->Flink;
+
+ /* Check if there's no Wait Routine */
+ if (!WaitBlock->WaitFunction)
+ {
+ /* Remove it from the Wait List */
+ if (WaitBlock->WaitList.Flink)
+ {
+ RemoveEntryList(&WaitBlock->WaitList);
+ }
+
+ /* Remove it from the User Wait List */
+ if (WaitBlock->UserWaitList.Flink)
+ {
+ RemoveEntryList(&WaitBlock->UserWaitList);
+ }
+
+ /* Dereference the thread waiting on it */
+ CsrDereferenceThread(WaitBlock->WaitThread);
+
+ /* Free the block */
+ RtlFreeHeap(CsrHeap, 0, WaitBlock);
+ }
+ }
+
+ /* Release the locks */
+ CsrReleaseWaitLock();
+ CsrReleaseProcessLock();
+}
+
+/*++
+ * @name CsrMoveSatisfiedWait
+ * @implemented NT5
+ *
+ * The CsrMoveSatisfiedWait routine moves satisfied waits from a wait list
+ * to another list entry.
+ *
+ * @param NewEntry
+ * Pointer to a list entry where the satisfied waits will be added.
+ *
+ * @param WaitList
+ * Pointer to a list entry to analyze for satisfied waits.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrMoveSatisfiedWait(IN PLIST_ENTRY NewEntry,
+ IN PLIST_ENTRY WaitList)
+{
+ PLIST_ENTRY NextEntry;
+ PCSR_WAIT_BLOCK WaitBlock;
+
+ /* Acquire the Wait Lock */
+ CsrAcquireWaitLock();
+
+ /* Set the List pointers */
+ NextEntry = WaitList->Flink;
+
+ /* Start looping */
+ while (NextEntry != WaitList)
+ {
+ /* Get the Wait block */
+ WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
+
+ /* Go to the next entry */
+ NextEntry = NextEntry->Flink;
+
+ /* Check if there is a Wait Callback */
+ if (WaitBlock->WaitFunction)
+ {
+ /* Remove it from the Wait Block Queue */
+ RemoveEntryList(&WaitBlock->WaitList);
+
+ /* Insert the new entry */
+ InsertTailList(&WaitBlock->WaitList, NewEntry);
+ }
+ }
+
+ /* Release the wait lock */
+ CsrReleaseWaitLock();
+}
+
+/*++
+ * @name CsrNotifyWait
+ * @implemented NT4
+ *
+ * The CsrNotifyWait notifies a CSR Wait Block.
+ *
+ * @param WaitList
+ * Pointer to the list entry for this wait.
+ *
+ * @param WaitType
+ * Type of the wait to perform, either WaitAny or WaitAll.
+ *
+ * @param WaitArgument[1-2]
+ * User-defined argument to pass on to the wait function.
+ *
+ * @return TRUE in case of success, FALSE otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrNotifyWait(IN PLIST_ENTRY WaitList,
+ IN ULONG WaitType,
+ IN PVOID WaitArgument1,
+ IN PVOID WaitArgument2)
+{
+ PLIST_ENTRY NextEntry;
+ PCSR_WAIT_BLOCK WaitBlock;
+ BOOLEAN NotifySuccess = FALSE;
+
+ /* Acquire the Wait Lock */
+ CsrAcquireWaitLock();
+
+ /* Set the List pointers */
+ NextEntry = WaitList->Flink;
+
+ /* Start looping */
+ while (NextEntry != WaitList)
+ {
+ /* Get the Wait block */
+ WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
+
+ /* Go to the next entry */
+ NextEntry = NextEntry->Flink;
+
+ /* Check if there is a Wait Callback */
+ if (WaitBlock->WaitFunction)
+ {
+ /* Notify the Waiter */
+ NotifySuccess |= CsrNotifyWaitBlock(WaitBlock,
+ WaitList,
+ WaitArgument1,
+ WaitArgument2,
+ 0,
+ FALSE);
+
+ /* We've already done a wait, so leave unless this is a Wait All */
+ if (WaitType != WaitAll) break;
+ }
+ }
+
+ /* Release the wait lock and return */
+ CsrReleaseWaitLock();
+ return NotifySuccess;
+}
+
+/* EOF */
--- /dev/null
+
+include_directories(
+ BEFORE .
+ ${REACTOS_SOURCE_DIR}/subsystems/win32/csrss/include
+ ${REACTOS_SOURCE_DIR}/include/reactos/subsys
+ ${REACTOS_SOURCE_DIR}/include/reactos/drivers
+ ${REACTOS_SOURCE_DIR}/dll/cpl/console
+ ${REACTOS_SOURCE_DIR}/win32ss/include)
+
+spec2def(win32csr.dll win32csr.spec)
+
+list(APPEND SOURCE
+ alias.c
+ coninput.c
+ conoutput.c
+ console.c
+ desktopbg.c
+ dllmain.c
+ exitros.c
+ file.c
+ guiconsole.c
+ handle.c
+ harderror.c
+ lineinput.c
+ tuiconsole.c
+ win32csr.rc
+ ${CMAKE_CURRENT_BINARY_DIR}/win32csr.def)
+
+add_library(win32csr SHARED ${SOURCE})
+target_link_libraries(win32csr win32ksys ${PSEH_LIB})
+set_module_type(win32csr win32dll)
+add_importlibs(win32csr psapi msvcrt kernel32 ntdll csrsrv)
+add_delay_importlibs(win32csr user32 gdi32 advapi32)
+add_pch(win32csr w32csr.h)
+add_dependencies(win32csr bugcodes)
+add_cd_file(TARGET win32csr DESTINATION reactos/system32 FOR all)
--- /dev/null
+/*
+ * PROJECT: ReactOS CSRSS
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: subsystems/win32/csrss/api/alias.c
+ * PURPOSE: CSRSS alias support functions
+ * COPYRIGHT: Christoph Wittich
+ * Johannes Anderwald
+ *
+ */
+
+
+/* INCLUDES ******************************************************************/
+
+#define NDEBUG
+#include "w32csr.h"
+#include <debug.h>
+
+typedef struct tagALIAS_ENTRY
+{
+ LPCWSTR lpSource;
+ LPCWSTR lpTarget;
+ struct tagALIAS_ENTRY * Next;
+} ALIAS_ENTRY, *PALIAS_ENTRY;
+
+
+typedef struct tagALIAS_HEADER
+{
+ LPCWSTR lpExeName;
+ PALIAS_ENTRY Data;
+ struct tagALIAS_HEADER * Next;
+
+} ALIAS_HEADER, *PALIAS_HEADER;
+
+static
+PALIAS_HEADER
+IntFindAliasHeader(PALIAS_HEADER RootHeader, LPCWSTR lpExeName)
+{
+ while(RootHeader)
+ {
+ INT diff = _wcsicmp(RootHeader->lpExeName, lpExeName);
+ if (!diff)
+ return RootHeader;
+
+ if (diff > 0)
+ break;
+
+ RootHeader = RootHeader->Next;
+ }
+ return NULL;
+}
+
+PALIAS_HEADER
+IntCreateAliasHeader(LPCWSTR lpExeName)
+{
+ PALIAS_HEADER Entry;
+ UINT dwLength = wcslen(lpExeName) + 1;
+
+ Entry = RtlAllocateHeap(Win32CsrApiHeap, 0, sizeof(ALIAS_HEADER) + sizeof(WCHAR) * dwLength);
+ if (!Entry)
+ return Entry;
+
+ Entry->lpExeName = (LPCWSTR)(Entry + 1);
+ wcscpy((WCHAR*)Entry->lpExeName, lpExeName);
+ Entry->Data = NULL;
+ Entry->Next = NULL;
+ return Entry;
+}
+
+VOID
+IntInsertAliasHeader(PALIAS_HEADER * RootHeader, PALIAS_HEADER NewHeader)
+{
+ PALIAS_HEADER CurrentHeader;
+ PALIAS_HEADER *LastLink = RootHeader;
+
+ while ((CurrentHeader = *LastLink) != NULL)
+ {
+ INT Diff = _wcsicmp(NewHeader->lpExeName, CurrentHeader->lpExeName);
+ if (Diff < 0)
+ {
+ break;
+ }
+ LastLink = &CurrentHeader->Next;
+ }
+
+ *LastLink = NewHeader;
+ NewHeader->Next = CurrentHeader;
+}
+
+PALIAS_ENTRY
+IntGetAliasEntry(PALIAS_HEADER Header, LPCWSTR lpSrcName)
+{
+ PALIAS_ENTRY RootHeader;
+
+ if (Header == NULL)
+ return NULL;
+
+ RootHeader = Header->Data;
+ while(RootHeader)
+ {
+ INT diff;
+ DPRINT("IntGetAliasEntry>lpSource %S\n", RootHeader->lpSource);
+ diff = _wcsicmp(RootHeader->lpSource, lpSrcName);
+ if (!diff)
+ return RootHeader;
+
+ if (diff > 0)
+ break;
+
+ RootHeader = RootHeader->Next;
+ }
+ return NULL;
+}
+
+
+VOID
+IntInsertAliasEntry(PALIAS_HEADER Header, PALIAS_ENTRY NewEntry)
+{
+ PALIAS_ENTRY CurrentEntry;
+ PALIAS_ENTRY *LastLink = &Header->Data;
+
+ while ((CurrentEntry = *LastLink) != NULL)
+ {
+ INT Diff = _wcsicmp(NewEntry->lpSource, CurrentEntry->lpSource);
+ if (Diff < 0)
+ {
+ break;
+ }
+ LastLink = &CurrentEntry->Next;
+ }
+
+ *LastLink = NewEntry;
+ NewEntry->Next = CurrentEntry;
+}
+
+PALIAS_ENTRY
+IntCreateAliasEntry(LPCWSTR lpSource, LPCWSTR lpTarget)
+{
+ UINT dwSource;
+ UINT dwTarget;
+ PALIAS_ENTRY Entry;
+
+ dwSource = wcslen(lpSource) + 1;
+ dwTarget = wcslen(lpTarget) + 1;
+
+ Entry = RtlAllocateHeap(Win32CsrApiHeap, 0, sizeof(ALIAS_ENTRY) + sizeof(WCHAR) * (dwSource + dwTarget));
+ if (!Entry)
+ return Entry;
+
+ Entry->lpSource = (LPCWSTR)(Entry + 1);
+ wcscpy((LPWSTR)Entry->lpSource, lpSource);
+ Entry->lpTarget = Entry->lpSource + dwSource;
+ wcscpy((LPWSTR)Entry->lpTarget, lpTarget);
+ Entry->Next = NULL;
+
+ return Entry;
+}
+
+UINT
+IntGetConsoleAliasesExesLength(PALIAS_HEADER RootHeader)
+{
+ UINT length = 0;
+
+ while(RootHeader)
+ {
+ length += (wcslen(RootHeader->lpExeName) + 1) * sizeof(WCHAR);
+ RootHeader = RootHeader->Next;
+ }
+ if (length)
+ length += sizeof(WCHAR); // last entry entry is terminated with 2 zero bytes
+
+ return length;
+}
+
+UINT
+IntGetConsoleAliasesExes(PALIAS_HEADER RootHeader, LPWSTR TargetBuffer, UINT TargetBufferSize)
+{
+ UINT Offset = 0;
+ UINT Length;
+
+ TargetBufferSize /= sizeof(WCHAR);
+ while(RootHeader)
+ {
+ Length = wcslen(RootHeader->lpExeName) + 1;
+ if (TargetBufferSize > Offset + Length)
+ {
+ wcscpy(&TargetBuffer[Offset], RootHeader->lpExeName);
+ Offset += Length;
+ }
+ else
+ {
+ break;
+ }
+ RootHeader = RootHeader->Next;
+ }
+ Length = min(Offset+1, TargetBufferSize);
+ TargetBuffer[Length] = L'\0';
+ return Length * sizeof(WCHAR);
+}
+
+UINT
+IntGetAllConsoleAliasesLength(PALIAS_HEADER Header)
+{
+ UINT Length = 0;
+ PALIAS_ENTRY CurEntry = Header->Data;
+
+ while(CurEntry)
+ {
+ Length += wcslen(CurEntry->lpSource);
+ Length += wcslen(CurEntry->lpTarget);
+ Length += 2; // zero byte and '='
+ CurEntry = CurEntry->Next;
+ }
+
+ if (Length)
+ {
+ return (Length+1) * sizeof(WCHAR);
+ }
+ return 0;
+}
+UINT
+IntGetAllConsoleAliases(PALIAS_HEADER Header, LPWSTR TargetBuffer, UINT TargetBufferLength)
+{
+ PALIAS_ENTRY CurEntry = Header->Data;
+ UINT Offset = 0;
+ UINT SrcLength, TargetLength;
+
+ TargetBufferLength /= sizeof(WCHAR);
+ while(CurEntry)
+ {
+ SrcLength = wcslen(CurEntry->lpSource) + 1;
+ TargetLength = wcslen(CurEntry->lpTarget) + 1;
+ if (Offset + TargetLength + SrcLength >= TargetBufferLength)
+ break;
+
+ wcscpy(&TargetBuffer[Offset], CurEntry->lpSource);
+ Offset += SrcLength;
+ TargetBuffer[Offset] = L'=';
+ wcscpy(&TargetBuffer[Offset], CurEntry->lpTarget);
+ Offset += TargetLength;
+
+ CurEntry = CurEntry->Next;
+ }
+ TargetBuffer[Offset] = L'\0';
+ return Offset * sizeof(WCHAR);
+}
+VOID
+IntDeleteAliasEntry(PALIAS_HEADER Header, PALIAS_ENTRY Entry)
+{
+ PALIAS_ENTRY *LastLink = &Header->Data;
+ PALIAS_ENTRY CurEntry;
+
+ while ((CurEntry = *LastLink) != NULL)
+ {
+ if (CurEntry == Entry)
+ {
+ *LastLink = Entry->Next;
+ RtlFreeHeap(Win32CsrApiHeap, 0, Entry);
+ return;
+ }
+ LastLink = &CurEntry->Next;
+ }
+}
+VOID
+IntDeleteAllAliases(PALIAS_HEADER RootHeader)
+{
+ PALIAS_HEADER Header, NextHeader;
+ PALIAS_ENTRY Entry, NextEntry;
+ for (Header = RootHeader; Header; Header = NextHeader)
+ {
+ NextHeader = Header->Next;
+ for (Entry = Header->Data; Entry; Entry = NextEntry)
+ {
+ NextEntry = Entry->Next;
+ RtlFreeHeap(Win32CsrApiHeap, 0, Entry);
+ }
+ RtlFreeHeap(Win32CsrApiHeap, 0, Header);
+ }
+}
+
+CSR_API(CsrAddConsoleAlias)
+{
+ PCSRSS_CONSOLE Console;
+ PALIAS_HEADER Header;
+ PALIAS_ENTRY Entry;
+ WCHAR * lpExeName;
+ WCHAR * lpSource;
+ WCHAR * lpTarget;
+ //ULONG TotalLength;
+ //WCHAR * Ptr;
+
+ //TotalLength = Request->Data.AddConsoleAlias.SourceLength + Request->Data.AddConsoleAlias.ExeLength + Request->Data.AddConsoleAlias.TargetLength;
+ //Ptr = (WCHAR*)((ULONG_PTR)Request + sizeof(CSR_API_MESSAGE));
+
+ lpSource = (WCHAR*)((ULONG_PTR)Request + sizeof(CSR_API_MESSAGE));
+ lpExeName = (WCHAR*)((ULONG_PTR)Request + sizeof(CSR_API_MESSAGE) + Request->Data.AddConsoleAlias.SourceLength * sizeof(WCHAR));
+ lpTarget = (Request->Data.AddConsoleAlias.TargetLength != 0 ? lpExeName + Request->Data.AddConsoleAlias.ExeLength : NULL);
+
+ DPRINT("CsrAddConsoleAlias entered Request %p lpSource %p lpExeName %p lpTarget %p\n", Request, lpSource, lpExeName, lpTarget);
+
+ if (lpExeName == NULL || lpSource == NULL)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Request->Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (!NT_SUCCESS(Request->Status))
+ {
+ return Request->Status;
+ }
+
+ Header = IntFindAliasHeader(Console->Aliases, lpExeName);
+ if (!Header && lpTarget != NULL)
+ {
+ Header = IntCreateAliasHeader(lpExeName);
+ if (!Header)
+ {
+ ConioUnlockConsole(Console);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ IntInsertAliasHeader(&Console->Aliases, Header);
+ }
+
+ if (lpTarget == NULL) // delete the entry
+ {
+ Entry = IntGetAliasEntry(Header, lpSource);
+ if (Entry)
+ {
+ IntDeleteAliasEntry(Header, Entry);
+ Request->Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ Request->Status = STATUS_INVALID_PARAMETER;
+ }
+ ConioUnlockConsole(Console);
+ return Request->Status;
+ }
+
+ Entry = IntCreateAliasEntry(lpSource, lpTarget);
+
+ if (!Entry)
+ {
+ ConioUnlockConsole(Console);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IntInsertAliasEntry(Header, Entry);
+ ConioUnlockConsole(Console);
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrGetConsoleAlias)
+{
+ PCSRSS_CONSOLE Console;
+ PALIAS_HEADER Header;
+ PALIAS_ENTRY Entry;
+ UINT Length;
+ WCHAR * lpExeName;
+ WCHAR * lpSource;
+ WCHAR * lpTarget;
+
+ lpSource = (LPWSTR)((ULONG_PTR)Request + sizeof(CSR_API_MESSAGE));
+ lpExeName = lpSource + Request->Data.GetConsoleAlias.SourceLength;
+ lpTarget = Request->Data.GetConsoleAlias.TargetBuffer;
+
+
+ DPRINT("CsrGetConsoleAlias entered lpExeName %p lpSource %p TargetBuffer %p TargetBufferLength %u\n",
+ lpExeName, lpSource, lpTarget, Request->Data.GetConsoleAlias.TargetBufferLength);
+
+ if (Request->Data.GetConsoleAlias.ExeLength == 0 || lpTarget == NULL ||
+ Request->Data.GetConsoleAlias.TargetBufferLength == 0 || Request->Data.GetConsoleAlias.SourceLength == 0)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Request->Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (!NT_SUCCESS(Request->Status))
+ {
+ return Request->Status;
+ }
+
+ Header = IntFindAliasHeader(Console->Aliases, lpExeName);
+ if (!Header)
+ {
+ ConioUnlockConsole(Console);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Entry = IntGetAliasEntry(Header, lpSource);
+ if (!Entry)
+ {
+ ConioUnlockConsole(Console);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Length = (wcslen(Entry->lpTarget)+1) * sizeof(WCHAR);
+ if (Length > Request->Data.GetConsoleAlias.TargetBufferLength)
+ {
+ ConioUnlockConsole(Console);
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (!Win32CsrValidateBuffer(ProcessData, lpTarget,
+ Request->Data.GetConsoleAlias.TargetBufferLength, 1))
+ {
+ ConioUnlockConsole(Console);
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ wcscpy(lpTarget, Entry->lpTarget);
+ Request->Data.GetConsoleAlias.BytesWritten = Length;
+ ConioUnlockConsole(Console);
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrGetAllConsoleAliases)
+{
+ PCSRSS_CONSOLE Console;
+ ULONG BytesWritten;
+ PALIAS_HEADER Header;
+
+ if (Request->Data.GetAllConsoleAlias.lpExeName == NULL)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Request->Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (!NT_SUCCESS(Request->Status))
+ {
+ return Request->Status;
+ }
+
+ Header = IntFindAliasHeader(Console->Aliases, Request->Data.GetAllConsoleAlias.lpExeName);
+ if (!Header)
+ {
+ ConioUnlockConsole(Console);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (IntGetAllConsoleAliasesLength(Header) > Request->Data.GetAllConsoleAlias.AliasBufferLength)
+ {
+ ConioUnlockConsole(Console);
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ if (!Win32CsrValidateBuffer(ProcessData,
+ Request->Data.GetAllConsoleAlias.AliasBuffer,
+ Request->Data.GetAllConsoleAlias.AliasBufferLength,
+ 1))
+ {
+ ConioUnlockConsole(Console);
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ BytesWritten = IntGetAllConsoleAliases(Header,
+ Request->Data.GetAllConsoleAlias.AliasBuffer,
+ Request->Data.GetAllConsoleAlias.AliasBufferLength);
+
+ Request->Data.GetAllConsoleAlias.BytesWritten = BytesWritten;
+ ConioUnlockConsole(Console);
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrGetAllConsoleAliasesLength)
+{
+ PCSRSS_CONSOLE Console;
+ PALIAS_HEADER Header;
+ UINT Length;
+
+ if (Request->Data.GetAllConsoleAliasesLength.lpExeName == NULL)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Request->Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (!NT_SUCCESS(Request->Status))
+ {
+ return Request->Status;
+ }
+
+ Header = IntFindAliasHeader(Console->Aliases, Request->Data.GetAllConsoleAliasesLength.lpExeName);
+ if (!Header)
+ {
+ ConioUnlockConsole(Console);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Length = IntGetAllConsoleAliasesLength(Header);
+ Request->Data.GetAllConsoleAliasesLength.Length = Length;
+ ConioUnlockConsole(Console);
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrGetConsoleAliasesExes)
+{
+ PCSRSS_CONSOLE Console;
+ UINT BytesWritten;
+ UINT ExesLength;
+
+ DPRINT("CsrGetConsoleAliasesExes entered\n");
+
+ Request->Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (!NT_SUCCESS(Request->Status))
+ {
+ return Request->Status;
+ }
+
+ ExesLength = IntGetConsoleAliasesExesLength(Console->Aliases);
+
+ if (ExesLength > Request->Data.GetConsoleAliasesExes.Length)
+ {
+ ConioUnlockConsole(Console);
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ if (Request->Data.GetConsoleAliasesExes.ExeNames == NULL)
+ {
+ ConioUnlockConsole(Console);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (!Win32CsrValidateBuffer(ProcessData,
+ Request->Data.GetConsoleAliasesExes.ExeNames,
+ Request->Data.GetConsoleAliasesExes.Length,
+ 1))
+ {
+ ConioUnlockConsole(Console);
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ BytesWritten = IntGetConsoleAliasesExes(Console->Aliases,
+ Request->Data.GetConsoleAliasesExes.ExeNames,
+ Request->Data.GetConsoleAliasesExes.Length);
+
+ Request->Data.GetConsoleAliasesExes.BytesWritten = BytesWritten;
+ ConioUnlockConsole(Console);
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrGetConsoleAliasesExesLength)
+{
+ PCSRSS_CONSOLE Console;
+ DPRINT("CsrGetConsoleAliasesExesLength entered\n");
+
+ Request->Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (NT_SUCCESS(Request->Status))
+ {
+ Request->Data.GetConsoleAliasesExesLength.Length = IntGetConsoleAliasesExesLength(Console->Aliases);
+ ConioUnlockConsole(Console);
+ }
+ return Request->Status;
+}
--- /dev/null
+/*
+ * reactos/subsys/csrss/win32csr/conio.c
+ *
+ * Console I/O functions
+ *
+ * ReactOS Operating System
+ */
+
+/* INCLUDES ******************************************************************/
+
+#define NDEBUG
+#include "w32csr.h"
+#include <debug.h>
+
+/* GLOBALS *******************************************************************/
+
+#define ConsoleInputUnicodeCharToAnsiChar(Console, dChar, sWChar) \
+ WideCharToMultiByte((Console)->CodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
+
+#define ConsoleInputAnsiCharToUnicodeChar(Console, dWChar, sChar) \
+ MultiByteToWideChar((Console)->CodePage, 0, (sChar), 1, (dWChar), 1)
+
+/* FUNCTIONS *****************************************************************/
+
+CSR_API(CsrReadConsole)
+{
+ PLIST_ENTRY CurrentEntry;
+ ConsoleInput *Input;
+ PCHAR Buffer;
+ PWCHAR UnicodeBuffer;
+ ULONG i = 0;
+ ULONG nNumberOfCharsToRead, CharSize;
+ PCSRSS_CONSOLE Console;
+ NTSTATUS Status;
+
+ DPRINT("CsrReadConsole\n");
+
+ CharSize = (Request->Data.ReadConsoleRequest.Unicode ? sizeof(WCHAR) : sizeof(CHAR));
+
+ nNumberOfCharsToRead = Request->Data.ReadConsoleRequest.NrCharactersToRead;
+
+ Buffer = (PCHAR)Request->Data.ReadConsoleRequest.Buffer;
+ UnicodeBuffer = (PWCHAR)Buffer;
+ if (!Win32CsrValidateBuffer(ProcessData, Buffer, nNumberOfCharsToRead, CharSize))
+ return STATUS_ACCESS_VIOLATION;
+
+ if (Request->Data.ReadConsoleRequest.NrCharactersRead * sizeof(WCHAR) > nNumberOfCharsToRead * CharSize)
+ return STATUS_INVALID_PARAMETER;
+
+ Status = ConioLockConsole(ProcessData, Request->Data.ReadConsoleRequest.ConsoleHandle,
+ &Console, GENERIC_READ);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Request->Data.ReadConsoleRequest.EventHandle = ProcessData->ConsoleEvent;
+
+ Status = STATUS_PENDING; /* we haven't read anything (yet) */
+ if (Console->Mode & ENABLE_LINE_INPUT)
+ {
+ if (Console->LineBuffer == NULL)
+ {
+ /* Starting a new line */
+ Console->LineMaxSize = max(256, nNumberOfCharsToRead);
+ Console->LineBuffer = HeapAlloc(Win32CsrApiHeap, 0, Console->LineMaxSize * sizeof(WCHAR));
+ if (Console->LineBuffer == NULL)
+ {
+ Status = STATUS_NO_MEMORY;
+ goto done;
+ }
+ Console->LineComplete = FALSE;
+ Console->LineUpPressed = FALSE;
+ Console->LineInsertToggle = 0;
+ Console->LineWakeupMask = Request->Data.ReadConsoleRequest.CtrlWakeupMask;
+ Console->LineSize = Request->Data.ReadConsoleRequest.NrCharactersRead;
+ Console->LinePos = Console->LineSize;
+ /* pre-filling the buffer is only allowed in the Unicode API,
+ * so we don't need to worry about conversion */
+ memcpy(Console->LineBuffer, Buffer, Console->LineSize * sizeof(WCHAR));
+ if (Console->LineSize == Console->LineMaxSize)
+ {
+ Console->LineComplete = TRUE;
+ Console->LinePos = 0;
+ }
+ }
+
+ /* If we don't have a complete line yet, process the pending input */
+ while (!Console->LineComplete && !IsListEmpty(&Console->InputEvents))
+ {
+ /* remove input event from queue */
+ CurrentEntry = RemoveHeadList(&Console->InputEvents);
+ if (IsListEmpty(&Console->InputEvents))
+ {
+ ResetEvent(Console->ActiveEvent);
+ }
+ Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
+
+ /* only pay attention to key down */
+ if (KEY_EVENT == Input->InputEvent.EventType
+ && Input->InputEvent.Event.KeyEvent.bKeyDown)
+ {
+ LineInputKeyDown(Console, &Input->InputEvent.Event.KeyEvent);
+ Request->Data.ReadConsoleRequest.ControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState;
+ }
+ HeapFree(Win32CsrApiHeap, 0, Input);
+ }
+
+ /* Check if we have a complete line to read from */
+ if (Console->LineComplete)
+ {
+ while (i < nNumberOfCharsToRead && Console->LinePos != Console->LineSize)
+ {
+ WCHAR Char = Console->LineBuffer[Console->LinePos++];
+ if (Request->Data.ReadConsoleRequest.Unicode)
+ UnicodeBuffer[i++] = Char;
+ else
+ ConsoleInputUnicodeCharToAnsiChar(Console, &Buffer[i++], &Char);
+ }
+ if (Console->LinePos == Console->LineSize)
+ {
+ /* Entire line has been read */
+ HeapFree(Win32CsrApiHeap, 0, Console->LineBuffer);
+ Console->LineBuffer = NULL;
+ }
+ Status = STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ /* Character input */
+ while (i < nNumberOfCharsToRead && !IsListEmpty(&Console->InputEvents))
+ {
+ /* remove input event from queue */
+ CurrentEntry = RemoveHeadList(&Console->InputEvents);
+ if (IsListEmpty(&Console->InputEvents))
+ {
+ ResetEvent(Console->ActiveEvent);
+ }
+ Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
+
+ /* only pay attention to valid ascii chars, on key down */
+ if (KEY_EVENT == Input->InputEvent.EventType
+ && Input->InputEvent.Event.KeyEvent.bKeyDown
+ && Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar != L'\0')
+ {
+ WCHAR Char = Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar;
+ if (Request->Data.ReadConsoleRequest.Unicode)
+ UnicodeBuffer[i++] = Char;
+ else
+ ConsoleInputUnicodeCharToAnsiChar(Console, &Buffer[i++], &Char);
+ Status = STATUS_SUCCESS; /* did read something */
+ }
+ HeapFree(Win32CsrApiHeap, 0, Input);
+ }
+ }
+done:
+ Request->Data.ReadConsoleRequest.NrCharactersRead = i;
+ ConioUnlockConsole(Console);
+
+ return Status;
+}
+
+static VOID FASTCALL
+ConioInputEventToAnsi(PCSRSS_CONSOLE Console, PINPUT_RECORD InputEvent)
+{
+ if (InputEvent->EventType == KEY_EVENT)
+ {
+ WCHAR UnicodeChar = InputEvent->Event.KeyEvent.uChar.UnicodeChar;
+ InputEvent->Event.KeyEvent.uChar.UnicodeChar = 0;
+ ConsoleInputUnicodeCharToAnsiChar(Console,
+ &InputEvent->Event.KeyEvent.uChar.AsciiChar,
+ &UnicodeChar);
+ }
+}
+
+static NTSTATUS FASTCALL
+ConioProcessChar(PCSRSS_CONSOLE Console,
+ PINPUT_RECORD InputEvent)
+{
+ ConsoleInput *ConInRec;
+
+ /* Check for pause or unpause */
+ if (InputEvent->EventType == KEY_EVENT && InputEvent->Event.KeyEvent.bKeyDown)
+ {
+ WORD vk = InputEvent->Event.KeyEvent.wVirtualKeyCode;
+ if (!(Console->PauseFlags & PAUSED_FROM_KEYBOARD))
+ {
+ DWORD cks = InputEvent->Event.KeyEvent.dwControlKeyState;
+ if (Console->Mode & ENABLE_LINE_INPUT &&
+ (vk == VK_PAUSE || (vk == 'S' &&
+ (cks & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) &&
+ !(cks & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)))))
+ {
+ ConioPause(Console, PAUSED_FROM_KEYBOARD);
+ return STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ if ((vk < VK_SHIFT || vk > VK_CAPITAL) && vk != VK_LWIN &&
+ vk != VK_RWIN && vk != VK_NUMLOCK && vk != VK_SCROLL)
+ {
+ ConioUnpause(Console, PAUSED_FROM_KEYBOARD);
+ return STATUS_SUCCESS;
+ }
+ }
+ }
+
+ /* add event to the queue */
+ ConInRec = RtlAllocateHeap(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
+ if (ConInRec == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+ ConInRec->InputEvent = *InputEvent;
+ InsertTailList(&Console->InputEvents, &ConInRec->ListEntry);
+ SetEvent(Console->ActiveEvent);
+ return STATUS_SUCCESS;
+}
+
+static DWORD FASTCALL
+ConioGetShiftState(PBYTE KeyState)
+{
+ DWORD ssOut = 0;
+
+ if (KeyState[VK_CAPITAL] & 1)
+ ssOut |= CAPSLOCK_ON;
+
+ if (KeyState[VK_NUMLOCK] & 1)
+ ssOut |= NUMLOCK_ON;
+
+ if (KeyState[VK_SCROLL] & 1)
+ ssOut |= SCROLLLOCK_ON;
+
+ if (KeyState[VK_SHIFT] & 0x80)
+ ssOut |= SHIFT_PRESSED;
+
+ if (KeyState[VK_LCONTROL] & 0x80)
+ ssOut |= LEFT_CTRL_PRESSED;
+ if (KeyState[VK_RCONTROL] & 0x80)
+ ssOut |= RIGHT_CTRL_PRESSED;
+
+ if (KeyState[VK_LMENU] & 0x80)
+ ssOut |= LEFT_ALT_PRESSED;
+ if (KeyState[VK_RMENU] & 0x80)
+ ssOut |= RIGHT_ALT_PRESSED;
+
+ return ssOut;
+}
+
+VOID WINAPI
+ConioProcessKey(MSG *msg, PCSRSS_CONSOLE Console, BOOL TextMode)
+{
+ static BYTE KeyState[256] = { 0 };
+ /* MSDN mentions that you should use the last virtual key code received
+ * when putting a virtual key identity to a WM_CHAR message since multiple
+ * or translated keys may be involved. */
+ static UINT LastVirtualKey = 0;
+ DWORD ShiftState;
+ UINT RepeatCount;
+ WCHAR UnicodeChar;
+ UINT VirtualKeyCode;
+ UINT VirtualScanCode;
+ BOOL Down = FALSE;
+ INPUT_RECORD er;
+ BOOLEAN Fake; // synthesized, not a real event
+ BOOLEAN NotChar; // message should not be used to return a character
+
+ RepeatCount = 1;
+ VirtualScanCode = (msg->lParam >> 16) & 0xff;
+ Down = msg->message == WM_KEYDOWN || msg->message == WM_CHAR ||
+ msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSCHAR;
+
+ GetKeyboardState(KeyState);
+ ShiftState = ConioGetShiftState(KeyState);
+
+ if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR)
+ {
+ VirtualKeyCode = LastVirtualKey;
+ UnicodeChar = msg->wParam;
+ }
+ else
+ {
+ WCHAR Chars[2];
+ INT RetChars = 0;
+
+ VirtualKeyCode = msg->wParam;
+ RetChars = ToUnicodeEx(VirtualKeyCode,
+ VirtualScanCode,
+ KeyState,
+ Chars,
+ 2,
+ 0,
+ 0);
+ UnicodeChar = (1 == RetChars ? Chars[0] : 0);
+ }
+
+ er.EventType = KEY_EVENT;
+ er.Event.KeyEvent.bKeyDown = Down;
+ er.Event.KeyEvent.wRepeatCount = RepeatCount;
+ er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar;
+ er.Event.KeyEvent.dwControlKeyState = ShiftState;
+ er.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode;
+ er.Event.KeyEvent.wVirtualScanCode = VirtualScanCode;
+
+ if (TextMode)
+ {
+ if (0 != (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
+ && VK_TAB == VirtualKeyCode)
+ {
+ if (Down)
+ {
+ TuiSwapConsole(ShiftState & SHIFT_PRESSED ? -1 : 1);
+ }
+
+ return;
+ }
+ else if (VK_MENU == VirtualKeyCode && ! Down)
+ {
+ if (TuiSwapConsole(0))
+ {
+ return;
+ }
+ }
+ }
+ else
+ {
+ if ((ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED) || KeyState[VK_MENU] & 0x80) &&
+ (VirtualKeyCode == VK_ESCAPE || VirtualKeyCode == VK_TAB || VirtualKeyCode == VK_SPACE))
+ {
+ DefWindowProcW( msg->hwnd, msg->message, msg->wParam, msg->lParam);
+ return;
+ }
+ }
+
+ if (NULL == Console)
+ {
+ DPRINT1("No Active Console!\n");
+ return;
+ }
+
+ Fake = UnicodeChar &&
+ (msg->message != WM_CHAR && msg->message != WM_SYSCHAR &&
+ msg->message != WM_KEYUP && msg->message != WM_SYSKEYUP);
+ NotChar = (msg->message != WM_CHAR && msg->message != WM_SYSCHAR);
+ if (NotChar)
+ LastVirtualKey = msg->wParam;
+
+ DPRINT ("csrss: %s %s %s %s %02x %02x '%lc' %04x\n",
+ Down ? "down" : "up ",
+ (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) ?
+ "char" : "key ",
+ Fake ? "fake" : "real",
+ NotChar ? "notc" : "char",
+ VirtualScanCode,
+ VirtualKeyCode,
+ (UnicodeChar >= L' ') ? UnicodeChar : L'.',
+ ShiftState);
+
+ if (Fake)
+ return;
+
+ /* process Ctrl-C and Ctrl-Break */
+ if (Console->Mode & ENABLE_PROCESSED_INPUT &&
+ er.Event.KeyEvent.bKeyDown &&
+ ((er.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE) ||
+ (er.Event.KeyEvent.wVirtualKeyCode == 'C')) &&
+ (er.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) || KeyState[VK_CONTROL] & 0x80))
+ {
+ PCSR_PROCESS current;
+ PLIST_ENTRY current_entry;
+ DPRINT1("Console_Api Ctrl-C\n");
+ current_entry = Console->ProcessList.Flink;
+ while (current_entry != &Console->ProcessList)
+ {
+ current = CONTAINING_RECORD(current_entry, CSR_PROCESS, ConsoleLink);
+ current_entry = current_entry->Flink;
+ ConioConsoleCtrlEvent((DWORD)CTRL_C_EVENT, current);
+ }
+ if (Console->LineBuffer && !Console->LineComplete)
+ {
+ /* Line input is in progress; end it */
+ Console->LinePos = Console->LineSize = 0;
+ Console->LineComplete = TRUE;
+ }
+ return;
+ }
+
+ if (0 != (er.Event.KeyEvent.dwControlKeyState
+ & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
+ && (VK_UP == er.Event.KeyEvent.wVirtualKeyCode
+ || VK_DOWN == er.Event.KeyEvent.wVirtualKeyCode))
+ {
+ if (er.Event.KeyEvent.bKeyDown)
+ {
+ /* scroll up or down */
+ if (VK_UP == er.Event.KeyEvent.wVirtualKeyCode)
+ {
+ /* only scroll up if there is room to scroll up into */
+ if (Console->ActiveBuffer->CurrentY != Console->ActiveBuffer->MaxY - 1)
+ {
+ Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY +
+ Console->ActiveBuffer->MaxY - 1) %
+ Console->ActiveBuffer->MaxY;
+ Console->ActiveBuffer->CurrentY++;
+ }
+ }
+ else
+ {
+ /* only scroll down if there is room to scroll down into */
+ if (Console->ActiveBuffer->CurrentY != 0)
+ {
+ Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + 1) %
+ Console->ActiveBuffer->MaxY;
+ Console->ActiveBuffer->CurrentY--;
+ }
+ }
+ ConioDrawConsole(Console);
+ }
+ return;
+ }
+ ConioProcessChar(Console, &er);
+}
+
+CSR_API(CsrReadInputEvent)
+{
+ PLIST_ENTRY CurrentEntry;
+ PCSRSS_CONSOLE Console;
+ NTSTATUS Status;
+ BOOLEAN Done = FALSE;
+ ConsoleInput *Input;
+
+ DPRINT("CsrReadInputEvent\n");
+
+ Request->Data.ReadInputRequest.Event = ProcessData->ConsoleEvent;
+
+ Status = ConioLockConsole(ProcessData, Request->Data.ReadInputRequest.ConsoleHandle, &Console, GENERIC_READ);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ /* only get input if there is any */
+ CurrentEntry = Console->InputEvents.Flink;
+ while (CurrentEntry != &Console->InputEvents)
+ {
+ Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
+ CurrentEntry = CurrentEntry->Flink;
+
+ if (Done)
+ {
+ Request->Data.ReadInputRequest.MoreEvents = TRUE;
+ break;
+ }
+
+ RemoveEntryList(&Input->ListEntry);
+
+ if (!Done)
+ {
+ Request->Data.ReadInputRequest.Input = Input->InputEvent;
+ if (Request->Data.ReadInputRequest.Unicode == FALSE)
+ {
+ ConioInputEventToAnsi(Console, &Request->Data.ReadInputRequest.Input);
+ }
+ Done = TRUE;
+ }
+
+ HeapFree(Win32CsrApiHeap, 0, Input);
+ }
+
+ if (Done)
+ Status = STATUS_SUCCESS;
+ else
+ Status = STATUS_PENDING;
+
+ if (IsListEmpty(&Console->InputEvents))
+ {
+ ResetEvent(Console->ActiveEvent);
+ }
+
+ ConioUnlockConsole(Console);
+
+ return Status;
+}
+
+CSR_API(CsrFlushInputBuffer)
+{
+ PLIST_ENTRY CurrentEntry;
+ PCSRSS_CONSOLE Console;
+ ConsoleInput* Input;
+ NTSTATUS Status;
+
+ DPRINT("CsrFlushInputBuffer\n");
+
+ Status = ConioLockConsole(ProcessData,
+ Request->Data.FlushInputBufferRequest.ConsoleInput,
+ &Console,
+ GENERIC_WRITE);
+ if(! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ /* Discard all entries in the input event queue */
+ while (!IsListEmpty(&Console->InputEvents))
+ {
+ CurrentEntry = RemoveHeadList(&Console->InputEvents);
+ Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
+ /* Destroy the event */
+ HeapFree(Win32CsrApiHeap, 0, Input);
+ }
+ ResetEvent(Console->ActiveEvent);
+
+ ConioUnlockConsole(Console);
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrGetNumberOfConsoleInputEvents)
+{
+ NTSTATUS Status;
+ PCSRSS_CONSOLE Console;
+ PLIST_ENTRY CurrentItem;
+ DWORD NumEvents;
+
+ DPRINT("CsrGetNumberOfConsoleInputEvents\n");
+
+ Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console, GENERIC_READ);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ CurrentItem = Console->InputEvents.Flink;
+ NumEvents = 0;
+
+ /* If there are any events ... */
+ while (CurrentItem != &Console->InputEvents)
+ {
+ CurrentItem = CurrentItem->Flink;
+ NumEvents++;
+ }
+
+ ConioUnlockConsole(Console);
+
+ Request->Data.GetNumInputEventsRequest.NumInputEvents = NumEvents;
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrPeekConsoleInput)
+{
+ NTSTATUS Status;
+ PCSRSS_CONSOLE Console;
+ DWORD Length;
+ PLIST_ENTRY CurrentItem;
+ PINPUT_RECORD InputRecord;
+ ConsoleInput* Item;
+ UINT NumItems;
+
+ DPRINT("CsrPeekConsoleInput\n");
+
+ Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console, GENERIC_READ);
+ if(! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ InputRecord = Request->Data.PeekConsoleInputRequest.InputRecord;
+ Length = Request->Data.PeekConsoleInputRequest.Length;
+
+ if (!Win32CsrValidateBuffer(ProcessData, InputRecord, Length, sizeof(INPUT_RECORD)))
+ {
+ ConioUnlockConsole(Console);
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ NumItems = 0;
+
+ if (! IsListEmpty(&Console->InputEvents))
+ {
+ CurrentItem = Console->InputEvents.Flink;
+
+ while (CurrentItem != &Console->InputEvents && NumItems < Length)
+ {
+ Item = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
+
+ ++NumItems;
+ *InputRecord = Item->InputEvent;
+
+ if (Request->Data.PeekConsoleInputRequest.Unicode == FALSE)
+ {
+ ConioInputEventToAnsi(Console, InputRecord);
+ }
+
+ InputRecord++;
+ CurrentItem = CurrentItem->Flink;
+ }
+ }
+
+ ConioUnlockConsole(Console);
+
+ Request->Data.PeekConsoleInputRequest.Length = NumItems;
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrWriteConsoleInput)
+{
+ PINPUT_RECORD InputRecord;
+ PCSRSS_CONSOLE Console;
+ NTSTATUS Status;
+ DWORD Length;
+ DWORD i;
+
+ DPRINT("CsrWriteConsoleInput\n");
+
+ Status = ConioLockConsole(ProcessData, Request->Data.WriteConsoleInputRequest.ConsoleHandle, &Console, GENERIC_WRITE);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ InputRecord = Request->Data.WriteConsoleInputRequest.InputRecord;
+ Length = Request->Data.WriteConsoleInputRequest.Length;
+
+ if (!Win32CsrValidateBuffer(ProcessData, InputRecord, Length, sizeof(INPUT_RECORD)))
+ {
+ ConioUnlockConsole(Console);
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ for (i = 0; i < Length && NT_SUCCESS(Status); i++)
+ {
+ if (!Request->Data.WriteConsoleInputRequest.Unicode &&
+ InputRecord->EventType == KEY_EVENT)
+ {
+ CHAR AsciiChar = InputRecord->Event.KeyEvent.uChar.AsciiChar;
+ ConsoleInputAnsiCharToUnicodeChar(Console,
+ &InputRecord->Event.KeyEvent.uChar.UnicodeChar,
+ &AsciiChar);
+ }
+ Status = ConioProcessChar(Console, InputRecord++);
+ }
+
+ ConioUnlockConsole(Console);
+
+ Request->Data.WriteConsoleInputRequest.Length = i;
+
+ return Status;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: subsys/csrss/include/conio.h
+ * PURPOSE: CSRSS internal console I/O interface
+ */
+
+#pragma once
+
+#include "api.h"
+#include "win32csr.h"
+
+#define CSR_DEFAULT_CURSOR_SIZE 25
+
+/* Object type magic numbers */
+
+#define CONIO_CONSOLE_MAGIC 0x00000001
+#define CONIO_SCREEN_BUFFER_MAGIC 0x00000002
+
+/************************************************************************
+ * Screen buffer structure represents the win32 screen buffer object. *
+ * Internally, the portion of the buffer being shown CAN loop past the *
+ * bottom of the virtual buffer and wrap around to the top. Win32 does *
+ * not do this. I decided to do this because it eliminates the need to *
+ * do a massive memcpy() to scroll the contents of the buffer up to *
+ * scroll the screen on output, instead I just shift down the position *
+ * to be displayed, and let it wrap around to the top again. *
+ * The VirtualY member keeps track of the top Y coord that win32 *
+ * clients THINK is currently being displayed, because they think that *
+ * when the display reaches the bottom of the buffer and another line *
+ * being printed causes another line to scroll down, that the buffer IS *
+ * memcpy()'s up, and the bottom of the buffer is still displayed, but *
+ * internally, I just wrap back to the top of the buffer. *
+ ***********************************************************************/
+
+typedef struct tagCSRSS_SCREEN_BUFFER
+{
+ Object_t Header; /* Object header */
+ BYTE *Buffer; /* pointer to screen buffer */
+ USHORT MaxX, MaxY; /* size of the entire scrollback buffer */
+ USHORT ShowX, ShowY; /* beginning offset for the actual display area */
+ ULONG CurrentX; /* Current X cursor position */
+ ULONG CurrentY; /* Current Y cursor position */
+ WORD DefaultAttrib; /* default char attribute */
+ USHORT VirtualY; /* top row of buffer being displayed, reported to callers */
+ CONSOLE_CURSOR_INFO CursorInfo;
+ USHORT Mode;
+ LIST_ENTRY ListEntry; /* entry in console's list of buffers */
+} CSRSS_SCREEN_BUFFER, *PCSRSS_SCREEN_BUFFER;
+
+typedef struct tagCSRSS_CONSOLE *PCSRSS_CONSOLE;
+
+typedef struct tagCSRSS_CONSOLE_VTBL
+{
+ VOID (WINAPI *InitScreenBuffer)(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER ScreenBuffer);
+ VOID (WINAPI *WriteStream)(PCSRSS_CONSOLE Console, SMALL_RECT *Block, LONG CursorStartX, LONG CursorStartY,
+ UINT ScrolledLines, CHAR *Buffer, UINT Length);
+ VOID (WINAPI *DrawRegion)(PCSRSS_CONSOLE Console, SMALL_RECT *Region);
+ BOOL (WINAPI *SetCursorInfo)(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER ScreenBuffer);
+ BOOL (WINAPI *SetScreenInfo)(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER ScreenBuffer,
+ UINT OldCursorX, UINT OldCursorY);
+ BOOL (WINAPI *UpdateScreenInfo)(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER ScreenBuffer);
+ BOOL (WINAPI *ChangeTitle)(PCSRSS_CONSOLE Console);
+ VOID (WINAPI *CleanupConsole)(PCSRSS_CONSOLE Console);
+ BOOL (WINAPI *ChangeIcon)(PCSRSS_CONSOLE Console, HICON hWindowIcon);
+ NTSTATUS (WINAPI *ResizeBuffer)(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER ScreenBuffer, COORD Size);
+} CSRSS_CONSOLE_VTBL, *PCSRSS_CONSOLE_VTBL;
+
+typedef struct tagCSRSS_CONSOLE
+{
+ Object_t Header; /* Object header */
+ LONG ReferenceCount;
+ CRITICAL_SECTION Lock;
+ PCSRSS_CONSOLE Prev, Next; /* Next and Prev consoles in console wheel */
+ HANDLE ActiveEvent;
+ LIST_ENTRY InputEvents; /* List head for input event queue */
+ PWCHAR LineBuffer; /* current line being input, in line buffered mode */
+ WORD LineMaxSize; /* maximum size of line in characters (including CR+LF) */
+ WORD LineSize; /* current size of line */
+ WORD LinePos; /* current position within line */
+ BOOLEAN LineComplete; /* user pressed enter, ready to send back to client */
+ BOOLEAN LineUpPressed;
+ BOOLEAN LineInsertToggle; /* replace character over cursor instead of inserting */
+ ULONG LineWakeupMask; /* bitmap of which control characters will end line input */
+ LIST_ENTRY HistoryBuffers;
+ WORD HistoryBufferSize; /* size for newly created history buffers */
+ WORD NumberOfHistoryBuffers; /* maximum number of history buffers allowed */
+ BOOLEAN HistoryNoDup; /* remove old duplicate history entries */
+ LIST_ENTRY BufferList; /* List of all screen buffers for this console */
+ PCSRSS_SCREEN_BUFFER ActiveBuffer; /* Pointer to currently active screen buffer */
+ WORD Mode; /* Console mode flags */
+ UNICODE_STRING Title; /* Title of console */
+ DWORD HardwareState; /* _GDI_MANAGED, _DIRECT */
+ HWND hWindow;
+ COORD Size;
+ PVOID PrivateData;
+ UINT CodePage;
+ UINT OutputCodePage;
+ PCSRSS_CONSOLE_VTBL Vtbl;
+ LIST_ENTRY ProcessList;
+ struct tagALIAS_HEADER *Aliases;
+ CONSOLE_SELECTION_INFO Selection;
+ BYTE PauseFlags;
+ HANDLE UnpauseEvent;
+} CSRSS_CONSOLE;
+
+typedef struct ConsoleInput_t
+{
+ LIST_ENTRY ListEntry;
+ INPUT_RECORD InputEvent;
+} ConsoleInput;
+
+/* CONSOLE_SELECTION_INFO dwFlags values */
+#define CONSOLE_NO_SELECTION 0x0
+#define CONSOLE_SELECTION_IN_PROGRESS 0x1
+#define CONSOLE_SELECTION_NOT_EMPTY 0x2
+#define CONSOLE_MOUSE_SELECTION 0x4
+#define CONSOLE_MOUSE_DOWN 0x8
+/* HistoryFlags values */
+#define HISTORY_NO_DUP_FLAG 0x1
+
+/* PauseFlags values (internal only) */
+#define PAUSED_FROM_KEYBOARD 0x1
+#define PAUSED_FROM_SCROLLBAR 0x2
+#define PAUSED_FROM_SELECTION 0x4
+
+#define ConioInitScreenBuffer(Console, Buff) (Console)->Vtbl->InitScreenBuffer((Console), (Buff))
+#define ConioDrawRegion(Console, Region) (Console)->Vtbl->DrawRegion((Console), (Region))
+#define ConioWriteStream(Console, Block, CurStartX, CurStartY, ScrolledLines, Buffer, Length) \
+ (Console)->Vtbl->WriteStream((Console), (Block), (CurStartX), (CurStartY), \
+ (ScrolledLines), (Buffer), (Length))
+#define ConioSetCursorInfo(Console, Buff) (Console)->Vtbl->SetCursorInfo((Console), (Buff))
+#define ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY) \
+ (Console)->Vtbl->SetScreenInfo((Console), (Buff), (OldCursorX), (OldCursorY))
+#define ConioUpdateScreenInfo(Console, Buff) \
+ (Console)->Vtbl->UpdateScreenInfo(Console, Buff)
+#define ConioChangeTitle(Console) (Console)->Vtbl->ChangeTitle(Console)
+#define ConioCleanupConsole(Console) (Console)->Vtbl->CleanupConsole(Console)
+#define ConioChangeIcon(Console, hWindowIcon) (Console)->Vtbl->ChangeIcon(Console, hWindowIcon)
+#define ConioResizeBuffer(Console, Buff, Size) (Console)->Vtbl->ResizeBuffer(Console, Buff, Size)
+
+/* console.c */
+NTSTATUS FASTCALL ConioConsoleFromProcessData(PCSR_PROCESS ProcessData, PCSRSS_CONSOLE *Console);
+VOID WINAPI ConioDeleteConsole(Object_t *Object);
+VOID WINAPI CsrInitConsoleSupport(VOID);
+VOID FASTCALL ConioPause(PCSRSS_CONSOLE Console, UINT Flags);
+VOID FASTCALL ConioUnpause(PCSRSS_CONSOLE Console, UINT Flags);
+VOID FASTCALL ConioConsoleCtrlEvent(DWORD Event, PCSR_PROCESS ProcessData);
+VOID FASTCALL ConioConsoleCtrlEventTimeout(DWORD Event, PCSR_PROCESS ProcessData,
+ DWORD Timeout);
+CSR_API(CsrAllocConsole);
+CSR_API(CsrFreeConsole);
+CSR_API(CsrSetConsoleMode);
+CSR_API(CsrGetConsoleMode);
+CSR_API(CsrSetTitle);
+CSR_API(CsrGetTitle);
+CSR_API(CsrHardwareStateProperty);
+CSR_API(CsrGetConsoleWindow);
+CSR_API(CsrSetConsoleIcon);
+CSR_API(CsrGetConsoleCodePage);
+CSR_API(CsrSetConsoleCodePage);
+CSR_API(CsrGetConsoleOutputCodePage);
+CSR_API(CsrSetConsoleOutputCodePage);
+CSR_API(CsrGetProcessList);
+CSR_API(CsrGenerateCtrlEvent);
+CSR_API(CsrGetConsoleSelectionInfo);
+
+/* coninput.c */
+#define ConioLockConsole(ProcessData, Handle, Ptr, Access) \
+ Win32CsrLockObject((ProcessData), (Handle), (Object_t **)(Ptr), Access, CONIO_CONSOLE_MAGIC)
+#define ConioUnlockConsole(Console) \
+ Win32CsrUnlockObject((Object_t *) Console)
+void WINAPI ConioProcessKey(MSG *msg, PCSRSS_CONSOLE Console, BOOL TextMode);
+CSR_API(CsrReadConsole);
+CSR_API(CsrReadInputEvent);
+CSR_API(CsrFlushInputBuffer);
+CSR_API(CsrGetNumberOfConsoleInputEvents);
+CSR_API(CsrPeekConsoleInput);
+CSR_API(CsrWriteConsoleInput);
+
+/* conoutput.c */
+#define ConioRectHeight(Rect) \
+ (((Rect)->Top) > ((Rect)->Bottom) ? 0 : ((Rect)->Bottom) - ((Rect)->Top) + 1)
+#define ConioRectWidth(Rect) \
+ (((Rect)->Left) > ((Rect)->Right) ? 0 : ((Rect)->Right) - ((Rect)->Left) + 1)
+#define ConioLockScreenBuffer(ProcessData, Handle, Ptr, Access) \
+ Win32CsrLockObject((ProcessData), (Handle), (Object_t **)(Ptr), Access, CONIO_SCREEN_BUFFER_MAGIC)
+#define ConioUnlockScreenBuffer(Buff) \
+ Win32CsrUnlockObject((Object_t *) Buff)
+PBYTE FASTCALL ConioCoordToPointer(PCSRSS_SCREEN_BUFFER Buf, ULONG X, ULONG Y);
+VOID FASTCALL ConioDrawConsole(PCSRSS_CONSOLE Console);
+NTSTATUS FASTCALL ConioWriteConsole(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff,
+ CHAR *Buffer, DWORD Length, BOOL Attrib);
+NTSTATUS FASTCALL CsrInitConsoleScreenBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buffer);
+VOID WINAPI ConioDeleteScreenBuffer(PCSRSS_SCREEN_BUFFER Buffer);
+DWORD FASTCALL ConioEffectiveCursorSize(PCSRSS_CONSOLE Console, DWORD Scale);
+
+CSR_API(CsrWriteConsole);
+CSR_API(CsrGetScreenBufferInfo);
+CSR_API(CsrSetCursor);
+CSR_API(CsrWriteConsoleOutputChar);
+CSR_API(CsrFillOutputChar);
+CSR_API(CsrWriteConsoleOutputAttrib);
+CSR_API(CsrFillOutputAttrib);
+CSR_API(CsrGetCursorInfo);
+CSR_API(CsrSetCursorInfo);
+CSR_API(CsrSetTextAttrib);
+CSR_API(CsrCreateScreenBuffer);
+CSR_API(CsrSetScreenBuffer);
+CSR_API(CsrWriteConsoleOutput);
+CSR_API(CsrScrollConsoleScreenBuffer);
+CSR_API(CsrReadConsoleOutputChar);
+CSR_API(CsrReadConsoleOutputAttrib);
+CSR_API(CsrReadConsoleOutput);
+CSR_API(CsrSetScreenBufferSize);
+
+/* alias.c */
+VOID IntDeleteAllAliases(struct tagALIAS_HEADER *RootHeader);
+CSR_API(CsrAddConsoleAlias);
+CSR_API(CsrGetConsoleAlias);
+CSR_API(CsrGetAllConsoleAliases);
+CSR_API(CsrGetAllConsoleAliasesLength);
+CSR_API(CsrGetConsoleAliasesExes);
+CSR_API(CsrGetConsoleAliasesExesLength);
+
+/* lineinput.c */
+struct tagHISTORY_BUFFER;
+VOID FASTCALL HistoryDeleteBuffer(struct tagHISTORY_BUFFER *Hist);
+CSR_API(CsrGetCommandHistoryLength);
+CSR_API(CsrGetCommandHistory);
+CSR_API(CsrExpungeCommandHistory);
+CSR_API(CsrSetHistoryNumberCommands);
+CSR_API(CsrGetHistoryInfo);
+CSR_API(CsrSetHistoryInfo);
+VOID FASTCALL LineInputKeyDown(PCSRSS_CONSOLE Console, KEY_EVENT_RECORD *KeyEvent);
+
+/* EOF */
--- /dev/null
+/*
+ * reactos/subsys/csrss/win32csr/conio.c
+ *
+ * Console I/O functions
+ *
+ * ReactOS Operating System
+ */
+
+/* INCLUDES ******************************************************************/
+
+#define NDEBUG
+#include "w32csr.h"
+#include <debug.h>
+
+/* GLOBALS *******************************************************************/
+
+#define ConioInitRect(Rect, top, left, bottom, right) \
+ ((Rect)->Top) = top; \
+ ((Rect)->Left) = left; \
+ ((Rect)->Bottom) = bottom; \
+ ((Rect)->Right) = right
+
+#define ConioIsRectEmpty(Rect) \
+ (((Rect)->Left > (Rect)->Right) || ((Rect)->Top > (Rect)->Bottom))
+
+#define ConsoleUnicodeCharToAnsiChar(Console, dChar, sWChar) \
+ WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
+
+#define ConsoleAnsiCharToUnicodeChar(Console, dWChar, sChar) \
+ MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1)
+
+/* FUNCTIONS *****************************************************************/
+
+PBYTE FASTCALL
+ConioCoordToPointer(PCSRSS_SCREEN_BUFFER Buff, ULONG X, ULONG Y)
+{
+ return &Buff->Buffer[2 * (((Y + Buff->VirtualY) % Buff->MaxY) * Buff->MaxX + X)];
+}
+
+static VOID FASTCALL
+ClearLineBuffer(PCSRSS_SCREEN_BUFFER Buff)
+{
+ PBYTE Ptr = ConioCoordToPointer(Buff, 0, Buff->CurrentY);
+ UINT Pos;
+
+ for (Pos = 0; Pos < Buff->MaxX; Pos++)
+ {
+ /* Fill the cell */
+ *Ptr++ = ' ';
+ *Ptr++ = Buff->DefaultAttrib;
+ }
+}
+
+NTSTATUS FASTCALL
+CsrInitConsoleScreenBuffer(PCSRSS_CONSOLE Console,
+ PCSRSS_SCREEN_BUFFER Buffer)
+{
+ DPRINT("CsrInitConsoleScreenBuffer Size X %d Size Y %d\n", Buffer->MaxX, Buffer->MaxY);
+
+ Buffer->Header.Type = CONIO_SCREEN_BUFFER_MAGIC;
+ Buffer->Header.Console = Console;
+ Buffer->Header.HandleCount = 0;
+ Buffer->ShowX = 0;
+ Buffer->ShowY = 0;
+ Buffer->VirtualY = 0;
+ Buffer->Buffer = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY, Buffer->MaxX * Buffer->MaxY * 2);
+ if (NULL == Buffer->Buffer)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ ConioInitScreenBuffer(Console, Buffer);
+ /* initialize buffer to be empty with default attributes */
+ for (Buffer->CurrentY = 0 ; Buffer->CurrentY < Buffer->MaxY; Buffer->CurrentY++)
+ {
+ ClearLineBuffer(Buffer);
+ }
+ Buffer->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
+ Buffer->CurrentX = 0;
+ Buffer->CurrentY = 0;
+
+ InsertHeadList(&Console->BufferList, &Buffer->ListEntry);
+ return STATUS_SUCCESS;
+}
+
+static VOID FASTCALL
+ConioNextLine(PCSRSS_SCREEN_BUFFER Buff, SMALL_RECT *UpdateRect, UINT *ScrolledLines)
+{
+ /* If we hit bottom, slide the viewable screen */
+ if (++Buff->CurrentY == Buff->MaxY)
+ {
+ Buff->CurrentY--;
+ if (++Buff->VirtualY == Buff->MaxY)
+ {
+ Buff->VirtualY = 0;
+ }
+ (*ScrolledLines)++;
+ ClearLineBuffer(Buff);
+ if (UpdateRect->Top != 0)
+ {
+ UpdateRect->Top--;
+ }
+ }
+ UpdateRect->Left = 0;
+ UpdateRect->Right = Buff->MaxX - 1;
+ UpdateRect->Bottom = Buff->CurrentY;
+}
+
+NTSTATUS FASTCALL
+ConioWriteConsole(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff,
+ CHAR *Buffer, DWORD Length, BOOL Attrib)
+{
+ UINT i;
+ PBYTE Ptr;
+ SMALL_RECT UpdateRect;
+ LONG CursorStartX, CursorStartY;
+ UINT ScrolledLines;
+
+ CursorStartX = Buff->CurrentX;
+ CursorStartY = Buff->CurrentY;
+ UpdateRect.Left = Buff->MaxX;
+ UpdateRect.Top = Buff->CurrentY;
+ UpdateRect.Right = -1;
+ UpdateRect.Bottom = Buff->CurrentY;
+ ScrolledLines = 0;
+
+ for (i = 0; i < Length; i++)
+ {
+ if (Buff->Mode & ENABLE_PROCESSED_OUTPUT)
+ {
+ /* --- LF --- */
+ if (Buffer[i] == '\n')
+ {
+ Buff->CurrentX = 0;
+ ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
+ continue;
+ }
+ /* --- BS --- */
+ else if (Buffer[i] == '\b')
+ {
+ /* Only handle BS if we're not on the first pos of the first line */
+ if (0 != Buff->CurrentX || 0 != Buff->CurrentY)
+ {
+ if (0 == Buff->CurrentX)
+ {
+ /* slide virtual position up */
+ Buff->CurrentX = Buff->MaxX - 1;
+ Buff->CurrentY--;
+ UpdateRect.Top = min(UpdateRect.Top, (LONG)Buff->CurrentY);
+ }
+ else
+ {
+ Buff->CurrentX--;
+ }
+ Ptr = ConioCoordToPointer(Buff, Buff->CurrentX, Buff->CurrentY);
+ Ptr[0] = ' ';
+ Ptr[1] = Buff->DefaultAttrib;
+ UpdateRect.Left = min(UpdateRect.Left, (LONG) Buff->CurrentX);
+ UpdateRect.Right = max(UpdateRect.Right, (LONG) Buff->CurrentX);
+ }
+ continue;
+ }
+ /* --- CR --- */
+ else if (Buffer[i] == '\r')
+ {
+ Buff->CurrentX = 0;
+ UpdateRect.Left = min(UpdateRect.Left, (LONG) Buff->CurrentX);
+ UpdateRect.Right = max(UpdateRect.Right, (LONG) Buff->CurrentX);
+ continue;
+ }
+ /* --- TAB --- */
+ else if (Buffer[i] == '\t')
+ {
+ UINT EndX;
+
+ UpdateRect.Left = min(UpdateRect.Left, (LONG)Buff->CurrentX);
+ EndX = (Buff->CurrentX + 8) & ~7;
+ if (EndX > Buff->MaxX)
+ {
+ EndX = Buff->MaxX;
+ }
+ Ptr = ConioCoordToPointer(Buff, Buff->CurrentX, Buff->CurrentY);
+ while (Buff->CurrentX < EndX)
+ {
+ *Ptr++ = ' ';
+ *Ptr++ = Buff->DefaultAttrib;
+ Buff->CurrentX++;
+ }
+ UpdateRect.Right = max(UpdateRect.Right, (LONG) Buff->CurrentX - 1);
+ if (Buff->CurrentX == Buff->MaxX)
+ {
+ if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
+ {
+ Buff->CurrentX = 0;
+ ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
+ }
+ else
+ {
+ Buff->CurrentX--;
+ }
+ }
+ continue;
+ }
+ }
+ UpdateRect.Left = min(UpdateRect.Left, (LONG)Buff->CurrentX);
+ UpdateRect.Right = max(UpdateRect.Right, (LONG) Buff->CurrentX);
+ Ptr = ConioCoordToPointer(Buff, Buff->CurrentX, Buff->CurrentY);
+ Ptr[0] = Buffer[i];
+ if (Attrib)
+ {
+ Ptr[1] = Buff->DefaultAttrib;
+ }
+ Buff->CurrentX++;
+ if (Buff->CurrentX == Buff->MaxX)
+ {
+ if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
+ {
+ Buff->CurrentX = 0;
+ ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
+ }
+ else
+ {
+ Buff->CurrentX = CursorStartX;
+ }
+ }
+ }
+
+ if (! ConioIsRectEmpty(&UpdateRect) && Buff == Console->ActiveBuffer)
+ {
+ ConioWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY, ScrolledLines,
+ Buffer, Length);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+__inline BOOLEAN ConioGetIntersection(
+ SMALL_RECT *Intersection,
+ SMALL_RECT *Rect1,
+ SMALL_RECT *Rect2)
+{
+ if (ConioIsRectEmpty(Rect1) ||
+ (ConioIsRectEmpty(Rect2)) ||
+ (Rect1->Top > Rect2->Bottom) ||
+ (Rect1->Left > Rect2->Right) ||
+ (Rect1->Bottom < Rect2->Top) ||
+ (Rect1->Right < Rect2->Left))
+ {
+ /* The rectangles do not intersect */
+ ConioInitRect(Intersection, 0, -1, 0, -1);
+ return FALSE;
+ }
+
+ ConioInitRect(Intersection,
+ max(Rect1->Top, Rect2->Top),
+ max(Rect1->Left, Rect2->Left),
+ min(Rect1->Bottom, Rect2->Bottom),
+ min(Rect1->Right, Rect2->Right));
+
+ return TRUE;
+}
+
+__inline BOOLEAN ConioGetUnion(
+ SMALL_RECT *Union,
+ SMALL_RECT *Rect1,
+ SMALL_RECT *Rect2)
+{
+ if (ConioIsRectEmpty(Rect1))
+ {
+ if (ConioIsRectEmpty(Rect2))
+ {
+ ConioInitRect(Union, 0, -1, 0, -1);
+ return FALSE;
+ }
+ else
+ {
+ *Union = *Rect2;
+ }
+ }
+ else if (ConioIsRectEmpty(Rect2))
+ {
+ *Union = *Rect1;
+ }
+ else
+ {
+ ConioInitRect(Union,
+ min(Rect1->Top, Rect2->Top),
+ min(Rect1->Left, Rect2->Left),
+ max(Rect1->Bottom, Rect2->Bottom),
+ max(Rect1->Right, Rect2->Right));
+ }
+
+ return TRUE;
+}
+
+/* Move from one rectangle to another. We must be careful about the order that
+ * this is done, to avoid overwriting parts of the source before they are moved. */
+static VOID FASTCALL
+ConioMoveRegion(PCSRSS_SCREEN_BUFFER ScreenBuffer,
+ SMALL_RECT *SrcRegion,
+ SMALL_RECT *DstRegion,
+ SMALL_RECT *ClipRegion,
+ WORD Fill)
+{
+ int Width = ConioRectWidth(SrcRegion);
+ int Height = ConioRectHeight(SrcRegion);
+ int SX, SY;
+ int DX, DY;
+ int XDelta, YDelta;
+ int i, j;
+
+ SY = SrcRegion->Top;
+ DY = DstRegion->Top;
+ YDelta = 1;
+ if (SY < DY)
+ {
+ /* Moving down: work from bottom up */
+ SY = SrcRegion->Bottom;
+ DY = DstRegion->Bottom;
+ YDelta = -1;
+ }
+ for (i = 0; i < Height; i++)
+ {
+ PWORD SRow = (PWORD)ConioCoordToPointer(ScreenBuffer, 0, SY);
+ PWORD DRow = (PWORD)ConioCoordToPointer(ScreenBuffer, 0, DY);
+
+ SX = SrcRegion->Left;
+ DX = DstRegion->Left;
+ XDelta = 1;
+ if (SX < DX)
+ {
+ /* Moving right: work from right to left */
+ SX = SrcRegion->Right;
+ DX = DstRegion->Right;
+ XDelta = -1;
+ }
+ for (j = 0; j < Width; j++)
+ {
+ WORD Cell = SRow[SX];
+ if (SX >= ClipRegion->Left && SX <= ClipRegion->Right
+ && SY >= ClipRegion->Top && SY <= ClipRegion->Bottom)
+ {
+ SRow[SX] = Fill;
+ }
+ if (DX >= ClipRegion->Left && DX <= ClipRegion->Right
+ && DY >= ClipRegion->Top && DY <= ClipRegion->Bottom)
+ {
+ DRow[DX] = Cell;
+ }
+ SX += XDelta;
+ DX += XDelta;
+ }
+ SY += YDelta;
+ DY += YDelta;
+ }
+}
+
+CSR_API(CsrWriteConsole)
+{
+ NTSTATUS Status;
+ PCHAR Buffer;
+ PCSRSS_SCREEN_BUFFER Buff;
+ PCSRSS_CONSOLE Console;
+ DWORD Written = 0;
+ ULONG Length;
+ ULONG CharSize = (Request->Data.WriteConsoleRequest.Unicode ? sizeof(WCHAR) : sizeof(CHAR));
+
+ DPRINT("CsrWriteConsole\n");
+
+ if (Request->Header.u1.s1.TotalLength
+ < CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE)
+ + (Request->Data.WriteConsoleRequest.NrCharactersToWrite * CharSize))
+ {
+ DPRINT1("Invalid request size\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Status = ConioLockScreenBuffer(ProcessData, Request->Data.WriteConsoleRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Console = Buff->Header.Console;
+
+ if (Console->UnpauseEvent)
+ {
+ Status = NtDuplicateObject(GetCurrentProcess(), Console->UnpauseEvent,
+ ProcessData->ProcessHandle, &Request->Data.WriteConsoleRequest.UnpauseEvent,
+ SYNCHRONIZE, 0, 0);
+ ConioUnlockScreenBuffer(Buff);
+ return NT_SUCCESS(Status) ? STATUS_PENDING : Status;
+ }
+
+ if(Request->Data.WriteConsoleRequest.Unicode)
+ {
+ Length = WideCharToMultiByte(Console->OutputCodePage, 0,
+ (PWCHAR)Request->Data.WriteConsoleRequest.Buffer,
+ Request->Data.WriteConsoleRequest.NrCharactersToWrite,
+ NULL, 0, NULL, NULL);
+ Buffer = RtlAllocateHeap(GetProcessHeap(), 0, Length);
+ if (Buffer)
+ {
+ WideCharToMultiByte(Console->OutputCodePage, 0,
+ (PWCHAR)Request->Data.WriteConsoleRequest.Buffer,
+ Request->Data.WriteConsoleRequest.NrCharactersToWrite,
+ Buffer, Length, NULL, NULL);
+ }
+ else
+ {
+ Status = STATUS_NO_MEMORY;
+ }
+ }
+ else
+ {
+ Buffer = (PCHAR)Request->Data.WriteConsoleRequest.Buffer;
+ }
+
+ if (Buffer)
+ {
+ if (NT_SUCCESS(Status))
+ {
+ Status = ConioWriteConsole(Console, Buff, Buffer,
+ Request->Data.WriteConsoleRequest.NrCharactersToWrite, TRUE);
+ if (NT_SUCCESS(Status))
+ {
+ Written = Request->Data.WriteConsoleRequest.NrCharactersToWrite;
+ }
+ }
+ if (Request->Data.WriteConsoleRequest.Unicode)
+ {
+ RtlFreeHeap(GetProcessHeap(), 0, Buffer);
+ }
+ }
+ ConioUnlockScreenBuffer(Buff);
+
+ Request->Data.WriteConsoleRequest.NrCharactersWritten = Written;
+
+ return Status;
+}
+
+VOID WINAPI
+ConioDeleteScreenBuffer(PCSRSS_SCREEN_BUFFER Buffer)
+{
+ PCSRSS_CONSOLE Console = Buffer->Header.Console;
+
+ RemoveEntryList(&Buffer->ListEntry);
+ if (Buffer == Console->ActiveBuffer)
+ {
+ /* Deleted active buffer; switch to most recently created */
+ Console->ActiveBuffer = NULL;
+ if (!IsListEmpty(&Console->BufferList))
+ {
+ Console->ActiveBuffer = CONTAINING_RECORD(Console->BufferList.Flink, CSRSS_SCREEN_BUFFER, ListEntry);
+ ConioDrawConsole(Console);
+ }
+ }
+
+ HeapFree(Win32CsrApiHeap, 0, Buffer->Buffer);
+ HeapFree(Win32CsrApiHeap, 0, Buffer);
+}
+
+VOID FASTCALL
+ConioDrawConsole(PCSRSS_CONSOLE Console)
+{
+ SMALL_RECT Region;
+
+ ConioInitRect(&Region, 0, 0, Console->Size.Y - 1, Console->Size.X - 1);
+
+ ConioDrawRegion(Console, &Region);
+}
+
+CSR_API(CsrGetScreenBufferInfo)
+{
+ NTSTATUS Status;
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff;
+ PCONSOLE_SCREEN_BUFFER_INFO pInfo;
+
+ DPRINT("CsrGetScreenBufferInfo\n");
+
+ Status = ConioLockScreenBuffer(ProcessData, Request->Data.ScreenBufferInfoRequest.ConsoleHandle, &Buff, GENERIC_READ);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Console = Buff->Header.Console;
+ pInfo = &Request->Data.ScreenBufferInfoRequest.Info;
+ pInfo->dwSize.X = Buff->MaxX;
+ pInfo->dwSize.Y = Buff->MaxY;
+ pInfo->dwCursorPosition.X = Buff->CurrentX;
+ pInfo->dwCursorPosition.Y = Buff->CurrentY;
+ pInfo->wAttributes = Buff->DefaultAttrib;
+ pInfo->srWindow.Left = Buff->ShowX;
+ pInfo->srWindow.Right = Buff->ShowX + Console->Size.X - 1;
+ pInfo->srWindow.Top = Buff->ShowY;
+ pInfo->srWindow.Bottom = Buff->ShowY + Console->Size.Y - 1;
+ pInfo->dwMaximumWindowSize.X = Buff->MaxX;
+ pInfo->dwMaximumWindowSize.Y = Buff->MaxY;
+ ConioUnlockScreenBuffer(Buff);
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrSetCursor)
+{
+ NTSTATUS Status;
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff;
+ LONG OldCursorX, OldCursorY;
+ LONG NewCursorX, NewCursorY;
+
+ DPRINT("CsrSetCursor\n");
+
+ Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Console = Buff->Header.Console;
+
+ NewCursorX = Request->Data.SetCursorRequest.Position.X;
+ NewCursorY = Request->Data.SetCursorRequest.Position.Y;
+ if (NewCursorX < 0 || NewCursorX >= Buff->MaxX ||
+ NewCursorY < 0 || NewCursorY >= Buff->MaxY)
+ {
+ ConioUnlockScreenBuffer(Buff);
+ return STATUS_INVALID_PARAMETER;
+ }
+ OldCursorX = Buff->CurrentX;
+ OldCursorY = Buff->CurrentY;
+ Buff->CurrentX = NewCursorX;
+ Buff->CurrentY = NewCursorY;
+ if (Buff == Console->ActiveBuffer)
+ {
+ if (! ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY))
+ {
+ ConioUnlockScreenBuffer(Buff);
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ ConioUnlockScreenBuffer(Buff);
+
+ return STATUS_SUCCESS;
+}
+
+static VOID FASTCALL
+ConioComputeUpdateRect(PCSRSS_SCREEN_BUFFER Buff, SMALL_RECT *UpdateRect, COORD *Start, UINT Length)
+{
+ if (Buff->MaxX <= Start->X + Length)
+ {
+ UpdateRect->Left = 0;
+ }
+ else
+ {
+ UpdateRect->Left = Start->X;
+ }
+ if (Buff->MaxX <= Start->X + Length)
+ {
+ UpdateRect->Right = Buff->MaxX - 1;
+ }
+ else
+ {
+ UpdateRect->Right = Start->X + Length - 1;
+ }
+ UpdateRect->Top = Start->Y;
+ UpdateRect->Bottom = Start->Y+ (Start->X + Length - 1) / Buff->MaxX;
+ if (Buff->MaxY <= UpdateRect->Bottom)
+ {
+ UpdateRect->Bottom = Buff->MaxY - 1;
+ }
+}
+
+CSR_API(CsrWriteConsoleOutputChar)
+{
+ NTSTATUS Status;
+ PCHAR String, tmpString = NULL;
+ PBYTE Buffer;
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff;
+ DWORD X, Y, Length, CharSize, Written = 0;
+ SMALL_RECT UpdateRect;
+
+ DPRINT("CsrWriteConsoleOutputChar\n");
+
+ CharSize = (Request->Data.WriteConsoleOutputCharRequest.Unicode ? sizeof(WCHAR) : sizeof(CHAR));
+
+ if (Request->Header.u1.s1.TotalLength
+ < CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE_OUTPUT_CHAR)
+ + (Request->Data.WriteConsoleOutputCharRequest.Length * CharSize))
+ {
+ DPRINT1("Invalid request size\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Status = ConioLockScreenBuffer(ProcessData,
+ Request->Data.WriteConsoleOutputCharRequest.ConsoleHandle,
+ &Buff,
+ GENERIC_WRITE);
+ if (NT_SUCCESS(Status))
+ {
+ Console = Buff->Header.Console;
+ if(Request->Data.WriteConsoleOutputCharRequest.Unicode)
+ {
+ Length = WideCharToMultiByte(Console->OutputCodePage, 0,
+ (PWCHAR)Request->Data.WriteConsoleOutputCharRequest.String,
+ Request->Data.WriteConsoleOutputCharRequest.Length,
+ NULL, 0, NULL, NULL);
+ tmpString = String = RtlAllocateHeap(GetProcessHeap(), 0, Length);
+ if (String)
+ {
+ WideCharToMultiByte(Console->OutputCodePage, 0,
+ (PWCHAR)Request->Data.WriteConsoleOutputCharRequest.String,
+ Request->Data.WriteConsoleOutputCharRequest.Length,
+ String, Length, NULL, NULL);
+ }
+ else
+ {
+ Status = STATUS_NO_MEMORY;
+ }
+ }
+ else
+ {
+ String = (PCHAR)Request->Data.WriteConsoleOutputCharRequest.String;
+ }
+
+ if (String)
+ {
+ if (NT_SUCCESS(Status))
+ {
+ X = Request->Data.WriteConsoleOutputCharRequest.Coord.X;
+ Y = (Request->Data.WriteConsoleOutputCharRequest.Coord.Y + Buff->VirtualY) % Buff->MaxY;
+ Length = Request->Data.WriteConsoleOutputCharRequest.Length;
+ Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
+ while (Length--)
+ {
+ *Buffer = *String++;
+ Written++;
+ Buffer += 2;
+ if (++X == Buff->MaxX)
+ {
+ if (++Y == Buff->MaxY)
+ {
+ Y = 0;
+ Buffer = Buff->Buffer;
+ }
+ X = 0;
+ }
+ }
+ if (Buff == Console->ActiveBuffer)
+ {
+ ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.WriteConsoleOutputCharRequest.Coord,
+ Request->Data.WriteConsoleOutputCharRequest.Length);
+ ConioDrawRegion(Console, &UpdateRect);
+ }
+
+ Request->Data.WriteConsoleOutputCharRequest.EndCoord.X = X;
+ Request->Data.WriteConsoleOutputCharRequest.EndCoord.Y = (Y + Buff->MaxY - Buff->VirtualY) % Buff->MaxY;
+
+ }
+ if (Request->Data.WriteConsoleRequest.Unicode)
+ {
+ RtlFreeHeap(GetProcessHeap(), 0, tmpString);
+ }
+ }
+ ConioUnlockScreenBuffer(Buff);
+ }
+ Request->Data.WriteConsoleOutputCharRequest.NrCharactersWritten = Written;
+ return Status;
+}
+
+CSR_API(CsrFillOutputChar)
+{
+ NTSTATUS Status;
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff;
+ DWORD X, Y, Length, Written = 0;
+ CHAR Char;
+ PBYTE Buffer;
+ SMALL_RECT UpdateRect;
+
+ DPRINT("CsrFillOutputChar\n");
+
+ Status = ConioLockScreenBuffer(ProcessData, Request->Data.FillOutputRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Console = Buff->Header.Console;
+
+ X = Request->Data.FillOutputRequest.Position.X;
+ Y = (Request->Data.FillOutputRequest.Position.Y + Buff->VirtualY) % Buff->MaxY;
+ Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
+ if(Request->Data.FillOutputRequest.Unicode)
+ ConsoleUnicodeCharToAnsiChar(Console, &Char, &Request->Data.FillOutputRequest.Char.UnicodeChar);
+ else
+ Char = Request->Data.FillOutputRequest.Char.AsciiChar;
+ Length = Request->Data.FillOutputRequest.Length;
+ while (Length--)
+ {
+ *Buffer = Char;
+ Buffer += 2;
+ Written++;
+ if (++X == Buff->MaxX)
+ {
+ if (++Y == Buff->MaxY)
+ {
+ Y = 0;
+ Buffer = Buff->Buffer;
+ }
+ X = 0;
+ }
+ }
+
+ if (Buff == Console->ActiveBuffer)
+ {
+ ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.FillOutputRequest.Position,
+ Request->Data.FillOutputRequest.Length);
+ ConioDrawRegion(Console, &UpdateRect);
+ }
+
+ ConioUnlockScreenBuffer(Buff);
+ Length = Request->Data.FillOutputRequest.Length;
+ Request->Data.FillOutputRequest.NrCharactersWritten = Length;
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrWriteConsoleOutputAttrib)
+{
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff;
+ PUCHAR Buffer;
+ PWORD Attribute;
+ int X, Y, Length;
+ NTSTATUS Status;
+ SMALL_RECT UpdateRect;
+
+ DPRINT("CsrWriteConsoleOutputAttrib\n");
+
+ if (Request->Header.u1.s1.TotalLength
+ < CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE_OUTPUT_ATTRIB)
+ + Request->Data.WriteConsoleOutputAttribRequest.Length * sizeof(WORD))
+ {
+ DPRINT1("Invalid request size\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Status = ConioLockScreenBuffer(ProcessData,
+ Request->Data.WriteConsoleOutputAttribRequest.ConsoleHandle,
+ &Buff,
+ GENERIC_WRITE);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Console = Buff->Header.Console;
+
+ X = Request->Data.WriteConsoleOutputAttribRequest.Coord.X;
+ Y = (Request->Data.WriteConsoleOutputAttribRequest.Coord.Y + Buff->VirtualY) % Buff->MaxY;
+ Length = Request->Data.WriteConsoleOutputAttribRequest.Length;
+ Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + 1];
+ Attribute = Request->Data.WriteConsoleOutputAttribRequest.Attribute;
+ while (Length--)
+ {
+ *Buffer = (UCHAR)(*Attribute++);
+ Buffer += 2;
+ if (++X == Buff->MaxX)
+ {
+ if (++Y == Buff->MaxY)
+ {
+ Y = 0;
+ Buffer = Buff->Buffer + 1;
+ }
+ X = 0;
+ }
+ }
+
+ if (Buff == Console->ActiveBuffer)
+ {
+ ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.WriteConsoleOutputAttribRequest.Coord,
+ Request->Data.WriteConsoleOutputAttribRequest.Length);
+ ConioDrawRegion(Console, &UpdateRect);
+ }
+
+ Request->Data.WriteConsoleOutputAttribRequest.EndCoord.X = X;
+ Request->Data.WriteConsoleOutputAttribRequest.EndCoord.Y = (Y + Buff->MaxY - Buff->VirtualY) % Buff->MaxY;
+
+ ConioUnlockScreenBuffer(Buff);
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrFillOutputAttrib)
+{
+ PCSRSS_SCREEN_BUFFER Buff;
+ PUCHAR Buffer;
+ NTSTATUS Status;
+ int X, Y, Length;
+ UCHAR Attr;
+ SMALL_RECT UpdateRect;
+ PCSRSS_CONSOLE Console;
+
+ DPRINT("CsrFillOutputAttrib\n");
+
+ Status = ConioLockScreenBuffer(ProcessData, Request->Data.FillOutputAttribRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Console = Buff->Header.Console;
+
+ X = Request->Data.FillOutputAttribRequest.Coord.X;
+ Y = (Request->Data.FillOutputAttribRequest.Coord.Y + Buff->VirtualY) % Buff->MaxY;
+ Length = Request->Data.FillOutputAttribRequest.Length;
+ Attr = Request->Data.FillOutputAttribRequest.Attribute;
+ Buffer = &Buff->Buffer[(Y * Buff->MaxX * 2) + (X * 2) + 1];
+ while (Length--)
+ {
+ *Buffer = Attr;
+ Buffer += 2;
+ if (++X == Buff->MaxX)
+ {
+ if (++Y == Buff->MaxY)
+ {
+ Y = 0;
+ Buffer = Buff->Buffer + 1;
+ }
+ X = 0;
+ }
+ }
+
+ if (Buff == Console->ActiveBuffer)
+ {
+ ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.FillOutputAttribRequest.Coord,
+ Request->Data.FillOutputAttribRequest.Length);
+ ConioDrawRegion(Console, &UpdateRect);
+ }
+
+ ConioUnlockScreenBuffer(Buff);
+
+ return STATUS_SUCCESS;
+}
+
+DWORD FASTCALL
+ConioEffectiveCursorSize(PCSRSS_CONSOLE Console, DWORD Scale)
+{
+ DWORD Size = (Console->ActiveBuffer->CursorInfo.dwSize * Scale + 99) / 100;
+ /* If line input in progress, perhaps adjust for insert toggle */
+ if (Console->LineBuffer && !Console->LineComplete && Console->LineInsertToggle)
+ return (Size * 2 <= Scale) ? (Size * 2) : (Size / 2);
+ return Size;
+}
+
+CSR_API(CsrGetCursorInfo)
+{
+ PCSRSS_SCREEN_BUFFER Buff;
+ NTSTATUS Status;
+
+ DPRINT("CsrGetCursorInfo\n");
+
+ Status = ConioLockScreenBuffer(ProcessData, Request->Data.GetCursorInfoRequest.ConsoleHandle, &Buff, GENERIC_READ);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Request->Data.GetCursorInfoRequest.Info.bVisible = Buff->CursorInfo.bVisible;
+ Request->Data.GetCursorInfoRequest.Info.dwSize = Buff->CursorInfo.dwSize;
+ ConioUnlockScreenBuffer(Buff);
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrSetCursorInfo)
+{
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff;
+ DWORD Size;
+ BOOL Visible;
+ NTSTATUS Status;
+
+ DPRINT("CsrSetCursorInfo\n");
+
+ Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorInfoRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Console = Buff->Header.Console;
+
+ Size = Request->Data.SetCursorInfoRequest.Info.dwSize;
+ Visible = Request->Data.SetCursorInfoRequest.Info.bVisible;
+ if (Size < 1)
+ {
+ Size = 1;
+ }
+ if (100 < Size)
+ {
+ Size = 100;
+ }
+
+ if (Size != Buff->CursorInfo.dwSize
+ || (Visible && ! Buff->CursorInfo.bVisible) || (! Visible && Buff->CursorInfo.bVisible))
+ {
+ Buff->CursorInfo.dwSize = Size;
+ Buff->CursorInfo.bVisible = Visible;
+
+ if (! ConioSetCursorInfo(Console, Buff))
+ {
+ ConioUnlockScreenBuffer(Buff);
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ ConioUnlockScreenBuffer(Buff);
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrSetTextAttrib)
+{
+ NTSTATUS Status;
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff;
+
+ DPRINT("CsrSetTextAttrib\n");
+
+ Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Console = Buff->Header.Console;
+
+ Buff->DefaultAttrib = Request->Data.SetAttribRequest.Attrib;
+ if (Buff == Console->ActiveBuffer)
+ {
+ if (! ConioUpdateScreenInfo(Console, Buff))
+ {
+ ConioUnlockScreenBuffer(Buff);
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ ConioUnlockScreenBuffer(Buff);
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrCreateScreenBuffer)
+{
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff;
+ NTSTATUS Status;
+
+ DPRINT("CsrCreateScreenBuffer\n");
+
+ RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Buff = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_SCREEN_BUFFER));
+
+ if (Buff != NULL)
+ {
+ if (Console->ActiveBuffer)
+ {
+ Buff->MaxX = Console->ActiveBuffer->MaxX;
+ Buff->MaxY = Console->ActiveBuffer->MaxY;
+ Buff->CursorInfo.bVisible = Console->ActiveBuffer->CursorInfo.bVisible;
+ Buff->CursorInfo.dwSize = Console->ActiveBuffer->CursorInfo.dwSize;
+ }
+ else
+ {
+ Buff->CursorInfo.bVisible = TRUE;
+ Buff->CursorInfo.dwSize = CSR_DEFAULT_CURSOR_SIZE;
+ }
+
+ if (Buff->MaxX == 0)
+ {
+ Buff->MaxX = 80;
+ }
+
+ if (Buff->MaxY == 0)
+ {
+ Buff->MaxY = 25;
+ }
+
+ Status = CsrInitConsoleScreenBuffer(Console, Buff);
+ if (NT_SUCCESS(Status))
+ {
+ Status = Win32CsrInsertObject(ProcessData,
+ &Request->Data.CreateScreenBufferRequest.OutputHandle,
+ &Buff->Header,
+ Request->Data.CreateScreenBufferRequest.Access,
+ Request->Data.CreateScreenBufferRequest.Inheritable,
+ Request->Data.CreateScreenBufferRequest.ShareMode);
+ }
+ }
+ else
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ConioUnlockConsole(Console);
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return Status;
+}
+
+CSR_API(CsrSetScreenBuffer)
+{
+ NTSTATUS Status;
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff;
+
+ DPRINT("CsrSetScreenBuffer\n");
+
+ Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetScreenBufferRequest.OutputHandle, &Buff, GENERIC_WRITE);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Console = Buff->Header.Console;
+
+ if (Buff == Console->ActiveBuffer)
+ {
+ ConioUnlockScreenBuffer(Buff);
+ return STATUS_SUCCESS;
+ }
+
+ /* If old buffer has no handles, it's now unreferenced */
+ if (Console->ActiveBuffer->Header.HandleCount == 0)
+ {
+ ConioDeleteScreenBuffer(Console->ActiveBuffer);
+ }
+ /* tie console to new buffer */
+ Console->ActiveBuffer = Buff;
+ /* Redraw the console */
+ ConioDrawConsole(Console);
+
+ ConioUnlockScreenBuffer(Buff);
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrWriteConsoleOutput)
+{
+ SHORT i, X, Y, SizeX, SizeY;
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff;
+ SMALL_RECT ScreenBuffer;
+ CHAR_INFO* CurCharInfo;
+ SMALL_RECT WriteRegion;
+ CHAR_INFO* CharInfo;
+ COORD BufferCoord;
+ COORD BufferSize;
+ NTSTATUS Status;
+ PBYTE Ptr;
+
+ DPRINT("CsrWriteConsoleOutput\n");
+
+ Status = ConioLockScreenBuffer(ProcessData,
+ Request->Data.WriteConsoleOutputRequest.ConsoleHandle,
+ &Buff,
+ GENERIC_WRITE);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Console = Buff->Header.Console;
+
+ BufferSize = Request->Data.WriteConsoleOutputRequest.BufferSize;
+ BufferCoord = Request->Data.WriteConsoleOutputRequest.BufferCoord;
+ CharInfo = Request->Data.WriteConsoleOutputRequest.CharInfo;
+ if (!Win32CsrValidateBuffer(ProcessData, CharInfo,
+ BufferSize.X * BufferSize.Y, sizeof(CHAR_INFO)))
+ {
+ ConioUnlockScreenBuffer(Buff);
+ return STATUS_ACCESS_VIOLATION;
+ }
+ WriteRegion = Request->Data.WriteConsoleOutputRequest.WriteRegion;
+
+ SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&WriteRegion));
+ SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&WriteRegion));
+ WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
+ WriteRegion.Right = WriteRegion.Left + SizeX - 1;
+
+ /* Make sure WriteRegion is inside the screen buffer */
+ ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
+ if (! ConioGetIntersection(&WriteRegion, &ScreenBuffer, &WriteRegion))
+ {
+ ConioUnlockScreenBuffer(Buff);
+
+ /* It is okay to have a WriteRegion completely outside the screen buffer.
+ No data is written then. */
+ return STATUS_SUCCESS;
+ }
+
+ for (i = 0, Y = WriteRegion.Top; Y <= WriteRegion.Bottom; i++, Y++)
+ {
+ CurCharInfo = CharInfo + (i + BufferCoord.Y) * BufferSize.X + BufferCoord.X;
+ Ptr = ConioCoordToPointer(Buff, WriteRegion.Left, Y);
+ for (X = WriteRegion.Left; X <= WriteRegion.Right; X++)
+ {
+ CHAR AsciiChar;
+ if (Request->Data.WriteConsoleOutputRequest.Unicode)
+ {
+ ConsoleUnicodeCharToAnsiChar(Console, &AsciiChar, &CurCharInfo->Char.UnicodeChar);
+ }
+ else
+ {
+ AsciiChar = CurCharInfo->Char.AsciiChar;
+ }
+ *Ptr++ = AsciiChar;
+ *Ptr++ = CurCharInfo->Attributes;
+ CurCharInfo++;
+ }
+ }
+
+ ConioDrawRegion(Console, &WriteRegion);
+
+ ConioUnlockScreenBuffer(Buff);
+
+ Request->Data.WriteConsoleOutputRequest.WriteRegion.Right = WriteRegion.Left + SizeX - 1;
+ Request->Data.WriteConsoleOutputRequest.WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
+ Request->Data.WriteConsoleOutputRequest.WriteRegion.Left = WriteRegion.Left;
+ Request->Data.WriteConsoleOutputRequest.WriteRegion.Top = WriteRegion.Top;
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrScrollConsoleScreenBuffer)
+{
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff;
+ SMALL_RECT ScreenBuffer;
+ SMALL_RECT SrcRegion;
+ SMALL_RECT DstRegion;
+ SMALL_RECT UpdateRegion;
+ SMALL_RECT ScrollRectangle;
+ SMALL_RECT ClipRectangle;
+ NTSTATUS Status;
+ HANDLE ConsoleHandle;
+ BOOLEAN UseClipRectangle;
+ COORD DestinationOrigin;
+ CHAR_INFO Fill;
+ CHAR FillChar;
+
+ DPRINT("CsrScrollConsoleScreenBuffer\n");
+
+ ConsoleHandle = Request->Data.ScrollConsoleScreenBufferRequest.ConsoleHandle;
+ UseClipRectangle = Request->Data.ScrollConsoleScreenBufferRequest.UseClipRectangle;
+ DestinationOrigin = Request->Data.ScrollConsoleScreenBufferRequest.DestinationOrigin;
+ Fill = Request->Data.ScrollConsoleScreenBufferRequest.Fill;
+
+ Status = ConioLockScreenBuffer(ProcessData, ConsoleHandle, &Buff, GENERIC_WRITE);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Console = Buff->Header.Console;
+
+ ScrollRectangle = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle;
+
+ /* Make sure source rectangle is inside the screen buffer */
+ ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
+ if (! ConioGetIntersection(&SrcRegion, &ScreenBuffer, &ScrollRectangle))
+ {
+ ConioUnlockScreenBuffer(Buff);
+ return STATUS_SUCCESS;
+ }
+
+ /* If the source was clipped on the left or top, adjust the destination accordingly */
+ if (ScrollRectangle.Left < 0)
+ {
+ DestinationOrigin.X -= ScrollRectangle.Left;
+ }
+ if (ScrollRectangle.Top < 0)
+ {
+ DestinationOrigin.Y -= ScrollRectangle.Top;
+ }
+
+ if (UseClipRectangle)
+ {
+ ClipRectangle = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle;
+ if (!ConioGetIntersection(&ClipRectangle, &ClipRectangle, &ScreenBuffer))
+ {
+ ConioUnlockScreenBuffer(Buff);
+ return STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ ClipRectangle = ScreenBuffer;
+ }
+
+ ConioInitRect(&DstRegion,
+ DestinationOrigin.Y,
+ DestinationOrigin.X,
+ DestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
+ DestinationOrigin.X + ConioRectWidth(&SrcRegion) - 1);
+
+ if (Request->Data.ScrollConsoleScreenBufferRequest.Unicode)
+ ConsoleUnicodeCharToAnsiChar(Console, &FillChar, &Fill.Char.UnicodeChar);
+ else
+ FillChar = Fill.Char.AsciiChar;
+
+ ConioMoveRegion(Buff, &SrcRegion, &DstRegion, &ClipRectangle, Fill.Attributes << 8 | (BYTE)FillChar);
+
+ if (Buff == Console->ActiveBuffer)
+ {
+ ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
+ if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &ClipRectangle))
+ {
+ /* Draw update region */
+ ConioDrawRegion(Console, &UpdateRegion);
+ }
+ }
+
+ ConioUnlockScreenBuffer(Buff);
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrReadConsoleOutputChar)
+{
+ NTSTATUS Status;
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff;
+ DWORD Xpos, Ypos;
+ PCHAR ReadBuffer;
+ DWORD i;
+ ULONG CharSize;
+ CHAR Char;
+
+ DPRINT("CsrReadConsoleOutputChar\n");
+
+ ReadBuffer = Request->Data.ReadConsoleOutputCharRequest.String;
+
+ CharSize = (Request->Data.ReadConsoleOutputCharRequest.Unicode ? sizeof(WCHAR) : sizeof(CHAR));
+
+ Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputCharRequest.ConsoleHandle, &Buff, GENERIC_READ);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Console = Buff->Header.Console;
+
+ Xpos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.X;
+ Ypos = (Request->Data.ReadConsoleOutputCharRequest.ReadCoord.Y + Buff->VirtualY) % Buff->MaxY;
+
+ for (i = 0; i < Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead; ++i)
+ {
+ Char = Buff->Buffer[(Xpos * 2) + (Ypos * 2 * Buff->MaxX)];
+
+ if(Request->Data.ReadConsoleOutputCharRequest.Unicode)
+ {
+ ConsoleAnsiCharToUnicodeChar(Console, (WCHAR*)ReadBuffer, &Char);
+ ReadBuffer += sizeof(WCHAR);
+ }
+ else
+ *(ReadBuffer++) = Char;
+
+ Xpos++;
+
+ if (Xpos == Buff->MaxX)
+ {
+ Xpos = 0;
+ Ypos++;
+
+ if (Ypos == Buff->MaxY)
+ {
+ Ypos = 0;
+ }
+ }
+ }
+
+ *ReadBuffer = 0;
+ Request->Data.ReadConsoleOutputCharRequest.EndCoord.X = Xpos;
+ Request->Data.ReadConsoleOutputCharRequest.EndCoord.Y = (Ypos - Buff->VirtualY + Buff->MaxY) % Buff->MaxY;
+
+ ConioUnlockScreenBuffer(Buff);
+
+ Request->Data.ReadConsoleOutputCharRequest.CharsRead = (DWORD)((ULONG_PTR)ReadBuffer - (ULONG_PTR)Request->Data.ReadConsoleOutputCharRequest.String) / CharSize;
+ if (Request->Data.ReadConsoleOutputCharRequest.CharsRead * CharSize + CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_CHAR) > sizeof(CSR_API_MESSAGE))
+ {
+ DPRINT1("Length won't fit in message\n");
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+CSR_API(CsrReadConsoleOutputAttrib)
+{
+ NTSTATUS Status;
+ PCSRSS_SCREEN_BUFFER Buff;
+ DWORD Xpos, Ypos;
+ PWORD ReadBuffer;
+ DWORD i;
+ DWORD CurrentLength;
+
+ DPRINT("CsrReadConsoleOutputAttrib\n");
+
+ ReadBuffer = Request->Data.ReadConsoleOutputAttribRequest.Attribute;
+
+ Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputAttribRequest.ConsoleHandle, &Buff, GENERIC_READ);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Xpos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.X;
+ Ypos = (Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.Y + Buff->VirtualY) % Buff->MaxY;
+
+ for (i = 0; i < Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead; ++i)
+ {
+ *ReadBuffer = Buff->Buffer[(Xpos * 2) + (Ypos * 2 * Buff->MaxX) + 1];
+
+ ReadBuffer++;
+ Xpos++;
+
+ if (Xpos == Buff->MaxX)
+ {
+ Xpos = 0;
+ Ypos++;
+
+ if (Ypos == Buff->MaxY)
+ {
+ Ypos = 0;
+ }
+ }
+ }
+
+ *ReadBuffer = 0;
+
+ Request->Data.ReadConsoleOutputAttribRequest.EndCoord.X = Xpos;
+ Request->Data.ReadConsoleOutputAttribRequest.EndCoord.Y = (Ypos - Buff->VirtualY + Buff->MaxY) % Buff->MaxY;
+
+ ConioUnlockScreenBuffer(Buff);
+
+ CurrentLength = CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_ATTRIB)
+ + Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead * sizeof(WORD);
+ if (CurrentLength > sizeof(CSR_API_MESSAGE))
+ {
+ DPRINT1("Length won't fit in message\n");
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrReadConsoleOutput)
+{
+ PCHAR_INFO CharInfo;
+ PCHAR_INFO CurCharInfo;
+ PCSRSS_SCREEN_BUFFER Buff;
+ DWORD SizeX, SizeY;
+ NTSTATUS Status;
+ COORD BufferSize;
+ COORD BufferCoord;
+ SMALL_RECT ReadRegion;
+ SMALL_RECT ScreenRect;
+ DWORD i;
+ PBYTE Ptr;
+ LONG X, Y;
+ UINT CodePage;
+
+ DPRINT("CsrReadConsoleOutput\n");
+
+ Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputRequest.ConsoleHandle, &Buff, GENERIC_READ);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ CharInfo = Request->Data.ReadConsoleOutputRequest.CharInfo;
+ ReadRegion = Request->Data.ReadConsoleOutputRequest.ReadRegion;
+ BufferSize = Request->Data.ReadConsoleOutputRequest.BufferSize;
+ BufferCoord = Request->Data.ReadConsoleOutputRequest.BufferCoord;
+
+ /* FIXME: Is this correct? */
+ CodePage = ProcessData->Console->OutputCodePage;
+
+ if (!Win32CsrValidateBuffer(ProcessData, CharInfo,
+ BufferSize.X * BufferSize.Y, sizeof(CHAR_INFO)))
+ {
+ ConioUnlockScreenBuffer(Buff);
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&ReadRegion));
+ SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&ReadRegion));
+ ReadRegion.Bottom = ReadRegion.Top + SizeY;
+ ReadRegion.Right = ReadRegion.Left + SizeX;
+
+ ConioInitRect(&ScreenRect, 0, 0, Buff->MaxY, Buff->MaxX);
+ if (! ConioGetIntersection(&ReadRegion, &ScreenRect, &ReadRegion))
+ {
+ ConioUnlockScreenBuffer(Buff);
+ return STATUS_SUCCESS;
+ }
+
+ for (i = 0, Y = ReadRegion.Top; Y < ReadRegion.Bottom; ++i, ++Y)
+ {
+ CurCharInfo = CharInfo + (i * BufferSize.X);
+
+ Ptr = ConioCoordToPointer(Buff, ReadRegion.Left, Y);
+ for (X = ReadRegion.Left; X < ReadRegion.Right; ++X)
+ {
+ if (Request->Data.ReadConsoleOutputRequest.Unicode)
+ {
+ MultiByteToWideChar(CodePage, 0,
+ (PCHAR)Ptr++, 1,
+ &CurCharInfo->Char.UnicodeChar, 1);
+ }
+ else
+ {
+ CurCharInfo->Char.AsciiChar = *Ptr++;
+ }
+ CurCharInfo->Attributes = *Ptr++;
+ ++CurCharInfo;
+ }
+ }
+
+ ConioUnlockScreenBuffer(Buff);
+
+ Request->Data.ReadConsoleOutputRequest.ReadRegion.Right = ReadRegion.Left + SizeX - 1;
+ Request->Data.ReadConsoleOutputRequest.ReadRegion.Bottom = ReadRegion.Top + SizeY - 1;
+ Request->Data.ReadConsoleOutputRequest.ReadRegion.Left = ReadRegion.Left;
+ Request->Data.ReadConsoleOutputRequest.ReadRegion.Top = ReadRegion.Top;
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrSetScreenBufferSize)
+{
+ NTSTATUS Status;
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff;
+
+ Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetScreenBufferSize.OutputHandle, &Buff, GENERIC_WRITE);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Console = Buff->Header.Console;
+
+ Status = ConioResizeBuffer(Console, Buff, Request->Data.SetScreenBufferSize.Size);
+ ConioUnlockScreenBuffer(Buff);
+
+ return Status;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * reactos/subsys/csrss/win32csr/conio.c
+ *
+ * Console I/O functions
+ *
+ * ReactOS Operating System
+ */
+
+/* INCLUDES ******************************************************************/
+
+#define NDEBUG
+#include "w32csr.h"
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+NTSTATUS FASTCALL
+ConioConsoleFromProcessData(PCSR_PROCESS ProcessData, PCSRSS_CONSOLE *Console)
+{
+ PCSRSS_CONSOLE ProcessConsole;
+
+ RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+ ProcessConsole = ProcessData->Console;
+
+ if (!ProcessConsole)
+ {
+ *Console = NULL;
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return STATUS_INVALID_HANDLE;
+ }
+
+ InterlockedIncrement(&ProcessConsole->ReferenceCount);
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ EnterCriticalSection(&(ProcessConsole->Lock));
+ *Console = ProcessConsole;
+
+ return STATUS_SUCCESS;
+}
+
+VOID FASTCALL
+ConioConsoleCtrlEventTimeout(DWORD Event, PCSR_PROCESS ProcessData, DWORD Timeout)
+{
+ HANDLE Thread;
+
+ DPRINT("ConioConsoleCtrlEvent Parent ProcessId = %x\n", ProcessData->ClientId.UniqueProcess);
+
+ if (ProcessData->CtrlDispatcher)
+ {
+
+ Thread = CreateRemoteThread(ProcessData->ProcessHandle, NULL, 0,
+ (LPTHREAD_START_ROUTINE) ProcessData->CtrlDispatcher,
+ UlongToPtr(Event), 0, NULL);
+ if (NULL == Thread)
+ {
+ DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
+ return;
+ }
+ WaitForSingleObject(Thread, Timeout);
+ CloseHandle(Thread);
+ }
+}
+
+VOID FASTCALL
+ConioConsoleCtrlEvent(DWORD Event, PCSR_PROCESS ProcessData)
+{
+ ConioConsoleCtrlEventTimeout(Event, ProcessData, 0);
+}
+
+static NTSTATUS WINAPI
+CsrInitConsole(PCSRSS_CONSOLE Console, int ShowCmd)
+{
+ NTSTATUS Status;
+ SECURITY_ATTRIBUTES SecurityAttributes;
+ PCSRSS_SCREEN_BUFFER NewBuffer;
+ BOOL GuiMode;
+ WCHAR Title[255];
+ HINSTANCE hInst;
+
+ Console->Title.MaximumLength = Console->Title.Length = 0;
+ Console->Title.Buffer = NULL;
+
+ hInst = GetModuleHandleW(L"win32csr");
+ if (LoadStringW(hInst,IDS_COMMAND_PROMPT,Title,sizeof(Title)/sizeof(Title[0])))
+ {
+ RtlCreateUnicodeString(&Console->Title, Title);
+ }
+ else
+ {
+ RtlCreateUnicodeString(&Console->Title, L"Command Prompt");
+ }
+
+ Console->ReferenceCount = 0;
+ Console->LineBuffer = NULL;
+ Console->Header.Type = CONIO_CONSOLE_MAGIC;
+ Console->Header.Console = Console;
+ Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
+ InitializeListHead(&Console->BufferList);
+ Console->ActiveBuffer = NULL;
+ InitializeListHead(&Console->InputEvents);
+ InitializeListHead(&Console->HistoryBuffers);
+ Console->CodePage = GetOEMCP();
+ Console->OutputCodePage = GetOEMCP();
+
+ SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+ SecurityAttributes.lpSecurityDescriptor = NULL;
+ SecurityAttributes.bInheritHandle = TRUE;
+
+ Console->ActiveEvent = CreateEventW(&SecurityAttributes, TRUE, FALSE, NULL);
+ if (NULL == Console->ActiveEvent)
+ {
+ RtlFreeUnicodeString(&Console->Title);
+ return STATUS_UNSUCCESSFUL;
+ }
+ Console->PrivateData = NULL;
+ InitializeCriticalSection(&Console->Lock);
+
+ GuiMode = DtbgIsDesktopVisible();
+
+ /* allocate console screen buffer */
+ NewBuffer = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_SCREEN_BUFFER));
+ if (NULL == NewBuffer)
+ {
+ RtlFreeUnicodeString(&Console->Title);
+ DeleteCriticalSection(&Console->Lock);
+ CloseHandle(Console->ActiveEvent);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ /* init screen buffer with defaults */
+ NewBuffer->CursorInfo.bVisible = TRUE;
+ NewBuffer->CursorInfo.dwSize = CSR_DEFAULT_CURSOR_SIZE;
+ /* make console active, and insert into console list */
+ Console->ActiveBuffer = (PCSRSS_SCREEN_BUFFER) NewBuffer;
+
+ /*
+ * If we are not in GUI-mode, start the text-mode console. If we fail,
+ * try to start the GUI-mode console (win32k will automatically switch
+ * to graphical mode, therefore no additional code is needed).
+ */
+ if (!GuiMode)
+ {
+ DPRINT1("WIN32CSR: Opening text-mode console\n");
+ Status = TuiInitConsole(Console);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to open text-mode console, switching to gui-mode, Status = 0x%08lx\n", Status);
+ GuiMode = TRUE;
+ }
+ }
+
+ /*
+ * Try to open the GUI-mode console. Two cases are possible:
+ * - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case
+ * failed and we start GUI-mode console.
+ * - We are in text-mode, therefore GuiMode == FALSE, the previous test-case
+ * succeeded BUT we failed at starting text-mode console. Then GuiMode
+ * was switched to TRUE in order to try to open the console in GUI-mode.
+ */
+ if (GuiMode)
+ {
+ DPRINT1("WIN32CSR: Opening GUI-mode console\n");
+ Status = GuiInitConsole(Console, ShowCmd);
+ if (!NT_SUCCESS(Status))
+ {
+ HeapFree(Win32CsrApiHeap,0, NewBuffer);
+ RtlFreeUnicodeString(&Console->Title);
+ DeleteCriticalSection(&Console->Lock);
+ CloseHandle(Console->ActiveEvent);
+ DPRINT1("GuiInitConsole: failed, Status = 0x%08lx\n", Status);
+ return Status;
+ }
+ }
+
+ Status = CsrInitConsoleScreenBuffer(Console, NewBuffer);
+ if (!NT_SUCCESS(Status))
+ {
+ ConioCleanupConsole(Console);
+ RtlFreeUnicodeString(&Console->Title);
+ DeleteCriticalSection(&Console->Lock);
+ CloseHandle(Console->ActiveEvent);
+ HeapFree(Win32CsrApiHeap, 0, NewBuffer);
+ DPRINT1("CsrInitConsoleScreenBuffer: failed\n");
+ return Status;
+ }
+
+ /* copy buffer contents to screen */
+ ConioDrawConsole(Console);
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrAllocConsole)
+{
+ PCSRSS_CONSOLE Console;
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOLEAN NewConsole = FALSE;
+
+ DPRINT("CsrAllocConsole\n");
+
+ RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+ if (ProcessData->Console)
+ {
+ DPRINT1("Process already has a console\n");
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* If we don't need a console, then get out of here */
+ if (!Request->Data.AllocConsoleRequest.ConsoleNeeded)
+ {
+ DPRINT("No console needed\n");
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return STATUS_SUCCESS;
+ }
+
+ /* If we already have one, then don't create a new one... */
+ if (!Request->Data.AllocConsoleRequest.Console ||
+ Request->Data.AllocConsoleRequest.Console != ProcessData->ParentConsole)
+ {
+ /* Allocate a console structure */
+ NewConsole = TRUE;
+ Console = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_CONSOLE));
+ if (NULL == Console)
+ {
+ DPRINT1("Not enough memory for console\n");
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return STATUS_NO_MEMORY;
+ }
+ /* initialize list head */
+ InitializeListHead(&Console->ProcessList);
+ /* insert process data required for GUI initialization */
+ InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink);
+ /* Initialize the Console */
+ Status = CsrInitConsole(Console, Request->Data.AllocConsoleRequest.ShowCmd);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Console init failed\n");
+ HeapFree(Win32CsrApiHeap, 0, Console);
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return Status;
+ }
+ }
+ else
+ {
+ /* Reuse our current console */
+ Console = Request->Data.AllocConsoleRequest.Console;
+ }
+
+ /* Set the Process Console */
+ ProcessData->Console = Console;
+
+ /* Return it to the caller */
+ Request->Data.AllocConsoleRequest.Console = Console;
+
+ /* Add a reference count because the process is tied to the console */
+ _InterlockedIncrement(&Console->ReferenceCount);
+
+ if (NewConsole || !ProcessData->bInheritHandles)
+ {
+ /* Insert the Objects */
+ Status = Win32CsrInsertObject(ProcessData,
+ &Request->Data.AllocConsoleRequest.InputHandle,
+ &Console->Header,
+ GENERIC_READ | GENERIC_WRITE,
+ TRUE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE);
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to insert object\n");
+ ConioDeleteConsole((Object_t *) Console);
+ ProcessData->Console = 0;
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return Status;
+ }
+
+ Status = Win32CsrInsertObject(ProcessData,
+ &Request->Data.AllocConsoleRequest.OutputHandle,
+ &Console->ActiveBuffer->Header,
+ GENERIC_READ | GENERIC_WRITE,
+ TRUE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to insert object\n");
+ ConioDeleteConsole((Object_t *) Console);
+ Win32CsrReleaseObject(ProcessData,
+ Request->Data.AllocConsoleRequest.InputHandle);
+ ProcessData->Console = 0;
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return Status;
+ }
+ }
+
+ /* Duplicate the Event */
+ if (!DuplicateHandle(GetCurrentProcess(),
+ ProcessData->Console->ActiveEvent,
+ ProcessData->ProcessHandle,
+ &ProcessData->ConsoleEvent,
+ EVENT_ALL_ACCESS,
+ FALSE,
+ 0))
+ {
+ DPRINT1("DuplicateHandle() failed: %lu\n", GetLastError());
+ ConioDeleteConsole((Object_t *) Console);
+ if (NewConsole || !ProcessData->bInheritHandles)
+ {
+ Win32CsrReleaseObject(ProcessData,
+ Request->Data.AllocConsoleRequest.OutputHandle);
+ Win32CsrReleaseObject(ProcessData,
+ Request->Data.AllocConsoleRequest.InputHandle);
+ }
+ ProcessData->Console = 0;
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return Status;
+ }
+
+ /* Set the Ctrl Dispatcher */
+ ProcessData->CtrlDispatcher = Request->Data.AllocConsoleRequest.CtrlDispatcher;
+ DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
+
+ if (!NewConsole)
+ {
+ /* Insert into the list if it has not been added */
+ InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
+ }
+
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrFreeConsole)
+{
+ Win32CsrReleaseConsole(ProcessData);
+ return STATUS_SUCCESS;
+}
+
+VOID WINAPI
+ConioDeleteConsole(Object_t *Object)
+{
+ PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Object;
+ ConsoleInput *Event;
+
+ DPRINT("ConioDeleteConsole\n");
+
+ /* Drain input event queue */
+ while (Console->InputEvents.Flink != &Console->InputEvents)
+ {
+ Event = (ConsoleInput *) Console->InputEvents.Flink;
+ Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
+ Console->InputEvents.Flink->Flink->Blink = &Console->InputEvents;
+ HeapFree(Win32CsrApiHeap, 0, Event);
+ }
+
+ ConioCleanupConsole(Console);
+ if (Console->LineBuffer)
+ RtlFreeHeap(Win32CsrApiHeap, 0, Console->LineBuffer);
+ while (!IsListEmpty(&Console->HistoryBuffers))
+ HistoryDeleteBuffer((struct tagHISTORY_BUFFER *)Console->HistoryBuffers.Flink);
+
+ ConioDeleteScreenBuffer(Console->ActiveBuffer);
+ if (!IsListEmpty(&Console->BufferList))
+ {
+ DPRINT1("BUG: screen buffer list not empty\n");
+ }
+
+ CloseHandle(Console->ActiveEvent);
+ if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
+ DeleteCriticalSection(&Console->Lock);
+ RtlFreeUnicodeString(&Console->Title);
+ IntDeleteAllAliases(Console->Aliases);
+ HeapFree(Win32CsrApiHeap, 0, Console);
+}
+
+VOID WINAPI
+CsrInitConsoleSupport(VOID)
+{
+ DPRINT("CSR: CsrInitConsoleSupport()\n");
+
+ /* Should call LoadKeyboardLayout */
+}
+
+VOID FASTCALL
+ConioPause(PCSRSS_CONSOLE Console, UINT Flags)
+{
+ Console->PauseFlags |= Flags;
+ if (!Console->UnpauseEvent)
+ Console->UnpauseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+}
+
+VOID FASTCALL
+ConioUnpause(PCSRSS_CONSOLE Console, UINT Flags)
+{
+ Console->PauseFlags &= ~Flags;
+ if (Console->PauseFlags == 0 && Console->UnpauseEvent)
+ {
+ SetEvent(Console->UnpauseEvent);
+ CloseHandle(Console->UnpauseEvent);
+ Console->UnpauseEvent = NULL;
+ }
+}
+
+CSR_API(CsrSetConsoleMode)
+{
+ NTSTATUS Status;
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff;
+
+ DPRINT("CsrSetConsoleMode\n");
+
+ Status = Win32CsrLockObject(ProcessData,
+ Request->Data.SetConsoleModeRequest.ConsoleHandle,
+ (Object_t **) &Console, GENERIC_WRITE, 0);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Buff = (PCSRSS_SCREEN_BUFFER)Console;
+ if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
+ {
+ Console->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_INPUT_MODE_VALID;
+ }
+ else if (CONIO_SCREEN_BUFFER_MAGIC == Console->Header.Type)
+ {
+ Buff->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_OUTPUT_MODE_VALID;
+ }
+ else
+ {
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ Win32CsrUnlockObject((Object_t *)Console);
+
+ return Status;
+}
+
+CSR_API(CsrGetConsoleMode)
+{
+ NTSTATUS Status;
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff; /* gee, I really wish I could use an anonymous union here */
+
+ DPRINT("CsrGetConsoleMode\n");
+
+ Status = Win32CsrLockObject(ProcessData, Request->Data.GetConsoleModeRequest.ConsoleHandle,
+ (Object_t **) &Console, GENERIC_READ, 0);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ Status = STATUS_SUCCESS;
+ Buff = (PCSRSS_SCREEN_BUFFER) Console;
+ if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
+ {
+ Request->Data.GetConsoleModeRequest.ConsoleMode = Console->Mode;
+ }
+ else if (CONIO_SCREEN_BUFFER_MAGIC == Buff->Header.Type)
+ {
+ Request->Data.GetConsoleModeRequest.ConsoleMode = Buff->Mode;
+ }
+ else
+ {
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ Win32CsrUnlockObject((Object_t *)Console);
+ return Status;
+}
+
+CSR_API(CsrSetTitle)
+{
+ NTSTATUS Status;
+ PCSRSS_CONSOLE Console;
+ PWCHAR Buffer;
+
+ DPRINT("CsrSetTitle\n");
+
+ if (!Win32CsrValidateBuffer(ProcessData, Request->Data.SetTitleRequest.Title,
+ Request->Data.SetTitleRequest.Length, 1))
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if(NT_SUCCESS(Status))
+ {
+ Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Request->Data.SetTitleRequest.Length);
+ if (Buffer)
+ {
+ /* copy title to console */
+ RtlFreeUnicodeString(&Console->Title);
+ Console->Title.Buffer = Buffer;
+ Console->Title.Length = Console->Title.MaximumLength = Request->Data.SetTitleRequest.Length;
+ memcpy(Console->Title.Buffer, Request->Data.SetTitleRequest.Title, Console->Title.Length);
+ if (! ConioChangeTitle(Console))
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ Status = STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ Status = STATUS_NO_MEMORY;
+ }
+ ConioUnlockConsole(Console);
+ }
+
+ return Status;
+}
+
+CSR_API(CsrGetTitle)
+{
+ NTSTATUS Status;
+ PCSRSS_CONSOLE Console;
+ DWORD Length;
+
+ DPRINT("CsrGetTitle\n");
+
+
+ if (!Win32CsrValidateBuffer(ProcessData, Request->Data.GetTitleRequest.Title,
+ Request->Data.GetTitleRequest.Length, 1))
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("Can't get console\n");
+ return Status;
+ }
+
+ /* Copy title of the console to the user title buffer */
+ if (Request->Data.GetTitleRequest.Length >= sizeof(WCHAR))
+ {
+ Length = min(Request->Data.GetTitleRequest.Length - sizeof(WCHAR), Console->Title.Length);
+ memcpy(Request->Data.GetTitleRequest.Title, Console->Title.Buffer, Length);
+ Request->Data.GetTitleRequest.Title[Length / sizeof(WCHAR)] = L'\0';
+ }
+
+ Request->Data.GetTitleRequest.Length = Console->Title.Length;
+
+ ConioUnlockConsole(Console);
+ return STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ * HardwareStateProperty
+ *
+ * DESCRIPTION
+ * Set/Get the value of the HardwareState and switch
+ * between direct video buffer ouput and GDI windowed
+ * output.
+ * ARGUMENTS
+ * Client hands us a CSRSS_CONSOLE_HARDWARE_STATE
+ * object. We use the same object to Request.
+ * NOTE
+ * ConsoleHwState has the correct size to be compatible
+ * with NT's, but values are not.
+ */
+static NTSTATUS FASTCALL
+SetConsoleHardwareState (PCSRSS_CONSOLE Console, DWORD ConsoleHwState)
+{
+ DPRINT1("Console Hardware State: %d\n", ConsoleHwState);
+
+ if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState)
+ ||(CONSOLE_HARDWARE_STATE_DIRECT == ConsoleHwState))
+ {
+ if (Console->HardwareState != ConsoleHwState)
+ {
+ /* TODO: implement switching from full screen to windowed mode */
+ /* TODO: or back; now simply store the hardware state */
+ Console->HardwareState = ConsoleHwState;
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ return STATUS_INVALID_PARAMETER_3; /* Client: (handle, set_get, [mode]) */
+}
+
+CSR_API(CsrHardwareStateProperty)
+{
+ PCSRSS_CONSOLE Console;
+ NTSTATUS Status;
+
+ DPRINT("CsrHardwareStateProperty\n");
+
+ Status = ConioLockConsole(ProcessData,
+ Request->Data.ConsoleHardwareStateRequest.ConsoleHandle,
+ &Console,
+ GENERIC_READ);
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to get console handle in SetConsoleHardwareState\n");
+ return Status;
+ }
+
+ switch (Request->Data.ConsoleHardwareStateRequest.SetGet)
+ {
+ case CONSOLE_HARDWARE_STATE_GET:
+ Request->Data.ConsoleHardwareStateRequest.State = Console->HardwareState;
+ break;
+
+ case CONSOLE_HARDWARE_STATE_SET:
+ DPRINT("Setting console hardware state.\n");
+ Status = SetConsoleHardwareState(Console, Request->Data.ConsoleHardwareStateRequest.State);
+ break;
+
+ default:
+ Status = STATUS_INVALID_PARAMETER_2; /* Client: (handle, [set_get], mode) */
+ break;
+ }
+
+ ConioUnlockConsole(Console);
+
+ return Status;
+}
+
+CSR_API(CsrGetConsoleWindow)
+{
+ PCSRSS_CONSOLE Console;
+ NTSTATUS Status;
+
+ DPRINT("CsrGetConsoleWindow\n");
+
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Request->Data.GetConsoleWindowRequest.WindowHandle = Console->hWindow;
+ ConioUnlockConsole(Console);
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrSetConsoleIcon)
+{
+ PCSRSS_CONSOLE Console;
+ NTSTATUS Status;
+
+ DPRINT("CsrSetConsoleIcon\n");
+
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Status = (ConioChangeIcon(Console, Request->Data.SetConsoleIconRequest.WindowIcon)
+ ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
+ ConioUnlockConsole(Console);
+
+ return Status;
+}
+
+CSR_API(CsrGetConsoleCodePage)
+{
+ PCSRSS_CONSOLE Console;
+ NTSTATUS Status;
+
+ DPRINT("CsrGetConsoleCodePage\n");
+
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Request->Data.GetConsoleCodePage.CodePage = Console->CodePage;
+ ConioUnlockConsole(Console);
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrSetConsoleCodePage)
+{
+ PCSRSS_CONSOLE Console;
+ NTSTATUS Status;
+
+ DPRINT("CsrSetConsoleCodePage\n");
+
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ if (IsValidCodePage(Request->Data.SetConsoleCodePage.CodePage))
+ {
+ Console->CodePage = Request->Data.SetConsoleCodePage.CodePage;
+ ConioUnlockConsole(Console);
+ return STATUS_SUCCESS;
+ }
+
+ ConioUnlockConsole(Console);
+ return STATUS_INVALID_PARAMETER;
+}
+
+CSR_API(CsrGetConsoleOutputCodePage)
+{
+ PCSRSS_CONSOLE Console;
+ NTSTATUS Status;
+
+ DPRINT("CsrGetConsoleOutputCodePage\n");
+
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Request->Data.GetConsoleOutputCodePage.CodePage = Console->OutputCodePage;
+ ConioUnlockConsole(Console);
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrSetConsoleOutputCodePage)
+{
+ PCSRSS_CONSOLE Console;
+ NTSTATUS Status;
+
+ DPRINT("CsrSetConsoleOutputCodePage\n");
+
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ if (IsValidCodePage(Request->Data.SetConsoleOutputCodePage.CodePage))
+ {
+ Console->OutputCodePage = Request->Data.SetConsoleOutputCodePage.CodePage;
+ ConioUnlockConsole(Console);
+ return STATUS_SUCCESS;
+ }
+
+ ConioUnlockConsole(Console);
+ return STATUS_INVALID_PARAMETER;
+}
+
+CSR_API(CsrGetProcessList)
+{
+ PDWORD Buffer;
+ PCSRSS_CONSOLE Console;
+ PCSR_PROCESS current;
+ PLIST_ENTRY current_entry;
+ ULONG nItems = 0;
+ NTSTATUS Status;
+
+ DPRINT("CsrGetProcessList\n");
+
+ Buffer = Request->Data.GetProcessListRequest.ProcessId;
+ if (!Win32CsrValidateBuffer(ProcessData, Buffer, Request->Data.GetProcessListRequest.nMaxIds, sizeof(DWORD)))
+ return STATUS_ACCESS_VIOLATION;
+
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ for (current_entry = Console->ProcessList.Flink;
+ current_entry != &Console->ProcessList;
+ current_entry = current_entry->Flink)
+ {
+ current = CONTAINING_RECORD(current_entry, CSR_PROCESS, ConsoleLink);
+ if (++nItems <= Request->Data.GetProcessListRequest.nMaxIds)
+ {
+ *Buffer++ = HandleToUlong(current->ClientId.UniqueProcess);
+ }
+ }
+
+ ConioUnlockConsole(Console);
+
+ Request->Data.GetProcessListRequest.nProcessIdsTotal = nItems;
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrGenerateCtrlEvent)
+{
+ PCSRSS_CONSOLE Console;
+ PCSR_PROCESS current;
+ PLIST_ENTRY current_entry;
+ DWORD Group;
+ NTSTATUS Status;
+
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Group = Request->Data.GenerateCtrlEvent.ProcessGroup;
+ Status = STATUS_INVALID_PARAMETER;
+ for (current_entry = Console->ProcessList.Flink;
+ current_entry != &Console->ProcessList;
+ current_entry = current_entry->Flink)
+ {
+ current = CONTAINING_RECORD(current_entry, CSR_PROCESS, ConsoleLink);
+ if (Group == 0 || current->ProcessGroupId == Group)
+ {
+ ConioConsoleCtrlEvent(Request->Data.GenerateCtrlEvent.Event, current);
+ Status = STATUS_SUCCESS;
+ }
+ }
+
+ ConioUnlockConsole(Console);
+
+ return Status;
+}
+
+CSR_API(CsrGetConsoleSelectionInfo)
+{
+ NTSTATUS Status;
+ PCSRSS_CONSOLE Console;
+
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (NT_SUCCESS(Status))
+ {
+ memset(&Request->Data.GetConsoleSelectionInfo.Info, 0, sizeof(CONSOLE_SELECTION_INFO));
+ if (Console->Selection.dwFlags != 0)
+ Request->Data.GetConsoleSelectionInfo.Info = Console->Selection;
+ ConioUnlockConsole(Console);
+ }
+ return Status;
+}
+
+/* EOF */
--- /dev/null
+#define NDEBUG
+
+#include "w32csr.h"
+#include <debug.h>
+
+CSR_API(CsrCreateDesktop)
+{
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrShowDesktop)
+{
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrHideDesktop)
+{
+ return STATUS_SUCCESS;
+}
+
+BOOL
+FASTCALL DtbgIsDesktopVisible(VOID)
+{
+ return !((BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE));
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: subsys/csrss/include/destkopbg.h
+ * PURPOSE: CSRSS internal desktop background window interface
+ */
+
+#pragma once
+
+#include "api.h"
+
+/* Api functions */
+CSR_API(CsrCreateDesktop);
+CSR_API(CsrShowDesktop);
+CSR_API(CsrHideDesktop);
+CSR_API(CsrRegisterSystemClasses);
+
+BOOL FASTCALL DtbgIsDesktopVisible(VOID);
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: subsys/csrss/win32csr/dllmain.c
+ * PURPOSE: Initialization
+ * PROGRAMMERS: Dmitry Philippov (shedon@mail.ru)
+ */
+
+/* INCLUDES ******************************************************************/
+#define NDEBUG
+#include "w32csr.h"
+#include "file.h"
+#include <debug.h>
+
+/* Not defined in any header file */
+extern VOID WINAPI PrivateCsrssManualGuiCheck(LONG Check);
+extern LIST_ENTRY DosDeviceHistory;
+extern RTL_CRITICAL_SECTION Win32CsrDefineDosDeviceCritSec;
+
+/* GLOBALS *******************************************************************/
+
+HANDLE Win32CsrApiHeap;
+HINSTANCE Win32CsrDllHandle = NULL;
+
+static CSRSS_API_DEFINITION Win32CsrApiDefinitions[] =
+{
+ CSRSS_DEFINE_API(GET_INPUT_HANDLE, CsrGetHandle),
+ CSRSS_DEFINE_API(GET_OUTPUT_HANDLE, CsrGetHandle),
+ CSRSS_DEFINE_API(CLOSE_HANDLE, CsrCloseHandle),
+ CSRSS_DEFINE_API(VERIFY_HANDLE, CsrVerifyHandle),
+ CSRSS_DEFINE_API(DUPLICATE_HANDLE, CsrDuplicateHandle),
+ CSRSS_DEFINE_API(GET_INPUT_WAIT_HANDLE, CsrGetInputWaitHandle),
+ CSRSS_DEFINE_API(WRITE_CONSOLE, CsrWriteConsole),
+ CSRSS_DEFINE_API(READ_CONSOLE, CsrReadConsole),
+ CSRSS_DEFINE_API(ALLOC_CONSOLE, CsrAllocConsole),
+ CSRSS_DEFINE_API(FREE_CONSOLE, CsrFreeConsole),
+ CSRSS_DEFINE_API(SCREEN_BUFFER_INFO, CsrGetScreenBufferInfo),
+ CSRSS_DEFINE_API(SET_CURSOR, CsrSetCursor),
+ CSRSS_DEFINE_API(FILL_OUTPUT, CsrFillOutputChar),
+ CSRSS_DEFINE_API(READ_INPUT, CsrReadInputEvent),
+ CSRSS_DEFINE_API(WRITE_CONSOLE_OUTPUT_CHAR, CsrWriteConsoleOutputChar),
+ CSRSS_DEFINE_API(WRITE_CONSOLE_OUTPUT_ATTRIB, CsrWriteConsoleOutputAttrib),
+ CSRSS_DEFINE_API(FILL_OUTPUT_ATTRIB, CsrFillOutputAttrib),
+ CSRSS_DEFINE_API(GET_CURSOR_INFO, CsrGetCursorInfo),
+ CSRSS_DEFINE_API(SET_CURSOR_INFO, CsrSetCursorInfo),
+ CSRSS_DEFINE_API(SET_ATTRIB, CsrSetTextAttrib),
+ CSRSS_DEFINE_API(GET_CONSOLE_MODE, CsrGetConsoleMode),
+ CSRSS_DEFINE_API(SET_CONSOLE_MODE, CsrSetConsoleMode),
+ CSRSS_DEFINE_API(CREATE_SCREEN_BUFFER, CsrCreateScreenBuffer),
+ CSRSS_DEFINE_API(SET_SCREEN_BUFFER, CsrSetScreenBuffer),
+ CSRSS_DEFINE_API(SET_TITLE, CsrSetTitle),
+ CSRSS_DEFINE_API(GET_TITLE, CsrGetTitle),
+ CSRSS_DEFINE_API(WRITE_CONSOLE_OUTPUT, CsrWriteConsoleOutput),
+ CSRSS_DEFINE_API(FLUSH_INPUT_BUFFER, CsrFlushInputBuffer),
+ CSRSS_DEFINE_API(SCROLL_CONSOLE_SCREEN_BUFFER, CsrScrollConsoleScreenBuffer),
+ CSRSS_DEFINE_API(READ_CONSOLE_OUTPUT_CHAR, CsrReadConsoleOutputChar),
+ CSRSS_DEFINE_API(READ_CONSOLE_OUTPUT_ATTRIB, CsrReadConsoleOutputAttrib),
+ CSRSS_DEFINE_API(GET_NUM_INPUT_EVENTS, CsrGetNumberOfConsoleInputEvents),
+ CSRSS_DEFINE_API(EXIT_REACTOS, CsrExitReactos),
+ CSRSS_DEFINE_API(PEEK_CONSOLE_INPUT, CsrPeekConsoleInput),
+ CSRSS_DEFINE_API(READ_CONSOLE_OUTPUT, CsrReadConsoleOutput),
+ CSRSS_DEFINE_API(WRITE_CONSOLE_INPUT, CsrWriteConsoleInput),
+ CSRSS_DEFINE_API(SETGET_CONSOLE_HW_STATE, CsrHardwareStateProperty),
+ CSRSS_DEFINE_API(GET_CONSOLE_WINDOW, CsrGetConsoleWindow),
+ CSRSS_DEFINE_API(CREATE_DESKTOP, CsrCreateDesktop),
+ CSRSS_DEFINE_API(SHOW_DESKTOP, CsrShowDesktop),
+ CSRSS_DEFINE_API(HIDE_DESKTOP, CsrHideDesktop),
+ CSRSS_DEFINE_API(SET_CONSOLE_ICON, CsrSetConsoleIcon),
+ CSRSS_DEFINE_API(SET_LOGON_NOTIFY_WINDOW, CsrSetLogonNotifyWindow),
+ CSRSS_DEFINE_API(REGISTER_LOGON_PROCESS, CsrRegisterLogonProcess),
+ CSRSS_DEFINE_API(GET_CONSOLE_CP, CsrGetConsoleCodePage),
+ CSRSS_DEFINE_API(SET_CONSOLE_CP, CsrSetConsoleCodePage),
+ CSRSS_DEFINE_API(GET_CONSOLE_OUTPUT_CP, CsrGetConsoleOutputCodePage),
+ CSRSS_DEFINE_API(SET_CONSOLE_OUTPUT_CP, CsrSetConsoleOutputCodePage),
+ CSRSS_DEFINE_API(GET_PROCESS_LIST, CsrGetProcessList),
+ CSRSS_DEFINE_API(ADD_CONSOLE_ALIAS, CsrAddConsoleAlias),
+ CSRSS_DEFINE_API(GET_CONSOLE_ALIAS, CsrGetConsoleAlias),
+ CSRSS_DEFINE_API(GET_ALL_CONSOLE_ALIASES, CsrGetAllConsoleAliases),
+ CSRSS_DEFINE_API(GET_ALL_CONSOLE_ALIASES_LENGTH, CsrGetAllConsoleAliasesLength),
+ CSRSS_DEFINE_API(GET_CONSOLE_ALIASES_EXES, CsrGetConsoleAliasesExes),
+ CSRSS_DEFINE_API(GET_CONSOLE_ALIASES_EXES_LENGTH, CsrGetConsoleAliasesExesLength),
+ CSRSS_DEFINE_API(GENERATE_CTRL_EVENT, CsrGenerateCtrlEvent),
+ CSRSS_DEFINE_API(SET_SCREEN_BUFFER_SIZE, CsrSetScreenBufferSize),
+ CSRSS_DEFINE_API(GET_CONSOLE_SELECTION_INFO, CsrGetConsoleSelectionInfo),
+ CSRSS_DEFINE_API(GET_COMMAND_HISTORY_LENGTH, CsrGetCommandHistoryLength),
+ CSRSS_DEFINE_API(GET_COMMAND_HISTORY, CsrGetCommandHistory),
+ CSRSS_DEFINE_API(EXPUNGE_COMMAND_HISTORY, CsrExpungeCommandHistory),
+ CSRSS_DEFINE_API(SET_HISTORY_NUMBER_COMMANDS, CsrSetHistoryNumberCommands),
+ CSRSS_DEFINE_API(GET_HISTORY_INFO, CsrGetHistoryInfo),
+ CSRSS_DEFINE_API(SET_HISTORY_INFO, CsrSetHistoryInfo),
+ CSRSS_DEFINE_API(GET_TEMP_FILE, CsrGetTempFile),
+ CSRSS_DEFINE_API(DEFINE_DOS_DEVICE, CsrDefineDosDevice),
+ CSRSS_DEFINE_API(SOUND_SENTRY, CsrSoundSentry),
+ { 0, 0, NULL }
+};
+
+static HHOOK hhk = NULL;
+
+/* FUNCTIONS *****************************************************************/
+
+LRESULT
+CALLBACK
+KeyboardHookProc(
+ int nCode,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ return CallNextHookEx(hhk, nCode, wParam, lParam);
+}
+
+ULONG
+InitializeVideoAddressSpace(VOID)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING PhysMemName = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
+ NTSTATUS Status;
+ HANDLE PhysMemHandle;
+ PVOID BaseAddress;
+ LARGE_INTEGER Offset;
+ SIZE_T ViewSize;
+ CHAR IVTAndBda[1024+256];
+
+ /* Free the 1MB pre-reserved region. In reality, ReactOS should simply support us mapping the view into the reserved area, but it doesn't. */
+ BaseAddress = 0;
+ ViewSize = 1024 * 1024;
+ Status = ZwFreeVirtualMemory(NtCurrentProcess(),
+ &BaseAddress,
+ &ViewSize,
+ MEM_RELEASE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Couldn't unmap reserved memory (%x)\n", Status);
+ return 0;
+ }
+
+ /* Open the physical memory section */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &PhysMemName,
+ 0,
+ NULL,
+ NULL);
+ Status = ZwOpenSection(&PhysMemHandle,
+ SECTION_ALL_ACCESS,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Couldn't open \\Device\\PhysicalMemory\n");
+ return 0;
+ }
+
+ /* Map the BIOS and device registers into the address space */
+ Offset.QuadPart = 0xa0000;
+ ViewSize = 0x100000 - 0xa0000;
+ BaseAddress = (PVOID)0xa0000;
+ Status = ZwMapViewOfSection(PhysMemHandle,
+ NtCurrentProcess(),
+ &BaseAddress,
+ 0,
+ ViewSize,
+ &Offset,
+ &ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_EXECUTE_READWRITE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Couldn't map physical memory (%x)\n", Status);
+ ZwClose(PhysMemHandle);
+ return 0;
+ }
+
+ /* Close physical memory section handle */
+ ZwClose(PhysMemHandle);
+
+ if (BaseAddress != (PVOID)0xa0000)
+ {
+ DPRINT1("Couldn't map physical memory at the right address (was %x)\n",
+ BaseAddress);
+ return 0;
+ }
+
+ /* Allocate some low memory to use for the non-BIOS
+ * parts of the v86 mode address space
+ */
+ BaseAddress = (PVOID)0x1;
+ ViewSize = 0xa0000 - 0x1000;
+ Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
+ &BaseAddress,
+ 0,
+ &ViewSize,
+ MEM_RESERVE | MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to allocate virtual memory (Status %x)\n", Status);
+ return 0;
+ }
+ if (BaseAddress != (PVOID)0x0)
+ {
+ DPRINT1("Failed to allocate virtual memory at right address (was %x)\n",
+ BaseAddress);
+ return 0;
+ }
+
+ /* Get the real mode IVT and BDA from the kernel */
+ Status = NtVdmControl(VdmInitialize, IVTAndBda);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtVdmControl failed (status %x)\n", Status);
+ return 0;
+ }
+
+ /* Return success */
+ return 1;
+}
+
+/**********************************************************************
+ * CsrpInitVideo/3
+ *
+ * TODO: we need a virtual device for sessions other than
+ * TODO: the console one
+ */
+NTSTATUS
+CsrpInitVideo (VOID)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\??\\DISPLAY1");
+ IO_STATUS_BLOCK Iosb;
+ HANDLE VideoHandle = (HANDLE) 0;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ DPRINT("CSR: %s called\n", __FUNCTION__);
+
+ InitializeVideoAddressSpace();
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &DeviceName,
+ 0,
+ NULL,
+ NULL);
+ Status = NtOpenFile(&VideoHandle,
+ FILE_ALL_ACCESS,
+ &ObjectAttributes,
+ &Iosb,
+ 0,
+ 0);
+ if (NT_SUCCESS(Status))
+ {
+ NtClose(VideoHandle);
+ }
+ return Status;
+}
+
+BOOL WINAPI
+DllMain(HANDLE hDll,
+ DWORD dwReason,
+ LPVOID lpReserved)
+{
+ if (DLL_PROCESS_ATTACH == dwReason)
+ {
+ Win32CsrDllHandle = hDll;
+//
+// HACK HACK HACK ReactOS to BOOT! Initialization BUG ALERT! See bug 5655.
+//
+ hhk = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProc, NULL, 0);
+// BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT!
+// BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT!
+// BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT!
+ }
+
+ if (DLL_PROCESS_DETACH == dwReason)
+ {
+ CsrCleanupDefineDosDevice();
+ }
+ return TRUE;
+}
+
+/* Ensure that a captured buffer is safe to access */
+BOOL FASTCALL
+Win32CsrValidateBuffer(PCSR_PROCESS ProcessData, PVOID Buffer,
+ SIZE_T NumElements, SIZE_T ElementSize)
+{
+ /* Check that the following conditions are true:
+ * 1. The start of the buffer is somewhere within the process's
+ * shared memory section view.
+ * 2. The remaining space in the view is at least as large as the buffer.
+ * (NB: Please don't try to "optimize" this by using multiplication
+ * instead of division; remember that 2147483648 * 2 = 0.)
+ * 3. The buffer is DWORD-aligned.
+ */
+ ULONG_PTR Offset = (BYTE *)Buffer - (BYTE *)ProcessData->ClientViewBase;
+ if (Offset >= ProcessData->ClientViewBounds
+ || NumElements > (ProcessData->ClientViewBounds - Offset) / ElementSize
+ || (Offset & (sizeof(DWORD) - 1)) != 0)
+ {
+ DPRINT1("Invalid buffer %p(%u*%u); section view is %p(%u)\n",
+ Buffer, NumElements, ElementSize,
+ ProcessData->ClientViewBase, ProcessData->ClientViewBounds);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+NTSTATUS FASTCALL
+Win32CsrEnumProcesses(CSRSS_ENUM_PROCESS_PROC EnumProc,
+ PVOID Context)
+{
+ return CsrEnumProcesses(EnumProc, Context);
+}
+
+VOID
+WINAPI
+PrivateCsrssManualGuiCheck(LONG Check)
+{
+ NtUserCallOneParam(Check, ONEPARAM_ROUTINE_CSRSS_GUICHECK);
+}
+
+DWORD
+WINAPI
+CreateSystemThreads(PVOID pParam)
+{
+ NtUserCallOneParam((DWORD)pParam, ONEPARAM_ROUTINE_CREATESYSTEMTHREADS);
+ DPRINT1("This thread should not terminate!\n");
+ return 0;
+}
+
+NTSTATUS
+WINAPI
+Win32CsrInitialization(IN PCSR_SERVER_DLL ServerDll)
+{
+ HANDLE ServerThread;
+ CLIENT_ID ClientId;
+ NTSTATUS Status;
+ UINT i;
+
+ Win32CsrApiHeap = RtlGetProcessHeap();
+
+ CsrpInitVideo();
+
+ NtUserInitialize(0, NULL, NULL);
+
+ PrivateCsrssManualGuiCheck(0);
+ CsrInitConsoleSupport();
+
+ /* HACK */
+ ServerDll->DispatchTable = (PVOID)Win32CsrApiDefinitions;
+ ServerDll->HighestApiSupported = 0xDEADBABE;
+
+ ServerDll->HardErrorCallback = Win32CsrHardError;
+ ServerDll->NewProcessCallback = Win32CsrDuplicateHandleTable;
+ ServerDll->DisconnectCallback = Win32CsrReleaseConsole;
+
+ RtlInitializeCriticalSection(&Win32CsrDefineDosDeviceCritSec);
+ InitializeListHead(&DosDeviceHistory);
+
+ /* Start the Raw Input Thread and the Desktop Thread */
+ for (i = 0; i < 2; ++i)
+ {
+ Status = RtlCreateUserThread(NtCurrentProcess(), NULL, TRUE, 0, 0, 0, (PTHREAD_START_ROUTINE)CreateSystemThreads, (PVOID)i, &ServerThread, &ClientId);
+ if (NT_SUCCESS(Status))
+ {
+ NtResumeThread(ServerThread, NULL);
+ NtClose(ServerThread);
+ }
+ else
+ DPRINT1("Cannot start Raw Input Thread!\n");
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CSRSS subsystem
+ * FILE: subsys/csrss/win32csr/exitros.c
+ * PURPOSE: Logout/shutdown
+ */
+
+/* INCLUDES ******************************************************************/
+#define NDEBUG
+#include "w32csr.h"
+#include <sddl.h>
+#include "resource.h"
+#include <debug.h>
+
+static HANDLE LogonProcess = NULL;
+
+CSR_API(CsrRegisterLogonProcess)
+{
+ if (Request->Data.RegisterLogonProcessRequest.Register)
+ {
+ if (0 != LogonProcess)
+ {
+ return STATUS_LOGON_SESSION_EXISTS;
+ }
+ LogonProcess = Request->Data.RegisterLogonProcessRequest.ProcessId;
+ }
+ else
+ {
+ if (Request->Header.ClientId.UniqueProcess != LogonProcess)
+ {
+ DPRINT1("Current logon process 0x%x, can't deregister from process 0x%x\n",
+ LogonProcess, Request->Header.ClientId.UniqueProcess);
+ return STATUS_NOT_LOGON_PROCESS;
+ }
+ LogonProcess = 0;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrSetLogonNotifyWindow)
+{
+ return STATUS_SUCCESS;
+}
+
+typedef struct tagSHUTDOWN_SETTINGS
+{
+ BOOL AutoEndTasks;
+ DWORD HungAppTimeout;
+ DWORD WaitToKillAppTimeout;
+} SHUTDOWN_SETTINGS, *PSHUTDOWN_SETTINGS;
+
+#define DEFAULT_AUTO_END_TASKS FALSE
+#define DEFAULT_HUNG_APP_TIMEOUT 5000
+#define DEFAULT_WAIT_TO_KILL_APP_TIMEOUT 20000
+
+typedef struct tagNOTIFY_CONTEXT
+{
+ DWORD ProcessId;
+ UINT Msg;
+ WPARAM wParam;
+ LPARAM lParam;
+ HDESK Desktop;
+ HDESK OldDesktop;
+ DWORD StartTime;
+ DWORD QueryResult;
+ HWND Dlg;
+ DWORD EndNowResult;
+ BOOL ShowUI;
+ HANDLE UIThread;
+ HWND WndClient;
+ PSHUTDOWN_SETTINGS ShutdownSettings;
+ LPTHREAD_START_ROUTINE SendMessageProc;
+} NOTIFY_CONTEXT, *PNOTIFY_CONTEXT;
+
+#define QUERY_RESULT_ABORT 0
+#define QUERY_RESULT_CONTINUE 1
+#define QUERY_RESULT_TIMEOUT 2
+#define QUERY_RESULT_ERROR 3
+#define QUERY_RESULT_FORCE 4
+
+static void FASTCALL
+UpdateProgressBar(HWND ProgressBar, PNOTIFY_CONTEXT NotifyContext)
+{
+ DWORD Passed;
+
+ Passed = GetTickCount() - NotifyContext->StartTime;
+ Passed -= NotifyContext->ShutdownSettings->HungAppTimeout;
+ if (NotifyContext->ShutdownSettings->WaitToKillAppTimeout < Passed)
+ {
+ Passed = NotifyContext->ShutdownSettings->WaitToKillAppTimeout;
+ }
+ SendMessageW(ProgressBar, PBM_SETPOS, Passed / 2, 0);
+}
+
+static INT_PTR CALLBACK
+EndNowDlgProc(HWND Dlg, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ INT_PTR Result;
+ PNOTIFY_CONTEXT NotifyContext;
+ HWND ProgressBar;
+ DWORD TitleLength;
+ int Len;
+ LPWSTR Title;
+
+ switch(Msg)
+ {
+ case WM_INITDIALOG:
+ NotifyContext = (PNOTIFY_CONTEXT) lParam;
+ NotifyContext->EndNowResult = QUERY_RESULT_ABORT;
+ SetWindowLongPtrW(Dlg, DWLP_USER, (LONG_PTR) lParam);
+ TitleLength = SendMessageW(NotifyContext->WndClient, WM_GETTEXTLENGTH,
+ 0, 0) +
+ GetWindowTextLengthW(Dlg);
+ Title = HeapAlloc(Win32CsrApiHeap, 0, (TitleLength + 1) * sizeof(WCHAR));
+ if (NULL != Title)
+ {
+ Len = GetWindowTextW(Dlg, Title, TitleLength + 1);
+ SendMessageW(NotifyContext->WndClient, WM_GETTEXT,
+ TitleLength + 1 - Len, (LPARAM) (Title + Len));
+ SetWindowTextW(Dlg, Title);
+ HeapFree(Win32CsrApiHeap, 0, Title);
+ }
+ ProgressBar = GetDlgItem(Dlg, IDC_PROGRESS);
+ SendMessageW(ProgressBar, PBM_SETRANGE32, 0,
+ NotifyContext->ShutdownSettings->WaitToKillAppTimeout / 2);
+ UpdateProgressBar(ProgressBar, NotifyContext);
+ SetTimer(Dlg, 0, 200, NULL);
+ Result = FALSE;
+ break;
+
+ case WM_TIMER:
+ NotifyContext = (PNOTIFY_CONTEXT) GetWindowLongPtrW(Dlg, DWLP_USER);
+ ProgressBar = GetDlgItem(Dlg, IDC_PROGRESS);
+ UpdateProgressBar(ProgressBar, NotifyContext);
+ Result = TRUE;
+ break;
+
+ case WM_COMMAND:
+ if (BN_CLICKED == HIWORD(wParam) && IDC_END_NOW == LOWORD(wParam))
+ {
+ NotifyContext = (PNOTIFY_CONTEXT) GetWindowLongPtrW(Dlg, DWLP_USER);
+ NotifyContext->EndNowResult = QUERY_RESULT_FORCE;
+ SendMessageW(Dlg, WM_CLOSE, 0, 0);
+ Result = TRUE;
+ }
+ else
+ {
+ Result = FALSE;
+ }
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow(Dlg);
+ Result = TRUE;
+ break;
+
+ case WM_DESTROY:
+ NotifyContext = (PNOTIFY_CONTEXT) GetWindowLongPtrW(Dlg, DWLP_USER);
+ NotifyContext->Dlg = NULL;
+ KillTimer(Dlg, 0);
+ PostQuitMessage(NotifyContext->EndNowResult);
+ Result = TRUE;
+ break;
+
+ default:
+ Result = FALSE;
+ break;
+ }
+
+ return Result;
+}
+
+typedef void (WINAPI *INITCOMMONCONTROLS_PROC)(void);
+
+static void
+CallInitCommonControls()
+{
+ static BOOL Initialized = FALSE;
+ HMODULE Lib;
+ INITCOMMONCONTROLS_PROC InitProc;
+
+ if (Initialized)
+ {
+ return;
+ }
+
+ Lib = LoadLibraryW(L"COMCTL32.DLL");
+ if (NULL == Lib)
+ {
+ return;
+ }
+ InitProc = (INITCOMMONCONTROLS_PROC) GetProcAddress(Lib, "InitCommonControls");
+ if (NULL == InitProc)
+ {
+ return;
+ }
+
+ (*InitProc)();
+
+ Initialized = TRUE;
+}
+
+static DWORD WINAPI
+EndNowThreadProc(LPVOID Parameter)
+{
+ PNOTIFY_CONTEXT NotifyContext = (PNOTIFY_CONTEXT) Parameter;
+ MSG Msg;
+
+ SetThreadDesktop(NotifyContext->Desktop);
+ SwitchDesktop(NotifyContext->Desktop);
+ CallInitCommonControls();
+ NotifyContext->Dlg = CreateDialogParam(GetModuleHandleW(L"win32csr"),
+ MAKEINTRESOURCE(IDD_END_NOW), NULL,
+ EndNowDlgProc, (LPARAM) NotifyContext);
+ if (NULL == NotifyContext->Dlg)
+ {
+ return 0;
+ }
+ ShowWindow(NotifyContext->Dlg, SW_SHOWNORMAL);
+
+ while (GetMessageW(&Msg, NULL, 0, 0))
+ {
+ if (! IsDialogMessage(NotifyContext->Dlg, &Msg))
+ {
+ TranslateMessage(&Msg);
+ DispatchMessageW(&Msg);
+ }
+ }
+
+ return Msg.wParam;
+}
+
+typedef struct tagMESSAGE_CONTEXT
+{
+ HWND Wnd;
+ UINT Msg;
+ WPARAM wParam;
+ LPARAM lParam;
+ DWORD Timeout;
+} MESSAGE_CONTEXT, *PMESSAGE_CONTEXT;
+
+static DWORD WINAPI
+SendQueryEndSession(LPVOID Parameter)
+{
+ PMESSAGE_CONTEXT Context = (PMESSAGE_CONTEXT) Parameter;
+ DWORD_PTR Result;
+
+ if (SendMessageTimeoutW(Context->Wnd, WM_QUERYENDSESSION, Context->wParam,
+ Context->lParam, SMTO_NORMAL, Context->Timeout,
+ &Result))
+ {
+ return Result ? QUERY_RESULT_CONTINUE : QUERY_RESULT_ABORT;
+ }
+
+ return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT : QUERY_RESULT_ERROR;
+}
+
+static DWORD WINAPI
+SendEndSession(LPVOID Parameter)
+{
+ PMESSAGE_CONTEXT Context = (PMESSAGE_CONTEXT) Parameter;
+ DWORD_PTR Result;
+
+ if (Context->wParam)
+ {
+ if (SendMessageTimeoutW(Context->Wnd, WM_ENDSESSION, Context->wParam,
+ Context->lParam, SMTO_NORMAL, Context->Timeout,
+ &Result))
+ {
+ return QUERY_RESULT_CONTINUE;
+ }
+ return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT : QUERY_RESULT_ERROR;
+ }
+ else
+ {
+ SendMessage(Context->Wnd, WM_ENDSESSION, Context->wParam,
+ Context->lParam);
+ return QUERY_RESULT_CONTINUE;
+ }
+}
+
+static BOOL CALLBACK
+NotifyTopLevelEnum(HWND Wnd, LPARAM lParam)
+{
+ PNOTIFY_CONTEXT NotifyContext = (PNOTIFY_CONTEXT) lParam;
+ MESSAGE_CONTEXT MessageContext;
+ DWORD Now, Passed;
+ DWORD Timeout, WaitStatus;
+ DWORD ProcessId;
+ HANDLE MessageThread;
+ HANDLE Threads[2];
+
+ if (0 == GetWindowThreadProcessId(Wnd, &ProcessId))
+ {
+ NotifyContext->QueryResult = QUERY_RESULT_ERROR;
+ return FALSE;
+ }
+
+ if (ProcessId == NotifyContext->ProcessId)
+ {
+ Now = GetTickCount();
+ if (0 == NotifyContext->StartTime)
+ {
+ NotifyContext->StartTime = Now;
+ }
+ /* Note: Passed is computed correctly even when GetTickCount() wraps due
+ to unsigned arithmetic */
+ Passed = Now - NotifyContext->StartTime;
+ MessageContext.Wnd = Wnd;
+ MessageContext.Msg = NotifyContext->Msg;
+ MessageContext.wParam = NotifyContext->wParam;
+ MessageContext.lParam = NotifyContext->lParam;
+ MessageContext.Timeout = NotifyContext->ShutdownSettings->HungAppTimeout;
+ if (! NotifyContext->ShutdownSettings->AutoEndTasks)
+ {
+ MessageContext.Timeout += NotifyContext->ShutdownSettings->WaitToKillAppTimeout;
+ }
+ if (Passed < MessageContext.Timeout)
+ {
+ MessageContext.Timeout -= Passed;
+ MessageThread = CreateThread(NULL, 0, NotifyContext->SendMessageProc,
+ (LPVOID) &MessageContext, 0, NULL);
+ if (NULL == MessageThread)
+ {
+ NotifyContext->QueryResult = QUERY_RESULT_ERROR;
+ return FALSE;
+ }
+ Timeout = NotifyContext->ShutdownSettings->HungAppTimeout;
+ if (Passed < Timeout)
+ {
+ Timeout -= Passed;
+ WaitStatus = WaitForSingleObjectEx(MessageThread, Timeout, FALSE);
+ }
+ else
+ {
+ WaitStatus = WAIT_TIMEOUT;
+ }
+ if (WAIT_TIMEOUT == WaitStatus)
+ {
+ NotifyContext->WndClient = Wnd;
+ if (NULL == NotifyContext->UIThread && NotifyContext->ShowUI)
+ {
+ NotifyContext->UIThread = CreateThread(NULL, 0,
+ EndNowThreadProc,
+ (LPVOID) NotifyContext,
+ 0, NULL);
+ }
+ Threads[0] = MessageThread;
+ Threads[1] = NotifyContext->UIThread;
+ WaitStatus = WaitForMultipleObjectsEx(NULL == NotifyContext->UIThread ?
+ 1 : 2,
+ Threads, FALSE, INFINITE,
+ FALSE);
+ if (WAIT_OBJECT_0 == WaitStatus)
+ {
+ if (! GetExitCodeThread(MessageThread, &NotifyContext->QueryResult))
+ {
+ NotifyContext->QueryResult = QUERY_RESULT_ERROR;
+ }
+ }
+ else if (WAIT_OBJECT_0 + 1 == WaitStatus)
+ {
+ if (! GetExitCodeThread(NotifyContext->UIThread,
+ &NotifyContext->QueryResult))
+ {
+ NotifyContext->QueryResult = QUERY_RESULT_ERROR;
+ }
+ }
+ else
+ {
+ NotifyContext->QueryResult = QUERY_RESULT_ERROR;
+ }
+ if (WAIT_OBJECT_0 != WaitStatus)
+ {
+ TerminateThread(MessageThread, QUERY_RESULT_TIMEOUT);
+ }
+ }
+ else if (WAIT_OBJECT_0 == WaitStatus)
+ {
+ if (! GetExitCodeThread(MessageThread,
+ &NotifyContext->QueryResult))
+ {
+ NotifyContext->QueryResult = QUERY_RESULT_ERROR;
+ }
+ }
+ else
+ {
+ NotifyContext->QueryResult = QUERY_RESULT_ERROR;
+ }
+ CloseHandle(MessageThread);
+ }
+ else
+ {
+ NotifyContext->QueryResult = QUERY_RESULT_TIMEOUT;
+ }
+ }
+
+ return QUERY_RESULT_CONTINUE == NotifyContext->QueryResult;
+}
+
+static BOOL CALLBACK
+NotifyDesktopEnum(LPWSTR DesktopName, LPARAM lParam)
+{
+ PNOTIFY_CONTEXT Context = (PNOTIFY_CONTEXT) lParam;
+
+ Context->Desktop = OpenDesktopW(DesktopName, 0, FALSE,
+ DESKTOP_ENUMERATE | DESKTOP_SWITCHDESKTOP);
+ if (NULL == Context->Desktop)
+ {
+ DPRINT1("OpenDesktop failed with error %d\n", GetLastError());
+ Context->QueryResult = QUERY_RESULT_ERROR;
+ return FALSE;
+ }
+
+ Context->OldDesktop = GetThreadDesktop(GetCurrentThreadId());
+ SwitchDesktop(Context->Desktop);
+
+ EnumDesktopWindows(Context->Desktop, NotifyTopLevelEnum, lParam);
+
+ SwitchDesktop(Context->OldDesktop);
+
+ CloseDesktop(Context->Desktop);
+
+ return QUERY_RESULT_CONTINUE == Context->QueryResult;
+}
+
+static BOOL FASTCALL
+NotifyTopLevelWindows(PNOTIFY_CONTEXT Context)
+{
+ HWINSTA WindowStation;
+
+ WindowStation = GetProcessWindowStation();
+ if (NULL == WindowStation)
+ {
+ DPRINT1("GetProcessWindowStation failed with error %d\n", GetLastError());
+ return TRUE;
+ }
+
+ EnumDesktopsW(WindowStation, NotifyDesktopEnum, (LPARAM) Context);
+
+ return TRUE;
+}
+
+static BOOL FASTCALL
+NotifyAndTerminateProcess(PCSR_PROCESS ProcessData,
+ PSHUTDOWN_SETTINGS ShutdownSettings,
+ UINT Flags)
+{
+ NOTIFY_CONTEXT Context;
+ HANDLE Process;
+ DWORD QueryResult = QUERY_RESULT_CONTINUE;
+
+ Context.QueryResult = QUERY_RESULT_CONTINUE;
+
+ if (0 == (Flags & EWX_FORCE))
+ {
+ if (NULL != ProcessData->Console)
+ {
+ ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT, ProcessData,
+ ShutdownSettings->WaitToKillAppTimeout);
+ }
+ else
+ {
+ Context.ProcessId = (DWORD_PTR) ProcessData->ClientId.UniqueProcess;
+ Context.wParam = 0;
+ Context.lParam = (0 != (Flags & EWX_INTERNAL_FLAG_LOGOFF) ?
+ ENDSESSION_LOGOFF : 0);
+ Context.StartTime = 0;
+ Context.UIThread = NULL;
+ Context.ShowUI = DtbgIsDesktopVisible();
+ Context.Dlg = NULL;
+ Context.ShutdownSettings = ShutdownSettings;
+ Context.SendMessageProc = SendQueryEndSession;
+
+ NotifyTopLevelWindows(&Context);
+
+ Context.wParam = (QUERY_RESULT_ABORT != Context.QueryResult);
+ Context.lParam = (0 != (Flags & EWX_INTERNAL_FLAG_LOGOFF) ?
+ ENDSESSION_LOGOFF : 0);
+ Context.SendMessageProc = SendEndSession;
+ Context.ShowUI = DtbgIsDesktopVisible() &&
+ (QUERY_RESULT_ABORT != Context.QueryResult);
+ QueryResult = Context.QueryResult;
+ Context.QueryResult = QUERY_RESULT_CONTINUE;
+
+ NotifyTopLevelWindows(&Context);
+
+ if (NULL != Context.UIThread)
+ {
+ if (NULL != Context.Dlg)
+ {
+ SendMessageW(Context.Dlg, WM_CLOSE, 0, 0);
+ }
+ else
+ {
+ TerminateThread(Context.UIThread, QUERY_RESULT_ERROR);
+ }
+ CloseHandle(Context.UIThread);
+ }
+ }
+
+ if (QUERY_RESULT_ABORT == QueryResult)
+ {
+ return FALSE;
+ }
+ }
+
+ /* Terminate this process */
+ Process = OpenProcess(PROCESS_TERMINATE, FALSE,
+ (DWORD_PTR) ProcessData->ClientId.UniqueProcess);
+ if (NULL == Process)
+ {
+ DPRINT1("Unable to open process %d, error %d\n", ProcessData->ClientId.UniqueProcess,
+ GetLastError());
+ return TRUE;
+ }
+ TerminateProcess(Process, 0);
+ CloseHandle(Process);
+
+ return TRUE;
+}
+
+typedef struct tagPROCESS_ENUM_CONTEXT
+{
+ UINT ProcessCount;
+ PCSR_PROCESS *ProcessData;
+ TOKEN_ORIGIN TokenOrigin;
+ DWORD ShellProcess;
+ DWORD CsrssProcess;
+} PROCESS_ENUM_CONTEXT, *PPROCESS_ENUM_CONTEXT;
+
+static NTSTATUS WINAPI
+ExitReactosProcessEnum(PCSR_PROCESS ProcessData, PVOID Data)
+{
+ HANDLE Process;
+ HANDLE Token;
+ TOKEN_ORIGIN Origin;
+ DWORD ReturnLength;
+ PPROCESS_ENUM_CONTEXT Context = (PPROCESS_ENUM_CONTEXT) Data;
+ PCSR_PROCESS *NewData;
+
+ /* Do not kill winlogon or csrss */
+ if ((DWORD_PTR) ProcessData->ClientId.UniqueProcess == Context->CsrssProcess ||
+ ProcessData->ClientId.UniqueProcess == LogonProcess)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ /* Get the login session of this process */
+ Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,
+ (DWORD_PTR) ProcessData->ClientId.UniqueProcess);
+ if (NULL == Process)
+ {
+ DPRINT1("Unable to open process %d, error %d\n", ProcessData->ClientId.UniqueProcess,
+ GetLastError());
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if (! OpenProcessToken(Process, TOKEN_QUERY, &Token))
+ {
+ DPRINT1("Unable to open token for process %d, error %d\n",
+ ProcessData->ClientId.UniqueProcess, GetLastError());
+ CloseHandle(Process);
+ return STATUS_UNSUCCESSFUL;
+ }
+ CloseHandle(Process);
+
+ if (! GetTokenInformation(Token, TokenOrigin, &Origin,
+ sizeof(TOKEN_ORIGIN), &ReturnLength))
+ {
+ DPRINT1("GetTokenInformation failed for process %d with error %d\n",
+ ProcessData->ClientId.UniqueProcess, GetLastError());
+ CloseHandle(Token);
+ return STATUS_UNSUCCESSFUL;
+ }
+ CloseHandle(Token);
+
+ /* This process will be killed if it's in the correct logon session */
+ if (RtlEqualLuid(&(Context->TokenOrigin.OriginatingLogonSession),
+ &(Origin.OriginatingLogonSession)))
+ {
+ /* Kill the shell process last */
+ if ((DWORD_PTR) ProcessData->ClientId.UniqueProcess == Context->ShellProcess)
+ {
+ ProcessData->ShutdownLevel = 0;
+ }
+ NewData = HeapAlloc(Win32CsrApiHeap, 0, (Context->ProcessCount + 1)
+ * sizeof(PCSR_PROCESS));
+ if (NULL == NewData)
+ {
+ return STATUS_NO_MEMORY;
+ }
+ if (0 != Context->ProcessCount)
+ {
+ memcpy(NewData, Context->ProcessData,
+ Context->ProcessCount * sizeof(PCSR_PROCESS));
+ HeapFree(Win32CsrApiHeap, 0, Context->ProcessData);
+ }
+ Context->ProcessData = NewData;
+ Context->ProcessData[Context->ProcessCount] = ProcessData;
+ Context->ProcessCount++;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static int
+ProcessDataCompare(const void *Elem1, const void *Elem2)
+{
+ const PCSR_PROCESS *ProcessData1 = (PCSR_PROCESS *) Elem1;
+ const PCSR_PROCESS *ProcessData2 = (PCSR_PROCESS *) Elem2;
+
+ if ((*ProcessData1)->ShutdownLevel < (*ProcessData2)->ShutdownLevel)
+ {
+ return +1;
+ }
+ else if ((*ProcessData2)->ShutdownLevel < (*ProcessData1)->ShutdownLevel)
+ {
+ return -1;
+ }
+ else if ((*ProcessData1)->ClientId.UniqueProcess < (*ProcessData2)->ClientId.UniqueProcess)
+ {
+ return +1;
+ }
+ else if ((*ProcessData2)->ClientId.UniqueProcess < (*ProcessData1)->ClientId.UniqueProcess)
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+static DWORD FASTCALL
+GetShutdownSetting(HKEY DesktopKey, LPCWSTR ValueName, DWORD DefaultValue)
+{
+ BYTE ValueBuffer[16];
+ LONG ErrCode;
+ DWORD Type;
+ DWORD ValueSize;
+ UNICODE_STRING StringValue;
+ ULONG Value;
+
+ ValueSize = sizeof(ValueBuffer);
+ ErrCode = RegQueryValueExW(DesktopKey, ValueName, NULL, &Type, ValueBuffer,
+ &ValueSize);
+ if (ERROR_SUCCESS != ErrCode)
+ {
+ DPRINT("GetShutdownSetting for %S failed with error code %ld\n",
+ ValueName, ErrCode);
+ return DefaultValue;
+ }
+
+ if (REG_SZ == Type)
+ {
+ RtlInitUnicodeString(&StringValue, (LPCWSTR) ValueBuffer);
+ if (! NT_SUCCESS(RtlUnicodeStringToInteger(&StringValue, 10, &Value)))
+ {
+ DPRINT1("Unable to convert value %S for setting %S\n",
+ StringValue.Buffer, ValueName);
+ return DefaultValue;
+ }
+ return (DWORD) Value;
+ }
+ else if (REG_DWORD == Type)
+ {
+ return *((DWORD *) ValueBuffer);
+ }
+
+ DPRINT1("Unexpected registry type %d for setting %S\n", Type, ValueName);
+ return DefaultValue;
+}
+
+static void FASTCALL
+LoadShutdownSettings(PSID Sid, PSHUTDOWN_SETTINGS ShutdownSettings)
+{
+ static WCHAR Subkey[] = L"\\Control Panel\\Desktop";
+ LPWSTR StringSid;
+ WCHAR InitialKeyName[128];
+ LPWSTR KeyName;
+ HKEY DesktopKey;
+ LONG ErrCode;
+
+ ShutdownSettings->AutoEndTasks = DEFAULT_AUTO_END_TASKS;
+ ShutdownSettings->HungAppTimeout = DEFAULT_HUNG_APP_TIMEOUT;
+ ShutdownSettings->WaitToKillAppTimeout = DEFAULT_WAIT_TO_KILL_APP_TIMEOUT;
+
+ if (! ConvertSidToStringSidW(Sid, &StringSid))
+ {
+ DPRINT1("ConvertSidToStringSid failed with error %d, using default shutdown settings\n",
+ GetLastError());
+ return;
+ }
+ if (wcslen(StringSid) + wcslen(Subkey) + 1 <=
+ sizeof(InitialKeyName) / sizeof(WCHAR))
+ {
+ KeyName = InitialKeyName;
+ }
+ else
+ {
+ KeyName = HeapAlloc(Win32CsrApiHeap, 0,
+ (wcslen(StringSid) + wcslen(Subkey) + 1) *
+ sizeof(WCHAR));
+ if (NULL == KeyName)
+ {
+ DPRINT1("Failed to allocate memory, using default shutdown settings\n");
+ LocalFree(StringSid);
+ return;
+ }
+ }
+ wcscat(wcscpy(KeyName, StringSid), Subkey);
+ LocalFree(StringSid);
+
+ ErrCode = RegOpenKeyExW(HKEY_USERS, KeyName, 0, KEY_QUERY_VALUE, &DesktopKey);
+ if (KeyName != InitialKeyName)
+ {
+ HeapFree(Win32CsrApiHeap, 0, KeyName);
+ }
+ if (ERROR_SUCCESS != ErrCode)
+ {
+ DPRINT1("RegOpenKeyEx failed with error %ld, using default shutdown settings\n", ErrCode);
+ return;
+ }
+
+ ShutdownSettings->AutoEndTasks = (BOOL) GetShutdownSetting(DesktopKey, L"AutoEndTasks",
+ (DWORD) DEFAULT_AUTO_END_TASKS);
+ ShutdownSettings->HungAppTimeout = GetShutdownSetting(DesktopKey,
+ L"HungAppTimeout",
+ DEFAULT_HUNG_APP_TIMEOUT);
+ ShutdownSettings->WaitToKillAppTimeout = GetShutdownSetting(DesktopKey,
+ L"WaitToKillAppTimeout",
+ DEFAULT_WAIT_TO_KILL_APP_TIMEOUT);
+
+ RegCloseKey(DesktopKey);
+}
+
+static NTSTATUS FASTCALL
+InternalExitReactos(DWORD ProcessId, DWORD ThreadId, UINT Flags)
+{
+ HANDLE CallerThread;
+ HANDLE CallerToken;
+ NTSTATUS Status;
+ PROCESS_ENUM_CONTEXT Context;
+ DWORD ReturnLength;
+ HWND ShellWnd;
+ UINT ProcessIndex;
+ char FixedUserInfo[64];
+ TOKEN_USER *UserInfo;
+ SHUTDOWN_SETTINGS ShutdownSettings;
+
+ if (ProcessId != (DWORD_PTR) LogonProcess)
+ {
+ DPRINT1("Internal ExitWindowsEx call not from winlogon\n");
+ return STATUS_ACCESS_DENIED;
+ }
+
+ DPRINT1("FIXME: Need to close all user processes!\n");
+ return STATUS_SUCCESS;
+
+ CallerThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, ThreadId);
+ if (NULL == CallerThread)
+ {
+ DPRINT1("OpenThread failed with error %d\n", GetLastError());
+ return STATUS_UNSUCCESSFUL;
+ }
+ if (! OpenThreadToken(CallerThread, TOKEN_QUERY, FALSE, &CallerToken))
+ {
+ DPRINT1("OpenThreadToken failed with error %d\n", GetLastError());
+ CloseHandle(CallerThread);
+ return STATUS_UNSUCCESSFUL;
+ }
+ CloseHandle(CallerThread);
+
+ Context.ProcessCount = 0;
+ Context.ProcessData = NULL;
+ if (! GetTokenInformation(CallerToken, TokenOrigin, &Context.TokenOrigin,
+ sizeof(TOKEN_ORIGIN), &ReturnLength))
+ {
+ DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
+ CloseHandle(CallerToken);
+ return STATUS_UNSUCCESSFUL;
+ }
+ if (! GetTokenInformation(CallerToken, TokenUser, FixedUserInfo,
+ sizeof(FixedUserInfo), &ReturnLength))
+ {
+ if (sizeof(FixedUserInfo) < ReturnLength)
+ {
+ UserInfo = HeapAlloc(Win32CsrApiHeap, 0, ReturnLength);
+ if (NULL == UserInfo)
+ {
+ DPRINT1("Unable to allocate %u bytes for user info\n",
+ (unsigned) ReturnLength);
+ CloseHandle(CallerToken);
+ return STATUS_NO_MEMORY;
+ }
+ if (! GetTokenInformation(CallerToken, TokenUser, UserInfo,
+ ReturnLength, &ReturnLength))
+ {
+ DPRINT1("GetTokenInformation failed with error %d\n",
+ GetLastError());
+ HeapFree(Win32CsrApiHeap, 0, UserInfo);
+ CloseHandle(CallerToken);
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+ else
+ {
+ DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
+ CloseHandle(CallerToken);
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+ else
+ {
+ UserInfo = (TOKEN_USER *) FixedUserInfo;
+ }
+ CloseHandle(CallerToken);
+ LoadShutdownSettings(UserInfo->User.Sid, &ShutdownSettings);
+ if (UserInfo != (TOKEN_USER *) FixedUserInfo)
+ {
+ HeapFree(Win32CsrApiHeap, 0, UserInfo);
+ }
+ Context.CsrssProcess = GetCurrentProcessId();
+ ShellWnd = GetShellWindow();
+ if (NULL == ShellWnd)
+ {
+ DPRINT("No shell present\n");
+ Context.ShellProcess = 0;
+ }
+ else if (0 == GetWindowThreadProcessId(ShellWnd, &Context.ShellProcess))
+ {
+ DPRINT1("Can't get process id of shell window\n");
+ Context.ShellProcess = 0;
+ }
+
+ Status = Win32CsrEnumProcesses(ExitReactosProcessEnum, &Context);
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to enumerate registered processes, status 0x%x\n",
+ Status);
+ if (NULL != Context.ProcessData)
+ {
+ HeapFree(Win32CsrApiHeap, 0, Context.ProcessData);
+ }
+ return Status;
+ }
+
+ qsort(Context.ProcessData, Context.ProcessCount, sizeof(PCSR_PROCESS),
+ ProcessDataCompare);
+
+ /* Terminate processes, stop if we find one kicking and screaming it doesn't
+ want to die */
+ Status = STATUS_SUCCESS;
+ for (ProcessIndex = 0;
+ ProcessIndex < Context.ProcessCount && NT_SUCCESS(Status);
+ ProcessIndex++)
+ {
+ if (! NotifyAndTerminateProcess(Context.ProcessData[ProcessIndex],
+ &ShutdownSettings, Flags))
+ {
+ Status = STATUS_REQUEST_ABORTED;
+ }
+ }
+
+ /* Cleanup */
+ if (NULL != Context.ProcessData)
+ {
+ HeapFree(Win32CsrApiHeap, 0, Context.ProcessData);
+ }
+
+ return Status;
+}
+
+static NTSTATUS FASTCALL
+UserExitReactos(DWORD UserProcessId, UINT Flags)
+{
+ NTSTATUS Status;
+
+ /* FIXME Inside 2000 says we should impersonate the caller here */
+ Status = NtUserCallTwoParam (UserProcessId, Flags, TWOPARAM_ROUTINE_EXITREACTOS);
+
+ /* If the message isn't handled, the return value is 0, so 0 doesn't indicate
+ success. Success is indicated by a 1 return value, if anything besides 0
+ or 1 it's a NTSTATUS value */
+ if (1 == Status)
+ {
+ Status = STATUS_SUCCESS;
+ }
+ else if (0 == Status)
+ {
+ Status = STATUS_NOT_IMPLEMENTED;
+ }
+
+ return Status;
+}
+
+CSR_API(CsrExitReactos)
+{
+ if (0 == (Request->Data.ExitReactosRequest.Flags & EWX_INTERNAL_FLAG))
+ {
+ return UserExitReactos((DWORD_PTR) Request->Header.ClientId.UniqueProcess,
+ Request->Data.ExitReactosRequest.Flags);
+ }
+ else
+ {
+ return InternalExitReactos((DWORD_PTR) Request->Header.ClientId.UniqueProcess,
+ (DWORD_PTR) Request->Header.ClientId.UniqueThread,
+ Request->Data.ExitReactosRequest.Flags);
+ }
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: subsys/csrss/win32csr/file.c
+ * PURPOSE: File handling
+ * PROGRAMMERS: Pierre Schweitzer (pierre.schweitzer@reactos.org)
+ * NOTE: Belongs to basesrv.dll
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <w32csr.h>
+#define NDEBUG
+#include <debug.h>
+#include "file.h"
+
+/* GLOBALS *******************************************************************/
+
+typedef BOOL (WINAPI *PUSER_SOUND_SENTRY)(VOID);
+BOOL
+WINAPI
+FirstSoundSentry(VOID);
+
+UINT CsrGetTempFileUnique;
+LIST_ENTRY DosDeviceHistory;
+RTL_CRITICAL_SECTION Win32CsrDefineDosDeviceCritSec;
+PUSER_SOUND_SENTRY _UserSoundSentry = FirstSoundSentry;
+
+/* FUNCTIONS *****************************************************************/
+
+BOOL
+WINAPI
+FailSoundSentry(VOID)
+{
+ /* In case the function can't be found/is unimplemented */
+ return FALSE;
+}
+
+BOOL
+WINAPI
+FirstSoundSentry(VOID)
+{
+ UNICODE_STRING DllString = RTL_CONSTANT_STRING(L"winsrv");
+ STRING FuncString = RTL_CONSTANT_STRING("_UserSoundSentry");
+ HANDLE DllHandle;
+ NTSTATUS Status;
+ PUSER_SOUND_SENTRY NewSoundSentry = FailSoundSentry;
+
+ /* Load winsrv manually */
+ Status = LdrGetDllHandle(NULL, NULL, &DllString, &DllHandle);
+ if (NT_SUCCESS(Status))
+ {
+ /* If it was found, get SoundSentry export */
+ Status = LdrGetProcedureAddress(DllHandle,
+ &FuncString,
+ 0,
+ (PVOID*)&NewSoundSentry);
+ }
+
+ /* Set it as the callback for the future, and call it */
+ _UserSoundSentry = NewSoundSentry;
+ return _UserSoundSentry();
+}
+
+CSR_API(CsrSoundSentry)
+{
+ /* Call the API and see if it suceeds */
+ return _UserSoundSentry() ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
+}
+
+CSR_API(CsrGetTempFile)
+{
+ DPRINT("CsrGetTempFile entered\n");
+
+ /* Return 16-bits ID */
+ Request->Data.GetTempFile.UniqueID = (++CsrGetTempFileUnique & 0xFFFF);
+
+ DPRINT("Returning: %u\n", Request->Data.GetTempFile.UniqueID);
+
+ return STATUS_SUCCESS;
+}
+
+CSR_API(CsrDefineDosDevice)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE LinkHandle = NULL;
+ NTSTATUS Status;
+ UNICODE_STRING DeviceName = {0};
+ UNICODE_STRING RequestDeviceName = {0};
+ UNICODE_STRING LinkTarget = {0};
+ PUNICODE_STRING RequestLinkTarget;
+ ULONG Length;
+ SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
+ SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY};
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+ PACL Dacl;
+ PSID AdminSid;
+ PSID SystemSid;
+ PSID WorldSid;
+ ULONG SidLength;
+ PCSRSS_DOS_DEVICE_HISTORY_ENTRY HistoryEntry;
+ PLIST_ENTRY Entry;
+ PLIST_ENTRY ListHead;
+ BOOLEAN Matched, AddHistory;
+ DWORD dwFlags;
+ PWSTR lpBuffer;
+
+ DPRINT("CsrDefineDosDevice entered, Flags:%d, DeviceName:%wZ, TargetName:%wZ\n",
+ Request->Data.DefineDosDeviceRequest.dwFlags,
+ &Request->Data.DefineDosDeviceRequest.DeviceName,
+ &Request->Data.DefineDosDeviceRequest.TargetName);
+
+ Matched = AddHistory = FALSE;
+ HistoryEntry = NULL;
+ AdminSid = SystemSid = WorldSid = NULL;
+ SecurityDescriptor = NULL;
+ ListHead = &DosDeviceHistory;
+ dwFlags = Request->Data.DefineDosDeviceRequest.dwFlags;
+
+ /* Validate the flags */
+ if ( (dwFlags & 0xFFFFFFF0) ||
+ ((dwFlags & DDD_EXACT_MATCH_ON_REMOVE) &&
+ ! (dwFlags & DDD_REMOVE_DEFINITION)) )
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Status = RtlEnterCriticalSection(&Win32CsrDefineDosDeviceCritSec);
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlEnterCriticalSection() failed (Status %lx)\n",
+ Status);
+ return Status;
+ }
+
+ _SEH2_TRY
+ {
+ Status =
+ RtlUpcaseUnicodeString(&RequestDeviceName,
+ &Request->Data.DefineDosDeviceRequest.DeviceName,
+ TRUE);
+ if (! NT_SUCCESS(Status))
+ _SEH2_LEAVE;
+
+ RequestLinkTarget =
+ &Request->Data.DefineDosDeviceRequest.TargetName;
+ lpBuffer = (PWSTR) RtlAllocateHeap(Win32CsrApiHeap,
+ HEAP_ZERO_MEMORY,
+ RequestDeviceName.MaximumLength + 5 * sizeof(WCHAR));
+ if (! lpBuffer)
+ {
+ DPRINT1("Failed to allocate memory\n");
+ Status = STATUS_NO_MEMORY;
+ _SEH2_LEAVE;
+ }
+
+ swprintf(lpBuffer,
+ L"\\??\\%wZ",
+ &RequestDeviceName);
+ RtlInitUnicodeString(&DeviceName,
+ lpBuffer);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &DeviceName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtOpenSymbolicLinkObject(&LinkHandle,
+ DELETE | 0x1,
+ &ObjectAttributes);
+ if (NT_SUCCESS(Status))
+ {
+ Status = NtQuerySymbolicLinkObject(LinkHandle,
+ &LinkTarget,
+ &Length);
+ if (! NT_SUCCESS(Status) &&
+ Status == STATUS_BUFFER_TOO_SMALL)
+ {
+ LinkTarget.Length = 0;
+ LinkTarget.MaximumLength = Length;
+ LinkTarget.Buffer = (PWSTR)
+ RtlAllocateHeap(Win32CsrApiHeap,
+ HEAP_ZERO_MEMORY,
+ Length);
+ if (! LinkTarget.Buffer)
+ {
+ DPRINT1("Failed to allocate memory\n");
+ Status = STATUS_NO_MEMORY;
+ _SEH2_LEAVE;
+ }
+
+ Status = NtQuerySymbolicLinkObject(LinkHandle,
+ &LinkTarget,
+ &Length);
+ }
+
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("NtQuerySymbolicLinkObject(%wZ) failed (Status %lx)\n",
+ &DeviceName, Status);
+ _SEH2_LEAVE;
+ }
+
+ if ((dwFlags & DDD_REMOVE_DEFINITION))
+ {
+ /* If no target name specified we remove the current symlink target */
+ if (RequestLinkTarget->Length == 0)
+ Matched = TRUE;
+ else
+ {
+ if (dwFlags & DDD_EXACT_MATCH_ON_REMOVE)
+ Matched = ! RtlCompareUnicodeString(RequestLinkTarget,
+ &LinkTarget,
+ TRUE);
+ else
+ Matched = RtlPrefixUnicodeString(RequestLinkTarget,
+ &LinkTarget,
+ TRUE);
+ }
+
+ if (Matched && IsListEmpty(ListHead))
+ {
+ /* Current symlink target macthed and there is nothing to revert to */
+ RequestLinkTarget = NULL;
+ }
+ else if (Matched && ! IsListEmpty(ListHead))
+ {
+ /* Fetch the first history entry we come across for the device name */
+ /* This will become the current symlink target for the device name */
+ Matched = FALSE;
+ Entry = ListHead->Flink;
+ while (Entry != ListHead)
+ {
+ HistoryEntry = (PCSRSS_DOS_DEVICE_HISTORY_ENTRY)
+ CONTAINING_RECORD(Entry,
+ CSRSS_DOS_DEVICE_HISTORY_ENTRY,
+ Entry);
+ Matched =
+ ! RtlCompareUnicodeString(&RequestDeviceName,
+ &HistoryEntry->Device,
+ FALSE);
+ if (Matched)
+ {
+ RemoveEntryList(&HistoryEntry->Entry);
+ RequestLinkTarget = &HistoryEntry->Target;
+ break;
+ }
+ Entry = Entry->Flink;
+ HistoryEntry = NULL;
+ }
+
+ /* Nothing to revert to so delete the symlink */
+ if (! Matched)
+ RequestLinkTarget = NULL;
+ }
+ else if (! Matched)
+ {
+ /* Locate a previous symlink target as we did not get a hit earlier */
+ /* If we find one we need to remove it */
+ Entry = ListHead->Flink;
+ while (Entry != ListHead)
+ {
+ HistoryEntry = (PCSRSS_DOS_DEVICE_HISTORY_ENTRY)
+ CONTAINING_RECORD(Entry,
+ CSRSS_DOS_DEVICE_HISTORY_ENTRY,
+ Entry);
+ Matched =
+ ! RtlCompareUnicodeString(&RequestDeviceName,
+ &HistoryEntry->Device,
+ FALSE);
+ if (! Matched)
+ {
+ HistoryEntry = NULL;
+ Entry = Entry->Flink;
+ continue;
+ }
+
+ Matched = FALSE;
+ if (dwFlags & DDD_EXACT_MATCH_ON_REMOVE)
+ {
+ if (! RtlCompareUnicodeString(RequestLinkTarget,
+ &HistoryEntry->Target,
+ TRUE))
+ {
+ Matched = TRUE;
+ }
+ }
+ else if (RtlPrefixUnicodeString(RequestLinkTarget,
+ &HistoryEntry->Target,
+ TRUE))
+ {
+ Matched = TRUE;
+ }
+
+ if (Matched)
+ {
+ RemoveEntryList(&HistoryEntry->Entry);
+ break;
+ }
+ Entry = Entry->Flink;
+ HistoryEntry = NULL;
+ }
+
+ /* Leave existing symlink as is */
+ if (! Matched)
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ else
+ Status = STATUS_SUCCESS;
+ _SEH2_LEAVE;
+ }
+ }
+ else
+ {
+ AddHistory = TRUE;
+ }
+
+ Status = NtMakeTemporaryObject(LinkHandle);
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("NtMakeTemporaryObject(%wZ) failed (Status %lx)\n",
+ &DeviceName, Status);
+ _SEH2_LEAVE;
+ }
+
+ Status = NtClose(LinkHandle);
+ LinkHandle = NULL;
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("NtClose(%wZ) failed (Status %lx)\n",
+ &DeviceName, Status);
+ _SEH2_LEAVE;
+ }
+ }
+
+ /* Don't create symlink if we don't have a target */
+ if (! RequestLinkTarget || RequestLinkTarget->Length == 0)
+ _SEH2_LEAVE;
+
+ if (AddHistory)
+ {
+ HistoryEntry = (PCSRSS_DOS_DEVICE_HISTORY_ENTRY)
+ RtlAllocateHeap(Win32CsrApiHeap,
+ HEAP_ZERO_MEMORY,
+ sizeof(CSRSS_DOS_DEVICE_HISTORY_ENTRY));
+ if (! HistoryEntry)
+ {
+ DPRINT1("Failed to allocate memory\n");
+ Status = STATUS_NO_MEMORY;
+ _SEH2_LEAVE;
+ }
+
+ HistoryEntry->Target.Buffer =
+ RtlAllocateHeap(Win32CsrApiHeap,
+ HEAP_ZERO_MEMORY,
+ LinkTarget.Length);
+ if (! HistoryEntry->Target.Buffer)
+ {
+ DPRINT1("Failed to allocate memory\n");
+ Status = STATUS_NO_MEMORY;
+ _SEH2_LEAVE;
+ }
+ HistoryEntry->Target.Length =
+ HistoryEntry->Target.MaximumLength =
+ LinkTarget.Length;
+ RtlCopyUnicodeString(&HistoryEntry->Target,
+ &LinkTarget);
+
+ HistoryEntry->Device.Buffer =
+ RtlAllocateHeap(Win32CsrApiHeap,
+ HEAP_ZERO_MEMORY,
+ RequestDeviceName.Length);
+ if (! HistoryEntry->Device.Buffer)
+ {
+ DPRINT1("Failed to allocate memory\n");
+ Status = STATUS_NO_MEMORY;
+ _SEH2_LEAVE;
+ }
+ HistoryEntry->Device.Length =
+ HistoryEntry->Device.MaximumLength =
+ RequestDeviceName.Length;
+ RtlCopyUnicodeString(&HistoryEntry->Device,
+ &RequestDeviceName);
+
+ /* Remember previous symlink target for this device */
+ InsertHeadList(ListHead,
+ &HistoryEntry->Entry);
+ HistoryEntry = NULL;
+ }
+
+ RtlAllocateAndInitializeSid(&WorldAuthority,
+ 1,
+ SECURITY_WORLD_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ &WorldSid);
+
+ RtlAllocateAndInitializeSid(&SystemAuthority,
+ 1,
+ SECURITY_LOCAL_SYSTEM_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ &SystemSid);
+
+ RtlAllocateAndInitializeSid(&SystemAuthority,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ SECURITY_NULL_RID,
+ &AdminSid);
+
+ SidLength = RtlLengthSid(SystemSid) +
+ RtlLengthSid(AdminSid) +
+ RtlLengthSid(WorldSid);
+ Length = sizeof(ACL) + SidLength + 3 * sizeof(ACCESS_ALLOWED_ACE);
+
+ SecurityDescriptor = RtlAllocateHeap(Win32CsrApiHeap,
+ 0,
+ SECURITY_DESCRIPTOR_MIN_LENGTH + Length);
+ if (! SecurityDescriptor)
+ {
+ DPRINT1("Failed to allocate memory\n");
+ Status = STATUS_NO_MEMORY;
+ _SEH2_LEAVE;
+ }
+
+ Dacl = (PACL)((ULONG_PTR)SecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH);
+ Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION);
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlCreateSecurityDescriptor() failed (Status %lx)\n",
+ Status);
+ _SEH2_LEAVE;
+ }
+
+ Status = RtlCreateAcl(Dacl,
+ Length,
+ ACL_REVISION);
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlCreateAcl() failed (Status %lx)\n",
+ Status);
+ _SEH2_LEAVE;
+ }
+
+ (void) RtlAddAccessAllowedAce(Dacl,
+ ACL_REVISION,
+ GENERIC_ALL,
+ SystemSid);
+ (void) RtlAddAccessAllowedAce(Dacl,
+ ACL_REVISION,
+ GENERIC_ALL,
+ AdminSid);
+ (void) RtlAddAccessAllowedAce(Dacl,
+ ACL_REVISION,
+ STANDARD_RIGHTS_READ,
+ WorldSid);
+
+ Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor,
+ TRUE,
+ Dacl,
+ FALSE);
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlSetDaclSecurityDescriptor() failed (Status %lx)\n",
+ Status);
+ _SEH2_LEAVE;
+ }
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &DeviceName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ SecurityDescriptor);
+ Status = NtCreateSymbolicLinkObject(&LinkHandle,
+ SYMBOLIC_LINK_ALL_ACCESS,
+ &ObjectAttributes,
+ RequestLinkTarget);
+ if (NT_SUCCESS(Status))
+ {
+ Status = NtMakePermanentObject(LinkHandle);
+ if (! NT_SUCCESS(Status))
+ {
+ DPRINT1("NtMakePermanentObject(%wZ) failed (Status %lx)\n",
+ &DeviceName, Status);
+ }
+ }
+ else
+ {
+ DPRINT1("NtCreateSymbolicLinkObject(%wZ) failed (Status %lx)\n",
+ &DeviceName, Status);
+ }
+ }
+ _SEH2_FINALLY
+ {
+ (void) RtlLeaveCriticalSection(&Win32CsrDefineDosDeviceCritSec);
+ if (DeviceName.Buffer)
+ (void) RtlFreeHeap(Win32CsrApiHeap,
+ 0,
+ DeviceName.Buffer);
+ if (LinkTarget.Buffer)
+ (void) RtlFreeHeap(Win32CsrApiHeap,
+ 0,
+ LinkTarget.Buffer);
+ if (SecurityDescriptor)
+ (void) RtlFreeHeap(Win32CsrApiHeap,
+ 0,
+ SecurityDescriptor);
+ if (LinkHandle)
+ (void) NtClose(LinkHandle);
+ if (SystemSid)
+ (void) RtlFreeSid(SystemSid);
+ if (AdminSid)
+ (void) RtlFreeSid(AdminSid);
+ if (WorldSid)
+ (void) RtlFreeSid(WorldSid);
+ RtlFreeUnicodeString(&RequestDeviceName);
+ if (HistoryEntry)
+ {
+ if (HistoryEntry->Target.Buffer)
+ (void) RtlFreeHeap(Win32CsrApiHeap,
+ 0,
+ HistoryEntry->Target.Buffer);
+ if (HistoryEntry->Device.Buffer)
+ (void) RtlFreeHeap(Win32CsrApiHeap,
+ 0,
+ HistoryEntry->Device.Buffer);
+ (void) RtlFreeHeap(Win32CsrApiHeap,
+ 0,
+ HistoryEntry);
+ }
+ }
+ _SEH2_END
+
+ DPRINT("CsrDefineDosDevice Exit, Statux: 0x%x\n", Status);
+ return Status;
+}
+
+void CsrCleanupDefineDosDevice(void)
+{
+ PLIST_ENTRY Entry, ListHead;
+ PCSRSS_DOS_DEVICE_HISTORY_ENTRY HistoryEntry;
+
+ (void) RtlDeleteCriticalSection(&Win32CsrDefineDosDeviceCritSec);
+
+ ListHead = &DosDeviceHistory;
+ Entry = ListHead->Flink;
+ while (Entry != ListHead)
+ {
+ HistoryEntry = (PCSRSS_DOS_DEVICE_HISTORY_ENTRY)
+ CONTAINING_RECORD(Entry,
+ CSRSS_DOS_DEVICE_HISTORY_ENTRY,
+ Entry);
+ Entry = Entry->Flink;
+
+ if (HistoryEntry)
+ {
+ if (HistoryEntry->Target.Buffer)
+ (void) RtlFreeHeap(Win32CsrApiHeap,
+ 0,
+ HistoryEntry->Target.Buffer);
+ if (HistoryEntry->Device.Buffer)
+ (void) RtlFreeHeap(Win32CsrApiHeap,
+ 0,
+ HistoryEntry->Device.Buffer);
+ (void) RtlFreeHeap(Win32CsrApiHeap,
+ 0,
+ HistoryEntry);
+ }
+ }
+}
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: subsystem/win32/csrss/win32csr/file.h
+ * PURPOSE: File handling
+ * PROGRAMMERS: Pierre Schweitzer (pierre.schweitzer@reactos.org)
+ * NOTE: Belongs to basesrv.dll
+ */
+
+#pragma once
+
+#include "api.h"
+
+typedef struct tagCSRSS_DOS_DEVICE_HISTORY_ENTRY
+{
+ UNICODE_STRING Device;
+ UNICODE_STRING Target;
+ LIST_ENTRY Entry;
+} CSRSS_DOS_DEVICE_HISTORY_ENTRY, *PCSRSS_DOS_DEVICE_HISTORY_ENTRY;
+
+/* Api functions */
+CSR_API(CsrGetTempFile);
+CSR_API(CsrDefineDosDevice);
+
+/* functions */
+void CsrCleanupDefineDosDevice();
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: subsys/csrss/win32csr/guiconsole.c
+ * PURPOSE: Implementation of gui-mode consoles
+ */
+
+/* INCLUDES ******************************************************************/
+
+#define NDEBUG
+#include "w32csr.h"
+#include <debug.h>
+
+/* Not defined in any header file */
+extern VOID WINAPI PrivateCsrssManualGuiCheck(LONG Check);
+
+/* GLOBALS *******************************************************************/
+
+typedef struct GUI_CONSOLE_DATA_TAG
+{
+ HFONT Font;
+ unsigned CharWidth;
+ unsigned CharHeight;
+ BOOL CursorBlinkOn;
+ BOOL ForceCursorOff;
+ CRITICAL_SECTION Lock;
+ HMODULE ConsoleLibrary;
+ HANDLE hGuiInitEvent;
+ WCHAR FontName[LF_FACESIZE];
+ DWORD FontSize;
+ DWORD FontWeight;
+ DWORD FullScreen;
+ DWORD QuickEdit;
+ DWORD InsertMode;
+ DWORD WindowPosition;
+ DWORD UseRasterFonts;
+ COLORREF ScreenText;
+ COLORREF ScreenBackground;
+ COLORREF PopupBackground;
+ COLORREF PopupText;
+ COLORREF Colors[16];
+ WCHAR szProcessName[MAX_PATH];
+ BOOL WindowSizeLock;
+ POINT OldCursor;
+} GUI_CONSOLE_DATA, *PGUI_CONSOLE_DATA;
+
+#ifndef WM_APP
+#define WM_APP 0x8000
+#endif
+#define PM_CREATE_CONSOLE (WM_APP + 1)
+#define PM_DESTROY_CONSOLE (WM_APP + 2)
+
+#define CURSOR_BLINK_TIME 500
+#define DEFAULT_ATTRIB (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
+
+static BOOL ConsInitialized = FALSE;
+static HWND NotifyWnd;
+
+typedef struct _GUICONSOLE_MENUITEM
+{
+ UINT uID;
+ const struct _GUICONSOLE_MENUITEM *SubMenu;
+ WORD wCmdID;
+} GUICONSOLE_MENUITEM, *PGUICONSOLE_MENUITEM;
+
+static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems[] =
+{
+ { IDS_MARK, NULL, ID_SYSTEM_EDIT_MARK },
+ { IDS_COPY, NULL, ID_SYSTEM_EDIT_COPY },
+ { IDS_PASTE, NULL, ID_SYSTEM_EDIT_PASTE },
+ { IDS_SELECTALL, NULL, ID_SYSTEM_EDIT_SELECTALL },
+ { IDS_SCROLL, NULL, ID_SYSTEM_EDIT_SCROLL },
+ { IDS_FIND, NULL, ID_SYSTEM_EDIT_FIND },
+
+ { 0, NULL, 0 } /* End of list */
+};
+
+static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems[] =
+{
+ { (UINT)-1, NULL, 0 }, /* Separator */
+ { IDS_EDIT, GuiConsoleEditMenuItems, 0 },
+ { IDS_DEFAULTS, NULL, ID_SYSTEM_DEFAULTS },
+ { IDS_PROPERTIES, NULL, ID_SYSTEM_PROPERTIES },
+
+ { 0, NULL, 0 } /* End of list */
+};
+
+static const COLORREF s_Colors[] =
+{
+ RGB(0, 0, 0),
+ RGB(0, 0, 128),
+ RGB(0, 128, 0),
+ RGB(0, 128, 128),
+ RGB(128, 0, 0),
+ RGB(128, 0, 128),
+ RGB(128, 128, 0),
+ RGB(192, 192, 192),
+ RGB(128, 128, 128),
+ RGB(0, 0, 255),
+ RGB(0, 255, 0),
+ RGB(0, 255, 255),
+ RGB(255, 0, 0),
+ RGB(255, 0, 255),
+ RGB(255, 255, 0),
+ RGB(255, 255, 255)
+};
+
+#define GuiConsoleRGBFromAttribute(GuiData, Attribute) ((GuiData)->Colors[(Attribute) & 0xF])
+
+/* FUNCTIONS *****************************************************************/
+
+static VOID
+GuiConsoleAppendMenuItems(HMENU hMenu,
+ const GUICONSOLE_MENUITEM *Items)
+{
+ UINT i = 0;
+ WCHAR szMenuString[255];
+ HMENU hSubMenu;
+ HINSTANCE hInst = GetModuleHandleW(L"win32csr");
+
+ do
+ {
+ if (Items[i].uID != (UINT)-1)
+ {
+ if (LoadStringW(hInst,
+ Items[i].uID,
+ szMenuString,
+ sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
+ {
+ if (Items[i].SubMenu != NULL)
+ {
+ hSubMenu = CreatePopupMenu();
+ if (hSubMenu != NULL)
+ {
+ GuiConsoleAppendMenuItems(hSubMenu,
+ Items[i].SubMenu);
+
+ if (!AppendMenuW(hMenu,
+ MF_STRING | MF_POPUP,
+ (UINT_PTR)hSubMenu,
+ szMenuString))
+ {
+ DestroyMenu(hSubMenu);
+ }
+ }
+ }
+ else
+ {
+ AppendMenuW(hMenu,
+ MF_STRING,
+ Items[i].wCmdID,
+ szMenuString);
+ }
+ }
+ }
+ else
+ {
+ AppendMenuW(hMenu,
+ MF_SEPARATOR,
+ 0,
+ NULL);
+ }
+ i++;
+ } while(!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
+}
+
+static VOID
+GuiConsoleCreateSysMenu(PCSRSS_CONSOLE Console)
+{
+ HMENU hMenu;
+ hMenu = GetSystemMenu(Console->hWindow,
+ FALSE);
+ if (hMenu != NULL)
+ {
+ GuiConsoleAppendMenuItems(hMenu,
+ GuiConsoleMainMenuItems);
+ DrawMenuBar(Console->hWindow);
+ }
+}
+
+static VOID
+GuiConsoleGetDataPointers(HWND hWnd, PCSRSS_CONSOLE *Console, PGUI_CONSOLE_DATA *GuiData)
+{
+ *Console = (PCSRSS_CONSOLE) GetWindowLongPtrW(hWnd, GWL_USERDATA);
+ *GuiData = (NULL == *Console ? NULL : (*Console)->PrivateData);
+}
+
+static BOOL
+GuiConsoleOpenUserRegistryPathPerProcessId(DWORD ProcessId, PHANDLE hProcHandle, PHKEY hResult, REGSAM samDesired)
+{
+ HANDLE hProcessToken = NULL;
+ HANDLE hProcess;
+
+ BYTE Buffer[256];
+ DWORD Length = 0;
+ UNICODE_STRING SidName;
+ LONG res;
+ PTOKEN_USER TokUser;
+
+ hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | READ_CONTROL, FALSE, ProcessId);
+ if (!hProcess)
+ {
+ DPRINT("Error: OpenProcess failed(0x%x)\n", GetLastError());
+ return FALSE;
+ }
+
+ if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hProcessToken))
+ {
+ DPRINT("Error: OpenProcessToken failed(0x%x)\n", GetLastError());
+ CloseHandle(hProcess);
+ return FALSE;
+ }
+
+ if (!GetTokenInformation(hProcessToken, TokenUser, (PVOID)Buffer, sizeof(Buffer), &Length))
+ {
+ DPRINT("Error: GetTokenInformation failed(0x%x)\n",GetLastError());
+ CloseHandle(hProcessToken);
+ CloseHandle(hProcess);
+ return FALSE;
+ }
+
+ TokUser = ((PTOKEN_USER)Buffer)->User.Sid;
+ if (!NT_SUCCESS(RtlConvertSidToUnicodeString(&SidName, TokUser, TRUE)))
+ {
+ DPRINT("Error: RtlConvertSidToUnicodeString failed(0x%x)\n", GetLastError());
+ CloseHandle(hProcessToken);
+ CloseHandle(hProcess);
+ return FALSE;
+ }
+
+ res = RegOpenKeyExW(HKEY_USERS, SidName.Buffer, 0, samDesired, hResult);
+ RtlFreeUnicodeString(&SidName);
+
+ CloseHandle(hProcessToken);
+ if (res != ERROR_SUCCESS)
+ {
+ CloseHandle(hProcess);
+ return FALSE;
+ }
+
+ if (hProcHandle)
+ *hProcHandle = hProcess;
+ else
+ CloseHandle(hProcess);
+
+ return TRUE;
+}
+
+static BOOL
+GuiConsoleOpenUserSettings(PGUI_CONSOLE_DATA GuiData, DWORD ProcessId, PHKEY hSubKey, REGSAM samDesired, BOOL bCreate)
+{
+ WCHAR szProcessName[MAX_PATH];
+ WCHAR szBuffer[MAX_PATH];
+ UINT fLength, wLength;
+ DWORD dwBitmask, dwLength;
+ WCHAR CurDrive[] = { 'A',':', 0 };
+ HANDLE hProcess;
+ HKEY hKey;
+ WCHAR * ptr;
+
+ /*
+ * console properties are stored under
+ * HKCU\Console\*
+ *
+ * There are 3 ways to store console properties
+ *
+ * 1. use console title as subkey name
+ * i.e. cmd.exe
+ *
+ * 2. use application name as subkey name
+ *
+ * 3. use unexpanded path to console application.
+ * i.e. %SystemRoot%_system32_cmd.exe
+ */
+
+ DPRINT("GuiConsoleOpenUserSettings entered\n");
+
+ if (!GuiConsoleOpenUserRegistryPathPerProcessId(ProcessId, &hProcess, &hKey, samDesired))
+ {
+ DPRINT("GuiConsoleOpenUserRegistryPathPerProcessId failed\n");
+ return FALSE;
+ }
+
+ /* FIXME we do not getting the process name so no menu will be loading, why ?*/
+ fLength = GetProcessImageFileNameW(hProcess, szProcessName, sizeof(GuiData->szProcessName) / sizeof(WCHAR));
+ CloseHandle(hProcess);
+
+ //DPRINT1("szProcessName3 : %S\n",szProcessName);
+
+ if (!fLength)
+ {
+ DPRINT("GetProcessImageFileNameW failed(0x%x)ProcessId %d\n", GetLastError(), ProcessId);
+ return FALSE;
+ }
+ /*
+ * try the process name as path
+ */
+
+ ptr = wcsrchr(szProcessName, L'\\');
+ wcscpy(GuiData->szProcessName, ptr);
+
+ swprintf(szBuffer, L"Console%s",ptr);
+ DPRINT("#1 Path : %S\n", szBuffer);
+
+ if (bCreate)
+ {
+ if (RegCreateKeyW(hKey, szBuffer, hSubKey) == ERROR_SUCCESS)
+ {
+ RegCloseKey(hKey);
+ return TRUE;
+ }
+ RegCloseKey(hKey);
+ return FALSE;
+ }
+
+ if (RegOpenKeyExW(hKey, szBuffer, 0, samDesired, hSubKey) == ERROR_SUCCESS)
+ {
+ RegCloseKey(hKey);
+ return TRUE;
+ }
+
+ /*
+ * try the "Shortcut to processname" as path
+ * FIXME: detect wheter the process was started as a shortcut
+ */
+
+ swprintf(szBuffer, L"Console\\Shortcut to %S", ptr);
+ DPRINT("#2 Path : %S\n", szBuffer);
+ if (RegOpenKeyExW(hKey, szBuffer, 0, samDesired, hSubKey) == ERROR_SUCCESS)
+ {
+ swprintf(GuiData->szProcessName, L"Shortcut to %S", ptr);
+ RegCloseKey(hKey);
+ return TRUE;
+ }
+
+ /*
+ * if the path contains \\Device\\HarddiskVolume1\... remove it
+ */
+
+ if (szProcessName[0] == L'\\')
+ {
+ dwBitmask = GetLogicalDrives();
+ while(dwBitmask)
+ {
+ if (dwBitmask & 0x1)
+ {
+ dwLength = QueryDosDeviceW(CurDrive, szBuffer, MAX_PATH);
+ if (dwLength)
+ {
+ if (!memcmp(szBuffer, szProcessName, (dwLength-2)*sizeof(WCHAR)))
+ {
+ wcscpy(szProcessName, CurDrive);
+ RtlMoveMemory(&szProcessName[2], &szProcessName[dwLength-1], fLength - dwLength -1);
+ break;
+ }
+ }
+ }
+ dwBitmask = (dwBitmask >> 1);
+ CurDrive[0]++;
+ }
+ }
+
+ /*
+ * last attempt: check whether the file is under %SystemRoot%
+ * and use path like Console\%SystemRoot%_dir_dir2_file.exe
+ */
+
+ wLength = GetWindowsDirectoryW(szBuffer, MAX_PATH);
+ if (wLength)
+ {
+ if (!wcsncmp(szProcessName, szBuffer, wLength))
+ {
+ /* replace slashes by underscores */
+ while((ptr = wcschr(szProcessName, L'\\')))
+ ptr[0] = L'_';
+
+ swprintf(szBuffer, L"Console\\%%SystemRoot%%%S", &szProcessName[wLength]);
+ DPRINT("#3 Path : %S\n", szBuffer);
+ if (RegOpenKeyExW(hKey, szBuffer, 0, samDesired, hSubKey) == ERROR_SUCCESS)
+ {
+ swprintf(GuiData->szProcessName, L"%%SystemRoot%%%S", &szProcessName[wLength]);
+ RegCloseKey(hKey);
+ return TRUE;
+ }
+ }
+ }
+ RegCloseKey(hKey);
+ return FALSE;
+}
+
+static VOID
+GuiConsoleWriteUserSettings(PCSRSS_CONSOLE Console, PGUI_CONSOLE_DATA GuiData)
+{
+ HKEY hKey;
+ PCSR_PROCESS ProcessData;
+
+ if (Console->ProcessList.Flink == &Console->ProcessList)
+ {
+ DPRINT("GuiConsoleWriteUserSettings: No Process!!!\n");
+ return;
+ }
+ ProcessData = CONTAINING_RECORD(Console->ProcessList.Flink, CSR_PROCESS, ConsoleLink);
+ if (!GuiConsoleOpenUserSettings(GuiData, PtrToUlong(ProcessData->ClientId.UniqueProcess), &hKey, KEY_READ | KEY_WRITE, TRUE))
+ {
+ return;
+ }
+
+ if (Console->ActiveBuffer->CursorInfo.dwSize <= 1)
+ {
+ RegDeleteKeyW(hKey, L"CursorSize");
+ }
+ else
+ {
+ RegSetValueExW(hKey, L"CursorSize", 0, REG_DWORD, (const BYTE *)&Console->ActiveBuffer->CursorInfo.dwSize, sizeof(DWORD));
+ }
+
+ if (Console->NumberOfHistoryBuffers == 5)
+ {
+ RegDeleteKeyW(hKey, L"NumberOfHistoryBuffers");
+ }
+ else
+ {
+ DWORD Temp = Console->NumberOfHistoryBuffers;
+ RegSetValueExW(hKey, L"NumberOfHistoryBuffers", 0, REG_DWORD, (const BYTE *)&Temp, sizeof(DWORD));
+ }
+
+ if (Console->HistoryBufferSize == 50)
+ {
+ RegDeleteKeyW(hKey, L"HistoryBufferSize");
+ }
+ else
+ {
+ DWORD Temp = Console->HistoryBufferSize;
+ RegSetValueExW(hKey, L"HistoryBufferSize", 0, REG_DWORD, (const BYTE *)&Temp, sizeof(DWORD));
+ }
+
+ if (GuiData->FullScreen == FALSE)
+ {
+ RegDeleteKeyW(hKey, L"FullScreen");
+ }
+ else
+ {
+ RegSetValueExW(hKey, L"FullScreen", 0, REG_DWORD, (const BYTE *)&GuiData->FullScreen, sizeof(DWORD));
+ }
+
+ if ( GuiData->QuickEdit == FALSE)
+ {
+ RegDeleteKeyW(hKey, L"QuickEdit");
+ }
+ else
+ {
+ RegSetValueExW(hKey, L"QuickEdit", 0, REG_DWORD, (const BYTE *)&GuiData->QuickEdit, sizeof(DWORD));
+ }
+
+ if (GuiData->InsertMode == TRUE)
+ {
+ RegDeleteKeyW(hKey, L"InsertMode");
+ }
+ else
+ {
+ RegSetValueExW(hKey, L"InsertMode", 0, REG_DWORD, (const BYTE *)&GuiData->InsertMode, sizeof(DWORD));
+ }
+
+ if (Console->HistoryNoDup == FALSE)
+ {
+ RegDeleteKeyW(hKey, L"HistoryNoDup");
+ }
+ else
+ {
+ DWORD Temp = Console->HistoryNoDup;
+ RegSetValueExW(hKey, L"HistoryNoDup", 0, REG_DWORD, (const BYTE *)&Temp, sizeof(DWORD));
+ }
+
+ if (GuiData->ScreenText == RGB(192, 192, 192))
+ {
+ /*
+ * MS uses console attributes instead of real color
+ */
+ RegDeleteKeyW(hKey, L"ScreenText");
+ }
+ else
+ {
+ RegSetValueExW(hKey, L"ScreenText", 0, REG_DWORD, (const BYTE *)&GuiData->ScreenText, sizeof(COLORREF));
+ }
+
+ if (GuiData->ScreenBackground == RGB(0, 0, 0))
+ {
+ RegDeleteKeyW(hKey, L"ScreenBackground");
+ }
+ else
+ {
+ RegSetValueExW(hKey, L"ScreenBackground", 0, REG_DWORD, (const BYTE *)&GuiData->ScreenBackground, sizeof(COLORREF));
+ }
+
+ RegCloseKey(hKey);
+}
+
+static void
+GuiConsoleReadUserSettings(HKEY hKey, PCSRSS_CONSOLE Console, PGUI_CONSOLE_DATA GuiData, PCSRSS_SCREEN_BUFFER Buffer)
+{
+ DWORD dwNumSubKeys = 0;
+ DWORD dwIndex;
+ DWORD dwValueName;
+ DWORD dwValue;
+ DWORD dwType;
+ WCHAR szValueName[MAX_PATH];
+ WCHAR szValue[LF_FACESIZE] = L"\0";
+ DWORD Value;
+
+ if (RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwNumSubKeys, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
+ {
+ DPRINT("GuiConsoleReadUserSettings: RegQueryInfoKey failed\n");
+ return;
+ }
+
+ DPRINT("GuiConsoleReadUserSettings entered dwNumSubKeys %d\n", dwNumSubKeys);
+
+ for (dwIndex = 0; dwIndex < dwNumSubKeys; dwIndex++)
+ {
+ dwValue = sizeof(Value);
+ dwValueName = MAX_PATH;
+
+ if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, &dwType, (BYTE*)&Value, &dwValue) != ERROR_SUCCESS)
+ {
+ if (dwType == REG_SZ)
+ {
+ /*
+ * retry in case of string value
+ */
+ dwValue = sizeof(szValue);
+ dwValueName = LF_FACESIZE;
+ if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, NULL, (BYTE*)szValue, &dwValue) != ERROR_SUCCESS)
+ break;
+ }
+ else
+ break;
+ }
+ if (!wcscmp(szValueName, L"CursorSize"))
+ {
+ if (Value == 0x32)
+ {
+ Buffer->CursorInfo.dwSize = Value;
+ }
+ else if (Value == 0x64)
+ {
+ Buffer->CursorInfo.dwSize = Value;
+ }
+ }
+ else if (!wcscmp(szValueName, L"ScreenText"))
+ {
+ GuiData->ScreenText = Value;
+ }
+ else if (!wcscmp(szValueName, L"ScreenBackground"))
+ {
+ GuiData->ScreenBackground = Value;
+ }
+ else if (!wcscmp(szValueName, L"FaceName"))
+ {
+ wcscpy(GuiData->FontName, szValue);
+ }
+ else if (!wcscmp(szValueName, L"FontSize"))
+ {
+ GuiData->FontSize = Value;
+ }
+ else if (!wcscmp(szValueName, L"FontWeight"))
+ {
+ GuiData->FontWeight = Value;
+ }
+ else if (!wcscmp(szValueName, L"HistoryNoDup"))
+ {
+ Console->HistoryNoDup = Value;
+ }
+ else if (!wcscmp(szValueName, L"WindowSize"))
+ {
+ Console->Size.X = LOWORD(Value);
+ Console->Size.Y = HIWORD(Value);
+ }
+ else if (!wcscmp(szValueName, L"ScreenBufferSize"))
+ {
+ if(Buffer)
+ {
+ Buffer->MaxX = LOWORD(Value);
+ Buffer->MaxY = HIWORD(Value);
+ }
+ }
+ else if (!wcscmp(szValueName, L"FullScreen"))
+ {
+ GuiData->FullScreen = Value;
+ }
+ else if (!wcscmp(szValueName, L"QuickEdit"))
+ {
+ GuiData->QuickEdit = Value;
+ }
+ else if (!wcscmp(szValueName, L"InsertMode"))
+ {
+ GuiData->InsertMode = Value;
+ }
+ }
+}
+static VOID
+GuiConsoleUseDefaults(PCSRSS_CONSOLE Console, PGUI_CONSOLE_DATA GuiData, PCSRSS_SCREEN_BUFFER Buffer)
+{
+ /*
+ * init guidata with default properties
+ */
+
+ wcscpy(GuiData->FontName, L"DejaVu Sans Mono");
+ GuiData->FontSize = 0x0008000C; // font is 8x12
+ GuiData->FontWeight = FW_NORMAL;
+ GuiData->FullScreen = FALSE;
+ GuiData->QuickEdit = FALSE;
+ GuiData->InsertMode = TRUE;
+ GuiData->ScreenText = RGB(192, 192, 192);
+ GuiData->ScreenBackground = RGB(0, 0, 0);
+ GuiData->PopupText = RGB(128, 0, 128);
+ GuiData->PopupBackground = RGB(255, 255, 255);
+ GuiData->WindowPosition = UINT_MAX;
+ GuiData->UseRasterFonts = TRUE;
+ memcpy(GuiData->Colors, s_Colors, sizeof(s_Colors));
+
+ Console->HistoryBufferSize = 50;
+ Console->NumberOfHistoryBuffers = 5;
+ Console->HistoryNoDup = FALSE;
+ Console->Size.X = 80;
+ Console->Size.Y = 25;
+
+ if (Buffer)
+ {
+ Buffer->MaxX = 80;
+ Buffer->MaxY = 300;
+ Buffer->CursorInfo.bVisible = TRUE;
+ Buffer->CursorInfo.dwSize = CSR_DEFAULT_CURSOR_SIZE;
+ }
+}
+
+VOID
+FASTCALL
+GuiConsoleInitScrollbar(PCSRSS_CONSOLE Console, HWND hwnd)
+{
+ SCROLLINFO sInfo;
+ PGUI_CONSOLE_DATA GuiData = Console->PrivateData;
+
+ DWORD Width = Console->Size.X * GuiData->CharWidth + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
+ DWORD Height = Console->Size.Y * GuiData->CharHeight + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
+
+ /* set scrollbar sizes */
+ sInfo.cbSize = sizeof(SCROLLINFO);
+ sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ sInfo.nMin = 0;
+ if (Console->ActiveBuffer->MaxY > Console->Size.Y)
+ {
+ sInfo.nMax = Console->ActiveBuffer->MaxY - 1;
+ sInfo.nPage = Console->Size.Y;
+ sInfo.nPos = Console->ActiveBuffer->ShowY;
+ SetScrollInfo(hwnd, SB_VERT, &sInfo, TRUE);
+ Width += GetSystemMetrics(SM_CXVSCROLL);
+ ShowScrollBar(hwnd, SB_VERT, TRUE);
+ }
+ else
+ {
+ ShowScrollBar(hwnd, SB_VERT, FALSE);
+ }
+
+ if (Console->ActiveBuffer->MaxX > Console->Size.X)
+ {
+ sInfo.nMax = Console->ActiveBuffer->MaxX - 1;
+ sInfo.nPage = Console->Size.X;
+ sInfo.nPos = Console->ActiveBuffer->ShowX;
+ SetScrollInfo(hwnd, SB_HORZ, &sInfo, TRUE);
+ Height += GetSystemMetrics(SM_CYHSCROLL);
+ ShowScrollBar(hwnd, SB_HORZ, TRUE);
+
+ }
+ else
+ {
+ ShowScrollBar(hwnd, SB_HORZ, FALSE);
+ }
+
+ SetWindowPos(hwnd, NULL, 0, 0, Width, Height,
+ SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
+}
+
+static BOOL
+GuiConsoleHandleNcCreate(HWND hWnd, CREATESTRUCTW *Create)
+{
+ PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Create->lpCreateParams;
+ PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)Console->PrivateData;
+ HDC Dc;
+ HFONT OldFont;
+ TEXTMETRICW Metrics;
+ SIZE CharSize;
+ PCSR_PROCESS ProcessData;
+ HKEY hKey;
+
+ Console->hWindow = hWnd;
+
+ if (NULL == GuiData)
+ {
+ DPRINT1("GuiConsoleNcCreate: HeapAlloc failed\n");
+ return FALSE;
+ }
+
+ GuiConsoleUseDefaults(Console, GuiData, Console->ActiveBuffer);
+ if (Console->ProcessList.Flink != &Console->ProcessList)
+ {
+ ProcessData = CONTAINING_RECORD(Console->ProcessList.Flink, CSR_PROCESS, ConsoleLink);
+ if (GuiConsoleOpenUserSettings(GuiData, PtrToUlong(ProcessData->ClientId.UniqueProcess), &hKey, KEY_READ, FALSE))
+ {
+ GuiConsoleReadUserSettings(hKey, Console, GuiData, Console->ActiveBuffer);
+ RegCloseKey(hKey);
+ }
+ }
+
+ InitializeCriticalSection(&GuiData->Lock);
+
+ GuiData->Font = CreateFontW(LOWORD(GuiData->FontSize),
+ 0, //HIWORD(GuiData->FontSize),
+ 0,
+ TA_BASELINE,
+ GuiData->FontWeight,
+ FALSE,
+ FALSE,
+ FALSE,
+ OEM_CHARSET,
+ OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ NONANTIALIASED_QUALITY, FIXED_PITCH | FF_DONTCARE,
+ GuiData->FontName);
+ if (NULL == GuiData->Font)
+ {
+ DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
+ DeleteCriticalSection(&GuiData->Lock);
+ HeapFree(Win32CsrApiHeap, 0, GuiData);
+ return FALSE;
+ }
+ Dc = GetDC(hWnd);
+ if (NULL == Dc)
+ {
+ DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
+ DeleteObject(GuiData->Font);
+ DeleteCriticalSection(&GuiData->Lock);
+ HeapFree(Win32CsrApiHeap, 0, GuiData);
+ return FALSE;
+ }
+ OldFont = SelectObject(Dc, GuiData->Font);
+ if (NULL == OldFont)
+ {
+ DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
+ ReleaseDC(hWnd, Dc);
+ DeleteObject(GuiData->Font);
+ DeleteCriticalSection(&GuiData->Lock);
+ HeapFree(Win32CsrApiHeap, 0, GuiData);
+ return FALSE;
+ }
+ if (! GetTextMetricsW(Dc, &Metrics))
+ {
+ DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
+ SelectObject(Dc, OldFont);
+ ReleaseDC(hWnd, Dc);
+ DeleteObject(GuiData->Font);
+ DeleteCriticalSection(&GuiData->Lock);
+ HeapFree(Win32CsrApiHeap, 0, GuiData);
+ return FALSE;
+ }
+ GuiData->CharWidth = Metrics.tmMaxCharWidth;
+ GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
+
+ /* Measure real char width more precisely if possible. */
+ if (GetTextExtentPoint32W(Dc, L"R", 1, &CharSize))
+ GuiData->CharWidth = CharSize.cx;
+
+ SelectObject(Dc, OldFont);
+
+ ReleaseDC(hWnd, Dc);
+ GuiData->CursorBlinkOn = TRUE;
+ GuiData->ForceCursorOff = FALSE;
+
+ DPRINT("Console %p GuiData %p\n", Console, GuiData);
+ Console->PrivateData = GuiData;
+ SetWindowLongPtrW(hWnd, GWL_USERDATA, (DWORD_PTR) Console);
+
+ SetTimer(hWnd, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
+ GuiConsoleCreateSysMenu(Console);
+
+ GuiData->WindowSizeLock = TRUE;
+ GuiConsoleInitScrollbar(Console, hWnd);
+ GuiData->WindowSizeLock = FALSE;
+
+ SetEvent(GuiData->hGuiInitEvent);
+
+ return (BOOL) DefWindowProcW(hWnd, WM_NCCREATE, 0, (LPARAM) Create);
+}
+
+static VOID
+SmallRectToRect(PCSRSS_CONSOLE Console, PRECT Rect, PSMALL_RECT SmallRect)
+{
+ PCSRSS_SCREEN_BUFFER Buffer = Console->ActiveBuffer;
+ PGUI_CONSOLE_DATA GuiData = Console->PrivateData;
+ Rect->left = (SmallRect->Left - Buffer->ShowX) * GuiData->CharWidth;
+ Rect->top = (SmallRect->Top - Buffer->ShowY) * GuiData->CharHeight;
+ Rect->right = (SmallRect->Right + 1 - Buffer->ShowX) * GuiData->CharWidth;
+ Rect->bottom = (SmallRect->Bottom + 1 - Buffer->ShowY) * GuiData->CharHeight;
+}
+
+static VOID
+GuiConsoleUpdateSelection(PCSRSS_CONSOLE Console, PCOORD coord)
+{
+ RECT oldRect, newRect;
+ HWND hWnd = Console->hWindow;
+
+ SmallRectToRect(Console, &oldRect, &Console->Selection.srSelection);
+
+ if(coord != NULL)
+ {
+ SMALL_RECT rc;
+ /* exchange left/top with right/bottom if required */
+ rc.Left = min(Console->Selection.dwSelectionAnchor.X, coord->X);
+ rc.Top = min(Console->Selection.dwSelectionAnchor.Y, coord->Y);
+ rc.Right = max(Console->Selection.dwSelectionAnchor.X, coord->X);
+ rc.Bottom = max(Console->Selection.dwSelectionAnchor.Y, coord->Y);
+
+ SmallRectToRect(Console, &newRect, &rc);
+
+ if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
+ {
+ if (memcmp(&rc, &Console->Selection.srSelection, sizeof(SMALL_RECT)) != 0)
+ {
+ HRGN rgn1, rgn2;
+
+ /* calculate the region that needs to be updated */
+ if((rgn1 = CreateRectRgnIndirect(&oldRect)))
+ {
+ if((rgn2 = CreateRectRgnIndirect(&newRect)))
+ {
+ if(CombineRgn(rgn1, rgn2, rgn1, RGN_XOR) != ERROR)
+ {
+ InvalidateRgn(hWnd, rgn1, FALSE);
+ }
+
+ DeleteObject(rgn2);
+ }
+ DeleteObject(rgn1);
+ }
+ }
+ }
+ else
+ {
+ InvalidateRect(hWnd, &newRect, FALSE);
+ }
+ Console->Selection.dwFlags |= CONSOLE_SELECTION_NOT_EMPTY;
+ Console->Selection.srSelection = rc;
+ ConioPause(Console, PAUSED_FROM_SELECTION);
+ }
+ else
+ {
+ /* clear the selection */
+ if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
+ {
+ InvalidateRect(hWnd, &oldRect, FALSE);
+ }
+ Console->Selection.dwFlags = CONSOLE_NO_SELECTION;
+ ConioUnpause(Console, PAUSED_FROM_SELECTION);
+ }
+}
+
+
+static VOID
+GuiConsolePaint(PCSRSS_CONSOLE Console,
+ PGUI_CONSOLE_DATA GuiData,
+ HDC hDC,
+ PRECT rc)
+{
+ PCSRSS_SCREEN_BUFFER Buff;
+ ULONG TopLine, BottomLine, LeftChar, RightChar;
+ ULONG Line, Char, Start;
+ PBYTE From;
+ PWCHAR To;
+ BYTE LastAttribute, Attribute;
+ ULONG CursorX, CursorY, CursorHeight;
+ HBRUSH CursorBrush, OldBrush;
+ HFONT OldFont;
+
+ Buff = Console->ActiveBuffer;
+
+ EnterCriticalSection(&Buff->Header.Console->Lock);
+
+ TopLine = rc->top / GuiData->CharHeight + Buff->ShowY;
+ BottomLine = (rc->bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1 + Buff->ShowY;
+ LeftChar = rc->left / GuiData->CharWidth + Buff->ShowX;
+ RightChar = (rc->right + (GuiData->CharWidth - 1)) / GuiData->CharWidth - 1 + Buff->ShowX;
+ LastAttribute = ConioCoordToPointer(Buff, LeftChar, TopLine)[1];
+
+ SetTextColor(hDC, GuiConsoleRGBFromAttribute(GuiData, LastAttribute));
+ SetBkColor(hDC, GuiConsoleRGBFromAttribute(GuiData, LastAttribute >> 4));
+
+ if (BottomLine >= Buff->MaxY) BottomLine = Buff->MaxY - 1;
+ if (RightChar >= Buff->MaxX) RightChar = Buff->MaxX - 1;
+
+ OldFont = SelectObject(hDC,
+ GuiData->Font);
+
+ for (Line = TopLine; Line <= BottomLine; Line++)
+ {
+ WCHAR LineBuffer[80];
+ From = ConioCoordToPointer(Buff, LeftChar, Line);
+ Start = LeftChar;
+ To = LineBuffer;
+
+ for (Char = LeftChar; Char <= RightChar; Char++)
+ {
+ if (*(From + 1) != LastAttribute || (Char - Start == sizeof(LineBuffer) / sizeof(WCHAR)))
+ {
+ TextOutW(hDC,
+ (Start - Buff->ShowX) * GuiData->CharWidth,
+ (Line - Buff->ShowY) * GuiData->CharHeight,
+ LineBuffer,
+ Char - Start);
+ Start = Char;
+ To = LineBuffer;
+ Attribute = *(From + 1);
+ if (Attribute != LastAttribute)
+ {
+ SetTextColor(hDC, GuiConsoleRGBFromAttribute(GuiData, Attribute));
+ SetBkColor(hDC, GuiConsoleRGBFromAttribute(GuiData, Attribute >> 4));
+ LastAttribute = Attribute;
+ }
+ }
+
+ MultiByteToWideChar(Console->OutputCodePage,
+ 0,
+ (PCHAR)From,
+ 1,
+ To,
+ 1);
+ To++;
+ From += 2;
+ }
+
+ TextOutW(hDC,
+ (Start - Buff->ShowX) * GuiData->CharWidth,
+ (Line - Buff->ShowY) * GuiData->CharHeight,
+ LineBuffer,
+ RightChar - Start + 1);
+ }
+
+ if (Buff->CursorInfo.bVisible && GuiData->CursorBlinkOn &&
+ !GuiData->ForceCursorOff)
+ {
+ CursorX = Buff->CurrentX;
+ CursorY = Buff->CurrentY;
+ if (LeftChar <= CursorX && CursorX <= RightChar &&
+ TopLine <= CursorY && CursorY <= BottomLine)
+ {
+ CursorHeight = ConioEffectiveCursorSize(Console, GuiData->CharHeight);
+ From = ConioCoordToPointer(Buff, Buff->CurrentX, Buff->CurrentY) + 1;
+
+ if (*From != DEFAULT_ATTRIB)
+ {
+ CursorBrush = CreateSolidBrush(GuiConsoleRGBFromAttribute(GuiData, *From));
+ }
+ else
+ {
+ CursorBrush = CreateSolidBrush(GuiData->ScreenText);
+ }
+
+ OldBrush = SelectObject(hDC,
+ CursorBrush);
+ PatBlt(hDC,
+ (CursorX - Buff->ShowX) * GuiData->CharWidth,
+ (CursorY - Buff->ShowY) * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight),
+ GuiData->CharWidth,
+ CursorHeight,
+ PATCOPY);
+ SelectObject(hDC,
+ OldBrush);
+ DeleteObject(CursorBrush);
+ }
+ }
+
+ LeaveCriticalSection(&Buff->Header.Console->Lock);
+
+ SelectObject(hDC,
+ OldFont);
+}
+
+static VOID
+GuiConsoleHandlePaint(HWND hWnd, HDC hDCPaint)
+{
+ HDC hDC;
+ PAINTSTRUCT ps;
+ PCSRSS_CONSOLE Console;
+ PGUI_CONSOLE_DATA GuiData;
+
+ hDC = BeginPaint(hWnd, &ps);
+ if (hDC != NULL &&
+ ps.rcPaint.left < ps.rcPaint.right &&
+ ps.rcPaint.top < ps.rcPaint.bottom)
+ {
+ GuiConsoleGetDataPointers(hWnd,
+ &Console,
+ &GuiData);
+ if (Console != NULL && GuiData != NULL &&
+ Console->ActiveBuffer != NULL)
+ {
+ if (Console->ActiveBuffer->Buffer != NULL)
+ {
+ EnterCriticalSection(&GuiData->Lock);
+
+ GuiConsolePaint(Console,
+ GuiData,
+ hDC,
+ &ps.rcPaint);
+
+ if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
+ {
+ RECT rc;
+ SmallRectToRect(Console, &rc, &Console->Selection.srSelection);
+
+ /* invert the selection */
+ if (IntersectRect(&rc,
+ &ps.rcPaint,
+ &rc))
+ {
+ PatBlt(hDC,
+ rc.left,
+ rc.top,
+ rc.right - rc.left,
+ rc.bottom - rc.top,
+ DSTINVERT);
+ }
+ }
+
+ LeaveCriticalSection(&GuiData->Lock);
+ }
+ }
+
+ }
+ EndPaint(hWnd, &ps);
+}
+
+static VOID
+GuiConsoleHandleKey(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ PCSRSS_CONSOLE Console;
+ PGUI_CONSOLE_DATA GuiData;
+ MSG Message;
+
+ GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
+ Message.hwnd = hWnd;
+ Message.message = msg;
+ Message.wParam = wParam;
+ Message.lParam = lParam;
+
+ if(msg == WM_CHAR || msg == WM_SYSKEYDOWN)
+ {
+ /* clear the selection */
+ GuiConsoleUpdateSelection(Console, NULL);
+ }
+
+ ConioProcessKey(&Message, Console, FALSE);
+}
+
+static VOID WINAPI
+GuiDrawRegion(PCSRSS_CONSOLE Console, SMALL_RECT *Region)
+{
+ RECT RegionRect;
+ SmallRectToRect(Console, &RegionRect, Region);
+ InvalidateRect(Console->hWindow, &RegionRect, FALSE);
+}
+
+static VOID
+GuiInvalidateCell(PCSRSS_CONSOLE Console, UINT x, UINT y)
+{
+ SMALL_RECT CellRect = { x, y, x, y };
+ GuiDrawRegion(Console, &CellRect);
+}
+
+static VOID WINAPI
+GuiWriteStream(PCSRSS_CONSOLE Console, SMALL_RECT *Region, LONG CursorStartX, LONG CursorStartY,
+ UINT ScrolledLines, CHAR *Buffer, UINT Length)
+{
+ PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA) Console->PrivateData;
+ PCSRSS_SCREEN_BUFFER Buff = Console->ActiveBuffer;
+ LONG CursorEndX, CursorEndY;
+ RECT ScrollRect;
+
+ if (NULL == Console->hWindow || NULL == GuiData)
+ {
+ return;
+ }
+
+ if (0 != ScrolledLines)
+ {
+ ScrollRect.left = 0;
+ ScrollRect.top = 0;
+ ScrollRect.right = Console->Size.X * GuiData->CharWidth;
+ ScrollRect.bottom = Region->Top * GuiData->CharHeight;
+
+ ScrollWindowEx(Console->hWindow,
+ 0,
+ -(ScrolledLines * GuiData->CharHeight),
+ &ScrollRect,
+ NULL,
+ NULL,
+ NULL,
+ SW_INVALIDATE);
+ }
+
+ GuiDrawRegion(Console, Region);
+
+ if (CursorStartX < Region->Left || Region->Right < CursorStartX
+ || CursorStartY < Region->Top || Region->Bottom < CursorStartY)
+ {
+ GuiInvalidateCell(Console, CursorStartX, CursorStartY);
+ }
+
+ CursorEndX = Buff->CurrentX;
+ CursorEndY = Buff->CurrentY;
+ if ((CursorEndX < Region->Left || Region->Right < CursorEndX
+ || CursorEndY < Region->Top || Region->Bottom < CursorEndY)
+ && (CursorEndX != CursorStartX || CursorEndY != CursorStartY))
+ {
+ GuiInvalidateCell(Console, CursorEndX, CursorEndY);
+ }
+
+ // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
+ // repaint the window without having it just freeze up and stay on the screen permanently.
+ GuiData->CursorBlinkOn = TRUE;
+ SetTimer(Console->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
+}
+
+static BOOL WINAPI
+GuiSetCursorInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
+{
+ if (Console->ActiveBuffer == Buff)
+ {
+ GuiInvalidateCell(Console, Buff->CurrentX, Buff->CurrentY);
+ }
+
+ return TRUE;
+}
+
+static BOOL WINAPI
+GuiSetScreenInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff, UINT OldCursorX, UINT OldCursorY)
+{
+ if (Console->ActiveBuffer == Buff)
+ {
+ /* Redraw char at old position (removes cursor) */
+ GuiInvalidateCell(Console, OldCursorX, OldCursorY);
+ /* Redraw char at new position (shows cursor) */
+ GuiInvalidateCell(Console, Buff->CurrentX, Buff->CurrentY);
+ }
+
+ return TRUE;
+}
+
+static BOOL WINAPI
+GuiUpdateScreenInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
+{
+ PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA) Console->PrivateData;
+
+ if (Console->ActiveBuffer == Buff)
+ {
+ GuiData->ScreenText = GuiConsoleRGBFromAttribute(GuiData, Buff->DefaultAttrib);
+ GuiData->ScreenBackground = GuiConsoleRGBFromAttribute(GuiData, Buff->DefaultAttrib >> 4);
+ }
+
+ return TRUE;
+}
+
+static VOID
+GuiConsoleHandleTimer(HWND hWnd)
+{
+ PCSRSS_CONSOLE Console;
+ PGUI_CONSOLE_DATA GuiData;
+ PCSRSS_SCREEN_BUFFER Buff;
+
+ SetTimer(hWnd, CONGUI_UPDATE_TIMER, CURSOR_BLINK_TIME, NULL);
+
+ GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
+
+ Buff = Console->ActiveBuffer;
+ GuiInvalidateCell(Console, Buff->CurrentX, Buff->CurrentY);
+ GuiData->CursorBlinkOn = ! GuiData->CursorBlinkOn;
+
+ if((GuiData->OldCursor.x != Buff->CurrentX) || (GuiData->OldCursor.y != Buff->CurrentY))
+ {
+ SCROLLINFO xScroll;
+ int OldScrollX = -1, OldScrollY = -1;
+ int NewScrollX = -1, NewScrollY = -1;
+
+ xScroll.cbSize = sizeof(SCROLLINFO);
+ xScroll.fMask = SIF_POS;
+ // Capture the original position of the scroll bars and save them.
+ if(GetScrollInfo(hWnd, SB_HORZ, &xScroll))OldScrollX = xScroll.nPos;
+ if(GetScrollInfo(hWnd, SB_VERT, &xScroll))OldScrollY = xScroll.nPos;
+
+ // If we successfully got the info for the horizontal scrollbar
+ if(OldScrollX >= 0)
+ {
+ if((Buff->CurrentX < Buff->ShowX)||(Buff->CurrentX >= (Buff->ShowX + Console->Size.X)))
+ {
+ // Handle the horizontal scroll bar
+ if(Buff->CurrentX >= Console->Size.X) NewScrollX = Buff->CurrentX - Console->Size.X + 1;
+ else NewScrollX = 0;
+ }
+ else
+ {
+ NewScrollX = OldScrollX;
+ }
+ }
+ // If we successfully got the info for the vertical scrollbar
+ if(OldScrollY >= 0)
+ {
+ if((Buff->CurrentY < Buff->ShowY) || (Buff->CurrentY >= (Buff->ShowY + Console->Size.Y)))
+ {
+ // Handle the vertical scroll bar
+ if(Buff->CurrentY >= Console->Size.Y) NewScrollY = Buff->CurrentY - Console->Size.Y + 1;
+ else NewScrollY = 0;
+ }
+ else
+ {
+ NewScrollY = OldScrollY;
+ }
+ }
+
+ // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area
+ // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar
+ // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling)
+ // and their associated scrollbar is left alone.
+ if((OldScrollX != NewScrollX) || (OldScrollY != NewScrollY))
+ {
+ Buff->ShowX = NewScrollX;
+ Buff->ShowY = NewScrollY;
+ ScrollWindowEx(hWnd,
+ (OldScrollX - NewScrollX) * GuiData->CharWidth,
+ (OldScrollY - NewScrollY) * GuiData->CharHeight,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ SW_INVALIDATE);
+ if(NewScrollX >= 0)
+ {
+ xScroll.nPos = NewScrollX;
+ SetScrollInfo(hWnd, SB_HORZ, &xScroll, TRUE);
+ }
+ if(NewScrollY >= 0)
+ {
+ xScroll.nPos = NewScrollY;
+ SetScrollInfo(hWnd, SB_VERT, &xScroll, TRUE);
+ }
+ UpdateWindow(hWnd);
+ GuiData->OldCursor.x = Buff->CurrentX;
+ GuiData->OldCursor.y = Buff->CurrentY;
+ }
+ }
+}
+
+static VOID
+GuiConsoleHandleClose(HWND hWnd)
+{
+ PCSRSS_CONSOLE Console;
+ PGUI_CONSOLE_DATA GuiData;
+ PLIST_ENTRY current_entry;
+ PCSR_PROCESS current;
+
+ GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
+
+ EnterCriticalSection(&Console->Lock);
+
+ current_entry = Console->ProcessList.Flink;
+ while (current_entry != &Console->ProcessList)
+ {
+ current = CONTAINING_RECORD(current_entry, CSR_PROCESS, ConsoleLink);
+ current_entry = current_entry->Flink;
+
+ /* FIXME: Windows will wait up to 5 seconds for the thread to exit.
+ * We shouldn't wait here, though, since the console lock is entered.
+ * A copy of the thread list probably needs to be made. */
+ ConioConsoleCtrlEvent(CTRL_CLOSE_EVENT, current);
+ }
+
+ LeaveCriticalSection(&Console->Lock);
+}
+
+static VOID
+GuiConsoleHandleNcDestroy(HWND hWnd)
+{
+ PCSRSS_CONSOLE Console;
+ PGUI_CONSOLE_DATA GuiData;
+
+
+ GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
+ KillTimer(hWnd, 1);
+ Console->PrivateData = NULL;
+ DeleteCriticalSection(&GuiData->Lock);
+ GetSystemMenu(hWnd, TRUE);
+ if (GuiData->ConsoleLibrary)
+ FreeLibrary(GuiData->ConsoleLibrary);
+
+ HeapFree(Win32CsrApiHeap, 0, GuiData);
+}
+
+static COORD
+PointToCoord(PCSRSS_CONSOLE Console, LPARAM lParam)
+{
+ PCSRSS_SCREEN_BUFFER Buffer = Console->ActiveBuffer;
+ PGUI_CONSOLE_DATA GuiData = Console->PrivateData;
+ COORD Coord;
+ Coord.X = Buffer->ShowX + ((short)LOWORD(lParam) / (int)GuiData->CharWidth);
+ Coord.Y = Buffer->ShowY + ((short)HIWORD(lParam) / (int)GuiData->CharHeight);
+
+ /* Clip coordinate to ensure it's inside buffer */
+ if (Coord.X < 0) Coord.X = 0;
+ else if (Coord.X >= Buffer->MaxX) Coord.X = Buffer->MaxX - 1;
+ if (Coord.Y < 0) Coord.Y = 0;
+ else if (Coord.Y >= Buffer->MaxY) Coord.Y = Buffer->MaxY - 1;
+ return Coord;
+}
+
+static VOID
+GuiConsoleLeftMouseDown(HWND hWnd, LPARAM lParam)
+{
+ PCSRSS_CONSOLE Console;
+ PGUI_CONSOLE_DATA GuiData;
+
+ GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
+ if (Console == NULL || GuiData == NULL) return;
+
+ Console->Selection.dwSelectionAnchor = PointToCoord(Console, lParam);
+
+ SetCapture(hWnd);
+
+ Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS | CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
+
+ GuiConsoleUpdateSelection(Console, &Console->Selection.dwSelectionAnchor);
+}
+
+static VOID
+GuiConsoleLeftMouseUp(HWND hWnd, LPARAM lParam)
+{
+ PCSRSS_CONSOLE Console;
+ PGUI_CONSOLE_DATA GuiData;
+ COORD c;
+
+ GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
+ if (Console == NULL || GuiData == NULL) return;
+ if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) return;
+
+ c = PointToCoord(Console, lParam);
+
+ Console->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN;
+
+ GuiConsoleUpdateSelection(Console, &c);
+
+ ReleaseCapture();
+}
+
+static VOID
+GuiConsoleMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+ PCSRSS_CONSOLE Console;
+ PGUI_CONSOLE_DATA GuiData;
+ COORD c;
+
+ if (!(wParam & MK_LBUTTON)) return;
+
+ GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
+ if (Console == NULL || GuiData == NULL) return;
+ if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) return;
+
+ c = PointToCoord(Console, lParam); /* TODO: Scroll buffer to bring c into view */
+
+ GuiConsoleUpdateSelection(Console, &c);
+}
+
+static VOID
+GuiConsoleCopy(HWND hWnd, PCSRSS_CONSOLE Console)
+{
+ if (OpenClipboard(hWnd) == TRUE)
+ {
+ HANDLE hData;
+ PBYTE ptr;
+ LPSTR data, dstPos;
+ ULONG selWidth, selHeight;
+ ULONG xPos, yPos, size;
+
+ selWidth = Console->Selection.srSelection.Right - Console->Selection.srSelection.Left + 1;
+ selHeight = Console->Selection.srSelection.Bottom - Console->Selection.srSelection.Top + 1;
+ DPRINT("Selection is (%d|%d) to (%d|%d)\n",
+ Console->Selection.srSelection.Left,
+ Console->Selection.srSelection.Top,
+ Console->Selection.srSelection.Right,
+ Console->Selection.srSelection.Bottom);
+
+ /* Basic size for one line and termination */
+ size = selWidth + 1;
+ if (selHeight > 0)
+ {
+ /* Multiple line selections have to get \r\n appended */
+ size += ((selWidth + 2) * (selHeight - 1));
+ }
+
+ /* Allocate memory, it will be passed to the system and may not be freed here */
+ hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size);
+ if (hData == NULL)
+ {
+ CloseClipboard();
+ return;
+ }
+ data = GlobalLock(hData);
+ if (data == NULL)
+ {
+ CloseClipboard();
+ return;
+ }
+
+ DPRINT("Copying %dx%d selection\n", selWidth, selHeight);
+ dstPos = data;
+
+ for (yPos = 0; yPos < selHeight; yPos++)
+ {
+ ptr = ConioCoordToPointer(Console->ActiveBuffer,
+ Console->Selection.srSelection.Left,
+ yPos + Console->Selection.srSelection.Top);
+ /* Copy only the characters, leave attributes alone */
+ for (xPos = 0; xPos < selWidth; xPos++)
+ {
+ dstPos[xPos] = ptr[xPos * 2];
+ }
+ dstPos += selWidth;
+ if (yPos != (selHeight - 1))
+ {
+ strcat(data, "\r\n");
+ dstPos += 2;
+ }
+ }
+
+ DPRINT("Setting data <%s> to clipboard\n", data);
+ GlobalUnlock(hData);
+
+ EmptyClipboard();
+ SetClipboardData(CF_TEXT, hData);
+ CloseClipboard();
+ }
+}
+
+static VOID
+GuiConsolePaste(HWND hWnd, PCSRSS_CONSOLE Console)
+{
+ if (OpenClipboard(hWnd) == TRUE)
+ {
+ HANDLE hData;
+ LPSTR str;
+ size_t len;
+
+ hData = GetClipboardData(CF_TEXT);
+ if (hData == NULL)
+ {
+ CloseClipboard();
+ return;
+ }
+
+ str = GlobalLock(hData);
+ if (str == NULL)
+ {
+ CloseClipboard();
+ return;
+ }
+ DPRINT("Got data <%s> from clipboard\n", str);
+ len = strlen(str);
+
+ ConioWriteConsole(Console, Console->ActiveBuffer, str, len, TRUE);
+
+ GlobalUnlock(hData);
+ CloseClipboard();
+ }
+}
+
+static VOID
+GuiConsoleRightMouseDown(HWND hWnd)
+{
+ PCSRSS_CONSOLE Console;
+ PGUI_CONSOLE_DATA GuiData;
+
+ GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
+ if (Console == NULL || GuiData == NULL) return;
+
+ if (!(Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY))
+ {
+ GuiConsolePaste(hWnd, Console);
+ }
+ else
+ {
+ GuiConsoleCopy(hWnd, Console);
+
+ /* Clear the selection */
+ GuiConsoleUpdateSelection(Console, NULL);
+ }
+
+}
+
+
+static VOID
+GuiConsoleShowConsoleProperties(HWND hWnd, BOOL Defaults, PGUI_CONSOLE_DATA GuiData)
+{
+ PCSRSS_CONSOLE Console;
+ APPLET_PROC CPLFunc;
+ TCHAR szBuffer[MAX_PATH];
+ ConsoleInfo SharedInfo;
+
+ DPRINT("GuiConsoleShowConsoleProperties entered\n");
+
+ GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
+
+ if (GuiData == NULL)
+ {
+ DPRINT("GuiConsoleGetDataPointers failed\n");
+ return;
+ }
+
+ if (GuiData->ConsoleLibrary == NULL)
+ {
+ GetWindowsDirectory(szBuffer,MAX_PATH);
+ _tcscat(szBuffer, _T("\\system32\\console.dll"));
+ GuiData->ConsoleLibrary = LoadLibrary(szBuffer);
+
+ if (GuiData->ConsoleLibrary == NULL)
+ {
+ DPRINT1("failed to load console.dll");
+ return;
+ }
+ }
+
+ CPLFunc = (APPLET_PROC) GetProcAddress(GuiData->ConsoleLibrary, _T("CPlApplet"));
+ if (!CPLFunc)
+ {
+ DPRINT("Error: Console.dll misses CPlApplet export\n");
+ return;
+ }
+
+ /* setup struct */
+ SharedInfo.InsertMode = GuiData->InsertMode;
+ SharedInfo.HistoryBufferSize = Console->HistoryBufferSize;
+ SharedInfo.NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers;
+ SharedInfo.ScreenText = GuiData->ScreenText;
+ SharedInfo.ScreenBackground = GuiData->ScreenBackground;
+ SharedInfo.PopupText = GuiData->PopupText;
+ SharedInfo.PopupBackground = GuiData->PopupBackground;
+ SharedInfo.WindowSize = (DWORD)MAKELONG(Console->Size.X, Console->Size.Y);
+ SharedInfo.WindowPosition = GuiData->WindowPosition;
+ SharedInfo.ScreenBuffer = (DWORD)MAKELONG(Console->ActiveBuffer->MaxX, Console->ActiveBuffer->MaxY);
+ SharedInfo.UseRasterFonts = GuiData->UseRasterFonts;
+ SharedInfo.FontSize = (DWORD)GuiData->FontSize;
+ SharedInfo.FontWeight = GuiData->FontWeight;
+ SharedInfo.CursorSize = Console->ActiveBuffer->CursorInfo.dwSize;
+ SharedInfo.HistoryNoDup = Console->HistoryNoDup;
+ SharedInfo.FullScreen = GuiData->FullScreen;
+ SharedInfo.QuickEdit = GuiData->QuickEdit;
+ memcpy(&SharedInfo.Colors[0], GuiData->Colors, sizeof(s_Colors));
+
+ if (!CPLFunc(hWnd, CPL_INIT, 0, 0))
+ {
+ DPRINT("Error: failed to initialize console.dll\n");
+ return;
+ }
+
+ if (CPLFunc(hWnd, CPL_GETCOUNT, 0, 0) != 1)
+ {
+ DPRINT("Error: console.dll returned unexpected CPL count\n");
+ return;
+ }
+
+ CPLFunc(hWnd, CPL_DBLCLK, (LPARAM)&SharedInfo, Defaults);
+}
+static LRESULT
+GuiConsoleHandleSysMenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT Ret = TRUE;
+ PCSRSS_CONSOLE Console;
+ PGUI_CONSOLE_DATA GuiData;
+ COORD bottomRight = { 0, 0 };
+
+ GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
+
+ switch(wParam)
+ {
+ case ID_SYSTEM_EDIT_MARK:
+ DPRINT1("Marking not handled yet\n");
+ break;
+
+ case ID_SYSTEM_EDIT_COPY:
+ GuiConsoleCopy(hWnd, Console);
+ break;
+
+ case ID_SYSTEM_EDIT_PASTE:
+ GuiConsolePaste(hWnd, Console);
+ break;
+
+ case ID_SYSTEM_EDIT_SELECTALL:
+ bottomRight.X = Console->Size.X - 1;
+ bottomRight.Y = Console->Size.Y - 1;
+ GuiConsoleUpdateSelection(Console, &bottomRight);
+ break;
+
+ case ID_SYSTEM_EDIT_SCROLL:
+ DPRINT1("Scrolling is not handled yet\n");
+ break;
+
+ case ID_SYSTEM_EDIT_FIND:
+ DPRINT1("Finding is not handled yet\n");
+ break;
+
+ case ID_SYSTEM_DEFAULTS:
+ GuiConsoleShowConsoleProperties(hWnd, TRUE, GuiData);
+ break;
+
+ case ID_SYSTEM_PROPERTIES:
+ GuiConsoleShowConsoleProperties(hWnd, FALSE, GuiData);
+ break;
+
+ default:
+ Ret = DefWindowProcW(hWnd, WM_SYSCOMMAND, wParam, lParam);
+ break;
+ }
+ return Ret;
+}
+
+static VOID
+GuiConsoleGetMinMaxInfo(HWND hWnd, PMINMAXINFO minMaxInfo)
+{
+ PCSRSS_CONSOLE Console;
+ PGUI_CONSOLE_DATA GuiData;
+ DWORD windx, windy;
+
+ GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
+ if((Console == NULL)|| (GuiData == NULL)) return;
+
+ windx = CONGUI_MIN_WIDTH * GuiData->CharWidth + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
+ windy = CONGUI_MIN_HEIGHT * GuiData->CharHeight + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
+
+ minMaxInfo->ptMinTrackSize.x = windx;
+ minMaxInfo->ptMinTrackSize.y = windy;
+
+ windx = (Console->ActiveBuffer->MaxX) * GuiData->CharWidth + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
+ windy = (Console->ActiveBuffer->MaxY) * GuiData->CharHeight + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
+
+ if(Console->Size.X < Console->ActiveBuffer->MaxX) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
+ if(Console->Size.Y < Console->ActiveBuffer->MaxY) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
+
+ minMaxInfo->ptMaxTrackSize.x = windx;
+ minMaxInfo->ptMaxTrackSize.y = windy;
+}
+static VOID
+GuiConsoleResize(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+ PCSRSS_CONSOLE Console;
+ PGUI_CONSOLE_DATA GuiData;
+ GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
+ if((Console == NULL) || (GuiData == NULL)) return;
+
+ if ((GuiData->WindowSizeLock == FALSE) && (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED))
+ {
+ PCSRSS_SCREEN_BUFFER Buff = Console->ActiveBuffer;
+ DWORD windx, windy, charx, chary;
+
+ GuiData->WindowSizeLock = TRUE;
+
+ windx = LOWORD(lParam);
+ windy = HIWORD(lParam);
+
+ // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
+ if(Console->Size.X < Buff->MaxX) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
+ if(Console->Size.Y < Buff->MaxY) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
+
+ charx = windx / GuiData->CharWidth;
+ chary = windy / GuiData->CharHeight;
+
+ // Character alignment (round size up or down)
+ if((windx % GuiData->CharWidth) >= (GuiData->CharWidth / 2)) ++charx;
+ if((windy % GuiData->CharHeight) >= (GuiData->CharHeight / 2)) ++chary;
+
+ // Compensate for added scroll bars in new window
+ if(charx < Buff->MaxX)windy -= GetSystemMetrics(SM_CYHSCROLL); // new window will have a horizontal scroll bar
+ if(chary < Buff->MaxY)windx -= GetSystemMetrics(SM_CXVSCROLL); // new window will have a vertical scroll bar
+
+ charx = windx / GuiData->CharWidth;
+ chary = windy / GuiData->CharHeight;
+
+ // Character alignment (round size up or down)
+ if((windx % GuiData->CharWidth) >= (GuiData->CharWidth / 2)) ++charx;
+ if((windy % GuiData->CharHeight) >= (GuiData->CharHeight / 2)) ++chary;
+
+ // Resize window
+ if((charx != Console->Size.X) || (chary != Console->Size.Y))
+ {
+ Console->Size.X = (charx <= Buff->MaxX) ? charx : Buff->MaxX;
+ Console->Size.Y = (chary <= Buff->MaxY) ? chary : Buff->MaxY;
+ }
+
+ GuiConsoleInitScrollbar(Console, hWnd);
+
+ // Adjust the start of the visible area if we are attempting to show nonexistent areas
+ if((Buff->MaxX - Buff->ShowX) < Console->Size.X) Buff->ShowX = Buff->MaxX - Console->Size.X;
+ if((Buff->MaxY - Buff->ShowY) < Console->Size.Y) Buff->ShowY = Buff->MaxY - Console->Size.Y;
+ InvalidateRect(hWnd, NULL, TRUE);
+
+ GuiData->WindowSizeLock = FALSE;
+ }
+}
+
+VOID
+FASTCALL
+GuiConsoleHandleScrollbarMenu(VOID)
+{
+ HMENU hMenu;
+
+ hMenu = CreatePopupMenu();
+ if (hMenu == NULL)
+ {
+ DPRINT("CreatePopupMenu failed\n");
+ return;
+ }
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
+ //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
+ //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
+ //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
+ //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
+
+}
+
+static NTSTATUS WINAPI
+GuiResizeBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER ScreenBuffer, COORD Size)
+{
+ BYTE * Buffer;
+ DWORD Offset = 0;
+ BYTE * OldPtr;
+ USHORT CurrentY;
+ BYTE * OldBuffer;
+#if HAVE_WMEMSET
+ USHORT value = MAKEWORD(' ', ScreenBuffer->DefaultAttrib);
+#endif
+ DWORD diff;
+ DWORD i;
+
+ /* Buffer size is not allowed to be smaller than window size */
+ if (Size.X < Console->Size.X || Size.Y < Console->Size.Y)
+ return STATUS_INVALID_PARAMETER;
+
+ if (Size.X == ScreenBuffer->MaxX && Size.Y == ScreenBuffer->MaxY)
+ return STATUS_SUCCESS;
+
+ Buffer = HeapAlloc(Win32CsrApiHeap, 0, Size.X * Size.Y * 2);
+ if (!Buffer)
+ return STATUS_NO_MEMORY;
+
+ DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->MaxX, ScreenBuffer->MaxY, Size.X, Size.Y);
+ OldBuffer = ScreenBuffer->Buffer;
+
+ for (CurrentY = 0; CurrentY < ScreenBuffer->MaxY && CurrentY < Size.Y; CurrentY++)
+ {
+ OldPtr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY);
+ if (Size.X <= ScreenBuffer->MaxX)
+ {
+ /* reduce size */
+ RtlCopyMemory(&Buffer[Offset], OldPtr, Size.X * 2);
+ Offset += (Size.X * 2);
+ }
+ else
+ {
+ /* enlarge size */
+ RtlCopyMemory(&Buffer[Offset], OldPtr, ScreenBuffer->MaxX * 2);
+ Offset += (ScreenBuffer->MaxX * 2);
+
+ diff = Size.X - ScreenBuffer->MaxX;
+ /* zero new part of it */
+#if HAVE_WMEMSET
+ wmemset((WCHAR*)&Buffer[Offset], value, diff);
+#else
+ for (i = 0; i < diff; i++)
+ {
+ Buffer[Offset++] = ' ';
+ Buffer[Offset++] = ScreenBuffer->DefaultAttrib;
+ }
+#endif
+ }
+ }
+
+ if (Size.Y > ScreenBuffer->MaxY)
+ {
+ diff = Size.X * (Size.Y - ScreenBuffer->MaxY);
+#if HAVE_WMEMSET
+ wmemset((WCHAR*)&Buffer[Offset], value, diff);
+#else
+ for (i = 0; i < diff; i++)
+ {
+ Buffer[Offset++] = ' ';
+ Buffer[Offset++] = ScreenBuffer->DefaultAttrib;
+ }
+#endif
+ }
+
+ (void)InterlockedExchangePointer((PVOID volatile *)&ScreenBuffer->Buffer, Buffer);
+ HeapFree(Win32CsrApiHeap, 0, OldBuffer);
+ ScreenBuffer->MaxX = Size.X;
+ ScreenBuffer->MaxY = Size.Y;
+ ScreenBuffer->VirtualY = 0;
+
+ /* Ensure cursor and window are within buffer */
+ if (ScreenBuffer->CurrentX >= Size.X)
+ ScreenBuffer->CurrentX = Size.X - 1;
+ if (ScreenBuffer->CurrentY >= Size.Y)
+ ScreenBuffer->CurrentY = Size.Y - 1;
+ if (ScreenBuffer->ShowX > Size.X - Console->Size.X)
+ ScreenBuffer->ShowX = Size.X - Console->Size.X;
+ if (ScreenBuffer->ShowY > Size.Y - Console->Size.Y)
+ ScreenBuffer->ShowY = Size.Y - Console->Size.Y;
+
+ /* TODO: Should update scrollbar, but can't use anything that
+ * calls SendMessage or it could cause deadlock */
+
+ return STATUS_SUCCESS;
+}
+
+static VOID
+GuiApplyUserSettings(PCSRSS_CONSOLE Console, PGUI_CONSOLE_DATA GuiData, PConsoleInfo pConInfo)
+{
+ DWORD windx, windy;
+ PCSRSS_SCREEN_BUFFER ActiveBuffer = Console->ActiveBuffer;
+ COORD BufSize;
+ BOOL SizeChanged = FALSE;
+
+ EnterCriticalSection(&Console->Lock);
+
+ /* apply text / background color */
+ GuiData->ScreenText = pConInfo->ScreenText;
+ GuiData->ScreenBackground = pConInfo->ScreenBackground;
+
+ /* apply cursor size */
+ ActiveBuffer->CursorInfo.dwSize = min(max(pConInfo->CursorSize, 1), 100);
+
+ windx = LOWORD(pConInfo->WindowSize);
+ windy = HIWORD(pConInfo->WindowSize);
+
+ if (windx != Console->Size.X || windy != Console->Size.Y)
+ {
+ /* resize window */
+ Console->Size.X = windx;
+ Console->Size.Y = windy;
+ SizeChanged = TRUE;
+ }
+
+ BufSize.X = LOWORD(pConInfo->ScreenBuffer);
+ BufSize.Y = HIWORD(pConInfo->ScreenBuffer);
+ if (BufSize.X != ActiveBuffer->MaxX || BufSize.Y != ActiveBuffer->MaxY)
+ {
+ if (NT_SUCCESS(GuiResizeBuffer(Console, ActiveBuffer, BufSize)))
+ SizeChanged = TRUE;
+ }
+
+ if (SizeChanged)
+ {
+ GuiData->WindowSizeLock = TRUE;
+ GuiConsoleInitScrollbar(Console, pConInfo->hConsoleWindow);
+ GuiData->WindowSizeLock = FALSE;
+ }
+
+ LeaveCriticalSection(&Console->Lock);
+ InvalidateRect(pConInfo->hConsoleWindow, NULL, TRUE);
+}
+
+static
+LRESULT
+GuiConsoleHandleScroll(HWND hwnd, UINT uMsg, WPARAM wParam)
+{
+ PCSRSS_CONSOLE Console;
+ PCSRSS_SCREEN_BUFFER Buff;
+ PGUI_CONSOLE_DATA GuiData;
+ SCROLLINFO sInfo;
+ int fnBar;
+ int old_pos, Maximum;
+ PUSHORT pShowXY;
+
+ GuiConsoleGetDataPointers(hwnd, &Console, &GuiData);
+ if (Console == NULL || GuiData == NULL)
+ return FALSE;
+ Buff = Console->ActiveBuffer;
+
+ if (uMsg == WM_HSCROLL)
+ {
+ fnBar = SB_HORZ;
+ Maximum = Buff->MaxX - Console->Size.X;
+ pShowXY = &Buff->ShowX;
+ }
+ else
+ {
+ fnBar = SB_VERT;
+ Maximum = Buff->MaxY - Console->Size.Y;
+ pShowXY = &Buff->ShowY;
+ }
+
+ /* set scrollbar sizes */
+ sInfo.cbSize = sizeof(SCROLLINFO);
+ sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
+
+ if (!GetScrollInfo(hwnd, fnBar, &sInfo))
+ {
+ return FALSE;
+ }
+
+ old_pos = sInfo.nPos;
+
+ switch(LOWORD(wParam))
+ {
+ case SB_LINELEFT:
+ sInfo.nPos -= 1;
+ break;
+
+ case SB_LINERIGHT:
+ sInfo.nPos += 1;
+ break;
+
+ case SB_PAGELEFT:
+ sInfo.nPos -= sInfo.nPage;
+ break;
+
+ case SB_PAGERIGHT:
+ sInfo.nPos += sInfo.nPage;
+ break;
+
+ case SB_THUMBTRACK:
+ sInfo.nPos = sInfo.nTrackPos;
+ ConioPause(Console, PAUSED_FROM_SCROLLBAR);
+ break;
+
+ case SB_THUMBPOSITION:
+ ConioUnpause(Console, PAUSED_FROM_SCROLLBAR);
+ break;
+
+ case SB_TOP:
+ sInfo.nPos = sInfo.nMin;
+ break;
+
+ case SB_BOTTOM:
+ sInfo.nPos = sInfo.nMax;
+ break;
+
+ default:
+ break;
+ }
+
+ sInfo.nPos = max(sInfo.nPos, 0);
+ sInfo.nPos = min(sInfo.nPos, Maximum);
+
+ if (old_pos != sInfo.nPos)
+ {
+ USHORT OldX = Buff->ShowX;
+ USHORT OldY = Buff->ShowY;
+ *pShowXY = sInfo.nPos;
+
+ ScrollWindowEx(hwnd,
+ (OldX - Buff->ShowX) * GuiData->CharWidth,
+ (OldY - Buff->ShowY) * GuiData->CharHeight,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ SW_INVALIDATE);
+
+ sInfo.fMask = SIF_POS;
+ SetScrollInfo(hwnd, fnBar, &sInfo, TRUE);
+
+ UpdateWindow(hwnd);
+ }
+ return 0;
+}
+
+static LRESULT CALLBACK
+GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT Result = 0;
+ PGUI_CONSOLE_DATA GuiData = NULL;
+ PCSRSS_CONSOLE Console = NULL;
+
+ GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
+
+ switch(msg)
+ {
+ case WM_NCCREATE:
+ Result = (LRESULT) GuiConsoleHandleNcCreate(hWnd, (CREATESTRUCTW *) lParam);
+ break;
+ case WM_PAINT:
+ GuiConsoleHandlePaint(hWnd, (HDC)wParam);
+ break;
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ case WM_CHAR:
+ GuiConsoleHandleKey(hWnd, msg, wParam, lParam);
+ break;
+ case WM_TIMER:
+ GuiConsoleHandleTimer(hWnd);
+ break;
+ case WM_CLOSE:
+ GuiConsoleHandleClose(hWnd);
+ break;
+ case WM_NCDESTROY:
+ GuiConsoleHandleNcDestroy(hWnd);
+ break;
+ case WM_LBUTTONDOWN:
+ GuiConsoleLeftMouseDown(hWnd, lParam);
+ break;
+ case WM_LBUTTONUP:
+ GuiConsoleLeftMouseUp(hWnd, lParam);
+ break;
+ case WM_RBUTTONDOWN:
+ GuiConsoleRightMouseDown(hWnd);
+ break;
+ case WM_MOUSEMOVE:
+ GuiConsoleMouseMove(hWnd, wParam, lParam);
+ break;
+ case WM_SYSCOMMAND:
+ Result = GuiConsoleHandleSysMenuCommand(hWnd, wParam, lParam);
+ break;
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ Result = GuiConsoleHandleScroll(hWnd, msg, wParam);
+ break;
+ case WM_GETMINMAXINFO:
+ GuiConsoleGetMinMaxInfo(hWnd, (PMINMAXINFO)lParam);
+ break;
+ case WM_SIZE:
+ GuiConsoleResize(hWnd, wParam, lParam);
+ break;
+ case PM_APPLY_CONSOLE_INFO:
+ GuiApplyUserSettings(Console, GuiData, (PConsoleInfo)wParam);
+ if (lParam)
+ {
+ GuiConsoleWriteUserSettings(Console, GuiData);
+ }
+ break;
+ default:
+ Result = DefWindowProcW(hWnd, msg, wParam, lParam);
+ break;
+ }
+
+ return Result;
+}
+
+static LRESULT CALLBACK
+GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND NewWindow;
+ LONG WindowCount;
+ MSG Msg;
+ PWCHAR Buffer, Title;
+ PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) lParam;
+
+
+
+ switch(msg)
+ {
+ case WM_CREATE:
+ SetWindowLongW(hWnd, GWL_USERDATA, 0);
+ return 0;
+ case PM_CREATE_CONSOLE:
+ Buffer = HeapAlloc(Win32CsrApiHeap, 0,
+ Console->Title.Length + sizeof(WCHAR));
+ if (NULL != Buffer)
+ {
+ memcpy(Buffer, Console->Title.Buffer, Console->Title.Length);
+ Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
+ Title = Buffer;
+ }
+ else
+ {
+ Title = L"";
+ }
+ NewWindow = CreateWindowExW(WS_EX_CLIENTEDGE,
+ L"ConsoleWindowClass",
+ Title,
+ WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ (HINSTANCE) GetModuleHandleW(NULL),
+ (PVOID) Console);
+ if (NULL != Buffer)
+ {
+ HeapFree(Win32CsrApiHeap, 0, Buffer);
+ }
+ if (NULL != NewWindow)
+ {
+ SetWindowLongW(hWnd, GWL_USERDATA, GetWindowLongW(hWnd, GWL_USERDATA) + 1);
+ ShowWindow(NewWindow, (int)wParam);
+ }
+ return (LRESULT) NewWindow;
+ case PM_DESTROY_CONSOLE:
+ /* Window creation is done using a PostMessage(), so it's possible that the
+ * window that we want to destroy doesn't exist yet. So first empty the message
+ * queue */
+ while(PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&Msg);
+ DispatchMessageW(&Msg);
+ }
+ DestroyWindow(Console->hWindow);
+ Console->hWindow = NULL;
+ WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
+ WindowCount--;
+ SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
+ if (0 == WindowCount)
+ {
+ NotifyWnd = NULL;
+ DestroyWindow(hWnd);
+ PrivateCsrssManualGuiCheck(-1);
+ PostQuitMessage(0);
+ }
+ return 0;
+ default:
+ return DefWindowProcW(hWnd, msg, wParam, lParam);
+ }
+}
+
+static DWORD WINAPI
+GuiConsoleGuiThread(PVOID Data)
+{
+ MSG msg;
+ PHANDLE GraphicsStartupEvent = (PHANDLE) Data;
+
+ NotifyWnd = CreateWindowW(L"Win32CsrCreateNotify",
+ L"",
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ (HINSTANCE) GetModuleHandleW(NULL),
+ NULL);
+ if (NULL == NotifyWnd)
+ {
+ PrivateCsrssManualGuiCheck(-1);
+ SetEvent(*GraphicsStartupEvent);
+ return 1;
+ }
+
+ SetEvent(*GraphicsStartupEvent);
+
+ while(GetMessageW(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+
+ return 1;
+}
+
+static BOOL
+GuiInit(VOID)
+{
+ WNDCLASSEXW wc;
+
+ if (NULL == NotifyWnd)
+ {
+ PrivateCsrssManualGuiCheck(+1);
+ }
+
+ wc.cbSize = sizeof(WNDCLASSEXW);
+ wc.lpszClassName = L"Win32CsrCreateNotify";
+ wc.lpfnWndProc = GuiConsoleNotifyWndProc;
+ wc.style = 0;
+ wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hIconSm = NULL;
+ if (RegisterClassExW(&wc) == 0)
+ {
+ DPRINT1("Failed to register notify wndproc\n");
+ return FALSE;
+ }
+
+ wc.cbSize = sizeof(WNDCLASSEXW);
+ wc.lpszClassName = L"ConsoleWindowClass";
+ wc.lpfnWndProc = GuiConsoleWndProc;
+ wc.style = 0;
+ wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
+ wc.hIcon = LoadIconW(GetModuleHandleW(L"win32csr"), MAKEINTRESOURCEW(1));
+ wc.hCursor = LoadCursorW(NULL, (LPCWSTR) IDC_ARROW);
+ wc.hbrBackground = CreateSolidBrush(RGB(0,0,0));
+ wc.lpszMenuName = NULL;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hIconSm = LoadImageW(GetModuleHandleW(L"win32csr"), MAKEINTRESOURCEW(1), IMAGE_ICON,
+ GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
+ LR_SHARED);
+ if (RegisterClassExW(&wc) == 0)
+ {
+ DPRINT1("Failed to register console wndproc\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static VOID WINAPI
+GuiInitScreenBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buffer)
+{
+ Buffer->DefaultAttrib = DEFAULT_ATTRIB;
+}
+
+static BOOL WINAPI
+GuiChangeTitle(PCSRSS_CONSOLE Console)
+{
+ PWCHAR Buffer, Title;
+
+ Buffer = HeapAlloc(Win32CsrApiHeap, 0,
+ Console->Title.Length + sizeof(WCHAR));
+ if (NULL != Buffer)
+ {
+ memcpy(Buffer, Console->Title.Buffer, Console->Title.Length);
+ Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
+ Title = Buffer;
+ }
+ else
+ {
+ Title = L"";
+ }
+
+ SendMessageW(Console->hWindow, WM_SETTEXT, 0, (LPARAM) Title);
+
+ if (NULL != Buffer)
+ {
+ HeapFree(Win32CsrApiHeap, 0, Buffer);
+ }
+
+ return TRUE;
+}
+
+static BOOL WINAPI
+GuiChangeIcon(PCSRSS_CONSOLE Console, HICON hWindowIcon)
+{
+ SendMessageW(Console->hWindow, WM_SETICON, ICON_BIG, (LPARAM)hWindowIcon);
+ SendMessageW(Console->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)hWindowIcon);
+
+ return TRUE;
+}
+
+static VOID WINAPI
+GuiCleanupConsole(PCSRSS_CONSOLE Console)
+{
+ SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM) Console);
+}
+
+static CSRSS_CONSOLE_VTBL GuiVtbl =
+{
+ GuiInitScreenBuffer,
+ GuiWriteStream,
+ GuiDrawRegion,
+ GuiSetCursorInfo,
+ GuiSetScreenInfo,
+ GuiUpdateScreenInfo,
+ GuiChangeTitle,
+ GuiCleanupConsole,
+ GuiChangeIcon,
+ GuiResizeBuffer,
+};
+
+NTSTATUS FASTCALL
+GuiInitConsole(PCSRSS_CONSOLE Console, int ShowCmd)
+{
+ HANDLE GraphicsStartupEvent;
+ HANDLE ThreadHandle;
+ PGUI_CONSOLE_DATA GuiData;
+
+ if (! ConsInitialized)
+ {
+ ConsInitialized = TRUE;
+ if (! GuiInit())
+ {
+ ConsInitialized = FALSE;
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ Console->Vtbl = &GuiVtbl;
+ if (NULL == NotifyWnd)
+ {
+ GraphicsStartupEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+ if (NULL == GraphicsStartupEvent)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ ThreadHandle = CreateThread(NULL,
+ 0,
+ GuiConsoleGuiThread,
+ (PVOID) &GraphicsStartupEvent,
+ 0,
+ NULL);
+ if (NULL == ThreadHandle)
+ {
+ CloseHandle(GraphicsStartupEvent);
+ DPRINT1("Win32Csr: Failed to create graphics console thread. Expect problems\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+ SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
+ CloseHandle(ThreadHandle);
+
+ WaitForSingleObject(GraphicsStartupEvent, INFINITE);
+ CloseHandle(GraphicsStartupEvent);
+
+ if (NULL == NotifyWnd)
+ {
+ DPRINT1("Win32Csr: Failed to create notification window.\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+ GuiData = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY,
+ sizeof(GUI_CONSOLE_DATA));
+ if (!GuiData)
+ {
+ DPRINT1("Win32Csr: Failed to create GUI_CONSOLE_DATA\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ Console->PrivateData = (PVOID) GuiData;
+ /*
+ * we need to wait untill the GUI has been fully initialized
+ * to retrieve custom settings i.e. WindowSize etc..
+ * Ideally we could use SendNotifyMessage for this but its not
+ * yet implemented.
+ *
+ */
+ GuiData->hGuiInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+ /* create console */
+ PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, ShowCmd, (LPARAM) Console);
+
+ /* wait untill initialization has finished */
+ WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE);
+ DPRINT("received event Console %p GuiData %p X %d Y %d\n", Console, Console->PrivateData, Console->Size.X, Console->Size.Y);
+ CloseHandle(GuiData->hGuiInitEvent);
+ GuiData->hGuiInitEvent = NULL;
+
+ return STATUS_SUCCESS;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: subsys/csrss/win32csr/guiconsole.h
+ * PURPOSE: Interface to GUI consoles
+ */
+
+#include "api.h"
+
+#define CONGUI_MIN_WIDTH 10
+#define CONGUI_MIN_HEIGHT 10
+#define CONGUI_UPDATE_TIME 0
+#define CONGUI_UPDATE_TIMER 1
+
+NTSTATUS FASTCALL GuiInitConsole(PCSRSS_CONSOLE Console, BOOL Visible);
+VOID FASTCALL GuiConsoleHandleScrollbarMenu(VOID);
+
+/*EOF*/
--- /dev/null
+/*
+ * reactos/subsys/csrss/api/handle.c
+ *
+ * CSRSS handle functions
+ *
+ * ReactOS Operating System
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <w32csr.h>
+
+#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+static
+BOOL
+CsrIsConsoleHandle(HANDLE Handle)
+{
+ return ((ULONG_PTR)Handle & 0x10000003) == 0x3;
+}
+
+static INT
+AdjustHandleCounts(PCSRSS_HANDLE Entry, INT Change)
+{
+ Object_t *Object = Entry->Object;
+ if (Entry->Access & GENERIC_READ) Object->AccessRead += Change;
+ if (Entry->Access & GENERIC_WRITE) Object->AccessWrite += Change;
+ if (!(Entry->ShareMode & FILE_SHARE_READ)) Object->ExclusiveRead += Change;
+ if (!(Entry->ShareMode & FILE_SHARE_WRITE)) Object->ExclusiveWrite += Change;
+ Object->HandleCount += Change;
+ return Object->HandleCount;
+}
+
+static VOID
+Win32CsrCreateHandleEntry(
+ PCSRSS_HANDLE Entry)
+{
+ Object_t *Object = Entry->Object;
+ EnterCriticalSection(&Object->Console->Lock);
+ AdjustHandleCounts(Entry, +1);
+ LeaveCriticalSection(&Object->Console->Lock);
+}
+
+static VOID
+Win32CsrCloseHandleEntry(
+ PCSRSS_HANDLE Entry)
+{
+ Object_t *Object = Entry->Object;
+ if (Object != NULL)
+ {
+ PCSRSS_CONSOLE Console = Object->Console;
+ EnterCriticalSection(&Console->Lock);
+ /* If the last handle to a screen buffer is closed, delete it */
+ if (AdjustHandleCounts(Entry, -1) == 0
+ && Object->Type == CONIO_SCREEN_BUFFER_MAGIC)
+ {
+ PCSRSS_SCREEN_BUFFER Buffer = (PCSRSS_SCREEN_BUFFER)Object;
+ /* ...unless it's the only buffer left. Windows allows deletion
+ * even of the last buffer, but having to deal with a lack of
+ * any active buffer might be error-prone. */
+ if (Buffer->ListEntry.Flink != Buffer->ListEntry.Blink)
+ ConioDeleteScreenBuffer(Buffer);
+ }
+ LeaveCriticalSection(&Console->Lock);
+ Entry->Object = NULL;
+ }
+}
+
+NTSTATUS
+FASTCALL
+Win32CsrReleaseObject(
+ PCSR_PROCESS ProcessData,
+ HANDLE Handle)
+{
+ ULONG_PTR h = (ULONG_PTR)Handle >> 2;
+ Object_t *Object;
+
+ RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+ if (h >= ProcessData->HandleTableSize
+ || (Object = ProcessData->HandleTable[h].Object) == NULL)
+ {
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return STATUS_INVALID_HANDLE;
+ }
+ Win32CsrCloseHandleEntry(&ProcessData->HandleTable[h]);
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+FASTCALL
+Win32CsrLockObject(PCSR_PROCESS ProcessData,
+ HANDLE Handle,
+ Object_t **Object,
+ DWORD Access,
+ LONG Type)
+{
+ ULONG_PTR h = (ULONG_PTR)Handle >> 2;
+
+ DPRINT("CsrGetObject, Object: %x, %x, %x\n",
+ Object, Handle, ProcessData ? ProcessData->HandleTableSize : 0);
+
+ RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+ if (!CsrIsConsoleHandle(Handle) || h >= ProcessData->HandleTableSize
+ || (*Object = ProcessData->HandleTable[h].Object) == NULL
+ || ~ProcessData->HandleTable[h].Access & Access
+ || (Type != 0 && (*Object)->Type != Type))
+ {
+ DPRINT1("CsrGetObject returning invalid handle (%x)\n", Handle);
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return STATUS_INVALID_HANDLE;
+ }
+ _InterlockedIncrement(&(*Object)->Console->ReferenceCount);
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+
+ EnterCriticalSection(&((*Object)->Console->Lock));
+ return STATUS_SUCCESS;
+}
+
+VOID
+FASTCALL
+Win32CsrUnlockObject(Object_t *Object)
+{
+ PCSRSS_CONSOLE Console = Object->Console;
+ LeaveCriticalSection(&Console->Lock);
+ /* dec ref count */
+ if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
+ ConioDeleteConsole(&Console->Header);
+}
+
+VOID
+WINAPI
+Win32CsrReleaseConsole(
+ PCSR_PROCESS ProcessData)
+{
+ PCSRSS_CONSOLE Console;
+ ULONG i;
+
+ /* Close all console handles and detach process from console */
+ RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+
+ for (i = 0; i < ProcessData->HandleTableSize; i++)
+ Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
+ ProcessData->HandleTableSize = 0;
+ RtlFreeHeap(Win32CsrApiHeap, 0, ProcessData->HandleTable);
+ ProcessData->HandleTable = NULL;
+
+ Console = ProcessData->Console;
+ if (Console != NULL)
+ {
+ ProcessData->Console = NULL;
+ EnterCriticalSection(&Console->Lock);
+ RemoveEntryList(&ProcessData->ConsoleLink);
+ LeaveCriticalSection(&Console->Lock);
+ if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
+ ConioDeleteConsole(&Console->Header);
+ //CloseHandle(ProcessData->ConsoleEvent);
+ //ProcessData->ConsoleEvent = NULL;
+ }
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+}
+
+NTSTATUS
+FASTCALL
+Win32CsrInsertObject(
+ PCSR_PROCESS ProcessData,
+ PHANDLE Handle,
+ Object_t *Object,
+ DWORD Access,
+ BOOL Inheritable,
+ DWORD ShareMode)
+{
+ ULONG i;
+ PCSRSS_HANDLE Block;
+
+ RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+
+ for (i = 0; i < ProcessData->HandleTableSize; i++)
+ {
+ if (ProcessData->HandleTable[i].Object == NULL)
+ {
+ break;
+ }
+ }
+ if (i >= ProcessData->HandleTableSize)
+ {
+ Block = RtlAllocateHeap(Win32CsrApiHeap,
+ HEAP_ZERO_MEMORY,
+ (ProcessData->HandleTableSize + 64) * sizeof(CSRSS_HANDLE));
+ if (Block == NULL)
+ {
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return(STATUS_UNSUCCESSFUL);
+ }
+ RtlCopyMemory(Block,
+ ProcessData->HandleTable,
+ ProcessData->HandleTableSize * sizeof(CSRSS_HANDLE));
+ RtlFreeHeap(Win32CsrApiHeap, 0, ProcessData->HandleTable);
+ ProcessData->HandleTable = Block;
+ ProcessData->HandleTableSize += 64;
+ }
+ ProcessData->HandleTable[i].Object = Object;
+ ProcessData->HandleTable[i].Access = Access;
+ ProcessData->HandleTable[i].Inheritable = Inheritable;
+ ProcessData->HandleTable[i].ShareMode = ShareMode;
+ Win32CsrCreateHandleEntry(&ProcessData->HandleTable[i]);
+ *Handle = UlongToHandle((i << 2) | 0x3);
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return(STATUS_SUCCESS);
+}
+
+NTSTATUS
+WINAPI
+Win32CsrDuplicateHandleTable(
+ PCSR_PROCESS SourceProcessData,
+ PCSR_PROCESS TargetProcessData)
+{
+ ULONG i;
+
+ /* Only inherit if the flag was set */
+ if (!TargetProcessData->bInheritHandles) return STATUS_SUCCESS;
+
+ if (TargetProcessData->HandleTableSize)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
+
+ /* we are called from CreateProcessData, it isn't necessary to lock the target process data */
+
+ TargetProcessData->HandleTable = RtlAllocateHeap(Win32CsrApiHeap,
+ HEAP_ZERO_MEMORY,
+ SourceProcessData->HandleTableSize
+ * sizeof(CSRSS_HANDLE));
+ if (TargetProcessData->HandleTable == NULL)
+ {
+ RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
+ return(STATUS_UNSUCCESSFUL);
+ }
+ TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
+ for (i = 0; i < SourceProcessData->HandleTableSize; i++)
+ {
+ if (SourceProcessData->HandleTable[i].Object != NULL &&
+ SourceProcessData->HandleTable[i].Inheritable)
+ {
+ TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i];
+ Win32CsrCreateHandleEntry(&TargetProcessData->HandleTable[i]);
+ }
+ }
+ RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
+ return(STATUS_SUCCESS);
+}
+
+CSR_API(CsrGetHandle)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ Request->Data.GetInputHandleRequest.Handle = INVALID_HANDLE_VALUE;
+
+ RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+ if (ProcessData->Console)
+ {
+ DWORD DesiredAccess = Request->Data.GetInputHandleRequest.Access;
+ DWORD ShareMode = Request->Data.GetInputHandleRequest.ShareMode;
+
+ PCSRSS_CONSOLE Console = ProcessData->Console;
+ Object_t *Object;
+
+ EnterCriticalSection(&Console->Lock);
+ if (Request->Type == GET_OUTPUT_HANDLE)
+ Object = &Console->ActiveBuffer->Header;
+ else
+ Object = &Console->Header;
+
+ if (((DesiredAccess & GENERIC_READ) && Object->ExclusiveRead != 0) ||
+ ((DesiredAccess & GENERIC_WRITE) && Object->ExclusiveWrite != 0) ||
+ (!(ShareMode & FILE_SHARE_READ) && Object->AccessRead != 0) ||
+ (!(ShareMode & FILE_SHARE_WRITE) && Object->AccessWrite != 0))
+ {
+ DPRINT1("Sharing violation\n");
+ Status = STATUS_SHARING_VIOLATION;
+ }
+ else
+ {
+ Status = Win32CsrInsertObject(ProcessData,
+ &Request->Data.GetInputHandleRequest.Handle,
+ Object,
+ DesiredAccess,
+ Request->Data.GetInputHandleRequest.Inheritable,
+ ShareMode);
+ }
+ LeaveCriticalSection(&Console->Lock);
+ }
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+
+ return Status;
+}
+
+CSR_API(CsrCloseHandle)
+{
+ return Win32CsrReleaseObject(ProcessData, Request->Data.CloseHandleRequest.Handle);
+}
+
+CSR_API(CsrVerifyHandle)
+{
+ ULONG_PTR Index;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ Index = (ULONG_PTR)Request->Data.VerifyHandleRequest.Handle >> 2;
+ RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+ if (Index >= ProcessData->HandleTableSize ||
+ ProcessData->HandleTable[Index].Object == NULL)
+ {
+ DPRINT("CsrVerifyObject failed\n");
+ Status = STATUS_INVALID_HANDLE;
+ }
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+
+ return Status;
+}
+
+CSR_API(CsrDuplicateHandle)
+{
+ ULONG_PTR Index;
+ PCSRSS_HANDLE Entry;
+ DWORD DesiredAccess;
+
+ Index = (ULONG_PTR)Request->Data.DuplicateHandleRequest.Handle >> 2;
+ RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+ if (Index >= ProcessData->HandleTableSize
+ || (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
+ {
+ DPRINT1("Couldn't dup invalid handle %p\n", Request->Data.DuplicateHandleRequest.Handle);
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return STATUS_INVALID_HANDLE;
+ }
+
+ if (Request->Data.DuplicateHandleRequest.Options & DUPLICATE_SAME_ACCESS)
+ {
+ DesiredAccess = Entry->Access;
+ }
+ else
+ {
+ DesiredAccess = Request->Data.DuplicateHandleRequest.Access;
+ /* Make sure the source handle has all the desired flags */
+ if (~Entry->Access & DesiredAccess)
+ {
+ DPRINT1("Handle %p only has access %X; requested %X\n",
+ Request->Data.DuplicateHandleRequest.Handle, Entry->Access, DesiredAccess);
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ Request->Status = Win32CsrInsertObject(ProcessData,
+ &Request->Data.DuplicateHandleRequest.Handle,
+ Entry->Object,
+ DesiredAccess,
+ Request->Data.DuplicateHandleRequest.Inheritable,
+ Entry->ShareMode);
+ if (NT_SUCCESS(Request->Status)
+ && Request->Data.DuplicateHandleRequest.Options & DUPLICATE_CLOSE_SOURCE)
+ {
+ Win32CsrCloseHandleEntry(Entry);
+ }
+
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return Request->Status;
+}
+
+CSR_API(CsrGetInputWaitHandle)
+{
+ Request->Data.GetConsoleInputWaitHandle.InputWaitHandle = ProcessData->ConsoleEvent;
+ return STATUS_SUCCESS;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: subsys/csrss/win32csr/dllmain.c
+ * PURPOSE: Initialization
+ * PROGRAMMERS: Dmitry Philippov (shedon@mail.ru)
+ * Timo Kreuzer (timo.kreuzer@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#define NDEBUG
+#include "w32csr.h"
+#include <debug.h>
+#include <strsafe.h>
+
+#define IDTRYAGAIN 10
+#define IDCONTINUE 11
+
+/* FUNCTIONS *****************************************************************/
+
+static
+NTSTATUS
+CsrpGetClientFileName(
+ OUT PUNICODE_STRING ClientFileNameU,
+ HANDLE hProcess)
+{
+ PLIST_ENTRY ModuleListHead;
+ PLIST_ENTRY Entry;
+ PLDR_DATA_TABLE_ENTRY Module;
+ PPEB_LDR_DATA Ldr;
+ PROCESS_BASIC_INFORMATION ClientBasicInfo;
+ LDR_DATA_TABLE_ENTRY ModuleData;
+ PVOID ClientDllBase;
+ NTSTATUS Status;
+ PPEB Peb;
+
+ /* Initialize string */
+ ClientFileNameU->MaximumLength = 0;
+ ClientFileNameU->Length = 0;
+ ClientFileNameU->Buffer = NULL;
+
+ /* Query process information */
+ Status = NtQueryInformationProcess(hProcess,
+ ProcessBasicInformation,
+ &ClientBasicInfo,
+ sizeof(ClientBasicInfo),
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ Peb = ClientBasicInfo.PebBaseAddress;
+ if (!Peb) return STATUS_UNSUCCESSFUL;
+
+ Status = NtReadVirtualMemory(hProcess, &Peb->Ldr, &Ldr, sizeof(Ldr), NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ ModuleListHead = &Ldr->InLoadOrderModuleList;
+ Status = NtReadVirtualMemory(hProcess,
+ &ModuleListHead->Flink,
+ &Entry,
+ sizeof(Entry),
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ if (Entry == ModuleListHead) return STATUS_UNSUCCESSFUL;
+
+ Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
+
+ Status = NtReadVirtualMemory(hProcess,
+ Module,
+ &ModuleData,
+ sizeof(ModuleData),
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ Status = NtReadVirtualMemory(hProcess,
+ &Peb->ImageBaseAddress,
+ &ClientDllBase,
+ sizeof(ClientDllBase),
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ if (ClientDllBase != ModuleData.DllBase) return STATUS_UNSUCCESSFUL;
+
+ ClientFileNameU->MaximumLength = ModuleData.BaseDllName.MaximumLength;
+ ClientFileNameU->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ ClientFileNameU->MaximumLength);
+
+ Status = NtReadVirtualMemory(hProcess,
+ ModuleData.BaseDllName.Buffer,
+ ClientFileNameU->Buffer,
+ ClientFileNameU->MaximumLength,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, ClientFileNameU->Buffer);
+ ClientFileNameU->Buffer = NULL;
+ ClientFileNameU->MaximumLength = 0;
+ return Status;
+ }
+
+ ClientFileNameU->Length = wcslen(ClientFileNameU->Buffer)*sizeof(wchar_t);
+ DPRINT("ClientFileNameU=\'%wZ\'\n", &ClientFileNameU);
+
+ return STATUS_SUCCESS;
+}
+
+static
+VOID
+CsrpFreeStringParameters(
+ IN OUT PULONG_PTR Parameters,
+ IN PHARDERROR_MSG HardErrorMessage)
+{
+ ULONG nParam;
+
+ /* Loop all parameters */
+ for (nParam = 0; nParam < HardErrorMessage->NumberOfParameters; nParam++)
+ {
+ /* Check if the current parameter is a string */
+ if (HardErrorMessage->UnicodeStringParameterMask & (1 << nParam) && Parameters[nParam])
+ {
+ /* Free the string buffer */
+ RtlFreeHeap(RtlGetProcessHeap(), 0, (PVOID)Parameters[nParam]);
+ }
+ }
+}
+
+static
+NTSTATUS
+CsrpCaptureStringParameters(
+ OUT PULONG_PTR Parameters,
+ OUT PULONG SizeOfAllUnicodeStrings,
+ IN PHARDERROR_MSG HardErrorMessage,
+ HANDLE hProcess)
+{
+ ULONG nParam, Size = 0;
+ NTSTATUS Status = STATUS_SUCCESS;
+ UNICODE_STRING TempStringU, ParamStringU;
+ ANSI_STRING TempStringA;
+
+ /* Read all strings from client space */
+ for (nParam = 0; nParam < HardErrorMessage->NumberOfParameters; nParam++)
+ {
+ Parameters[nParam] = 0;
+
+ /* Check if the current parameter is a unicode string */
+ if (HardErrorMessage->UnicodeStringParameterMask & (1 << nParam))
+ {
+ /* Read the UNICODE_STRING from the process memory */
+ Status = NtReadVirtualMemory(hProcess,
+ (PVOID)HardErrorMessage->Parameters[nParam],
+ &ParamStringU,
+ sizeof(ParamStringU),
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ break;
+
+ /* Allocate a buffer for the string */
+ TempStringU.MaximumLength = ParamStringU.Length;
+ TempStringU.Length = ParamStringU.Length;
+ TempStringU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ TempStringU.MaximumLength);
+
+ if (!TempStringU.Buffer)
+ {
+ DPRINT1("Cannot allocate memory %u\n", TempStringU.MaximumLength);
+ Status = STATUS_NO_MEMORY;
+ }
+
+ /* Read the string buffer from the process memory */
+ Status = NtReadVirtualMemory(hProcess,
+ ParamStringU.Buffer,
+ TempStringU.Buffer,
+ ParamStringU.Length,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtReadVirtualMemory failed with code: %lx\n", Status);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU.Buffer);
+ break;
+ }
+
+ DPRINT("ParamString=\'%wZ\'\n", &TempStringU);
+
+ /* Allocate a buffer for converted to ANSI string */
+ TempStringA.MaximumLength = RtlUnicodeStringToAnsiSize(&TempStringU);
+ TempStringA.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ TempStringA.MaximumLength);
+
+ if (!TempStringA.Buffer)
+ {
+ DPRINT1("Cannot allocate memory %u\n", TempStringA.MaximumLength);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU.Buffer);
+ Status = STATUS_NO_MEMORY;
+ break;
+ }
+
+ /* Convert string to ANSI and free temporary buffer */
+ Status = RtlUnicodeStringToAnsiString(&TempStringA, &TempStringU, FALSE);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU.Buffer);
+ if (!NT_SUCCESS(Status))
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringA.Buffer);
+ break;
+ }
+
+ /* Note: RtlUnicodeStringToAnsiString returns NULL terminated string */
+ Parameters[nParam] = (ULONG_PTR)TempStringA.Buffer;
+ Size += TempStringU.Length;
+ }
+ else
+ {
+ /* It's not a unicode string */
+ Parameters[nParam] = HardErrorMessage->Parameters[nParam];
+ }
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ CsrpFreeStringParameters(Parameters, HardErrorMessage);
+ return Status;
+ }
+
+ *SizeOfAllUnicodeStrings = Size;
+ return Status;
+}
+
+static
+NTSTATUS
+CsrpFormatMessages(
+ OUT PUNICODE_STRING TextStringU,
+ OUT PUNICODE_STRING CaptionStringU,
+ IN PULONG_PTR Parameters,
+ IN ULONG SizeOfStrings,
+ IN PHARDERROR_MSG Message,
+ IN HANDLE hProcess)
+{
+ NTSTATUS Status;
+ UNICODE_STRING FileNameU, TempStringU, FormatU;
+ ANSI_STRING FormatA;
+ PMESSAGE_RESOURCE_ENTRY MessageResource;
+ PWSTR FormatString;
+ ULONG Size, ExceptionCode;
+
+ /* Get the file name of the client process */
+ CsrpGetClientFileName(&FileNameU, hProcess);
+
+ /* Check if we have a file name */
+ if (!FileNameU.Buffer)
+ {
+ /* No, use system */
+ RtlInitUnicodeString(&FileNameU, L"System");
+ }
+
+ /* Get text string of the error code */
+ Status = RtlFindMessage(GetModuleHandleW(L"ntdll"),
+ (ULONG_PTR)RT_MESSAGETABLE,
+ LANG_NEUTRAL,
+ Message->Status,
+ &MessageResource);
+
+ if (NT_SUCCESS(Status))
+ {
+ if (MessageResource->Flags)
+ {
+ RtlInitUnicodeString(&FormatU, (PWSTR)MessageResource->Text);
+ FormatA.Buffer = NULL;
+ }
+ else
+ {
+ RtlInitAnsiString(&FormatA, (PCHAR)MessageResource->Text);
+ RtlAnsiStringToUnicodeString(&FormatU, &FormatA, TRUE);
+ }
+ }
+ else
+ {
+ /* Fall back to hardcoded value */
+ RtlInitUnicodeString(&FormatU, L"Unknown Hard Error");
+ FormatA.Buffer = NULL;
+ }
+
+ FormatString = FormatU.Buffer;
+
+ /* Check whether a caption exists */
+ if (FormatString[0] == L'{')
+ {
+ /* Set caption start */
+ TempStringU.Buffer = ++FormatString;
+
+ /* Get size of the caption */
+ for (Size = 0; *FormatString != 0 && *FormatString != L'}'; Size++)
+ FormatString++;
+
+ /* Skip '}', '\r', '\n' */
+ FormatString += 3;
+
+ TempStringU.Length = Size * sizeof(WCHAR);
+ TempStringU.MaximumLength = TempStringU.Length;
+ }
+ else
+ {
+ /* FIXME: Set string based on severity */
+ RtlInitUnicodeString(&TempStringU, L"Application Error");
+ }
+
+ /* Calculate buffer length for the caption */
+ CaptionStringU->MaximumLength = FileNameU.Length + TempStringU.Length +
+ 4 * sizeof(WCHAR);
+
+ /* Allocate a buffer for the caption */
+ CaptionStringU->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ CaptionStringU->MaximumLength);
+
+ /* Append the file name, seperator and the caption text */
+ CaptionStringU->Length = 0;
+ RtlAppendUnicodeStringToString(CaptionStringU, &FileNameU);
+ RtlAppendUnicodeToString(CaptionStringU, L" - ");
+ RtlAppendUnicodeStringToString(CaptionStringU, &TempStringU);
+
+ /* Zero terminate the buffer */
+ CaptionStringU->Buffer[CaptionStringU->Length / sizeof(WCHAR)] = 0;
+
+ /* Free the file name buffer */
+ RtlFreeUnicodeString(&FileNameU);
+
+ /* Check if this is an exception message */
+ if (Message->Status == STATUS_UNHANDLED_EXCEPTION)
+ {
+ ExceptionCode = Parameters[0];
+
+ /* Handle special cases */
+ if (ExceptionCode == STATUS_ACCESS_VIOLATION)
+ {
+ Parameters[0] = Parameters[1];
+ Parameters[1] = Parameters[3];
+ if (Parameters[2]) Parameters[2] = (ULONG_PTR)L"written";
+ else Parameters[2] = (ULONG_PTR)L"read";
+ MessageResource = NULL;
+ }
+ else if (ExceptionCode == STATUS_IN_PAGE_ERROR)
+ {
+ Parameters[0] = Parameters[1];
+ Parameters[1] = Parameters[3];
+ MessageResource = NULL;
+ }
+ else
+ {
+ /* Fall back to hardcoded value */
+ Parameters[2] = Parameters[1];
+ Parameters[1] = Parameters[0];
+ Parameters[0] = (ULONG_PTR)L"unknown software exception";
+ }
+
+ if (!MessageResource)
+ {
+ /* Get text string of the exception code */
+ Status = RtlFindMessage(GetModuleHandleW(L"ntdll"),
+ (ULONG_PTR)RT_MESSAGETABLE,
+ LANG_NEUTRAL,
+ ExceptionCode,
+ &MessageResource);
+
+ if (NT_SUCCESS(Status))
+ {
+ if (FormatA.Buffer) RtlFreeUnicodeString(&FormatU);
+
+ if (MessageResource->Flags)
+ {
+ RtlInitUnicodeString(&FormatU, (PWSTR)MessageResource->Text);
+ FormatA.Buffer = NULL;
+ }
+ else
+ {
+ RtlInitAnsiString(&FormatA, (PCHAR)MessageResource->Text);
+ RtlAnsiStringToUnicodeString(&FormatU, &FormatA, TRUE);
+ }
+ FormatString = FormatU.Buffer;
+ }
+ else
+ {
+ /* Fall back to hardcoded value */
+ Parameters[2] = Parameters[1];
+ Parameters[1] = Parameters[0];
+ Parameters[0] = (ULONG_PTR)L"unknown software exception";
+ }
+ }
+ }
+
+ /* Calculate length of text buffer */
+ TextStringU->MaximumLength = FormatU.Length + SizeOfStrings + 42 * sizeof(WCHAR);
+
+ /* Allocate a buffer for the text */
+ TextStringU->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ TextStringU->MaximumLength);
+
+ /* Wrap in SEH to protect from invalid string parameters */
+ _SEH2_TRY
+ {
+ /* Print the string into the buffer */
+ StringCbPrintfW(TextStringU->Buffer,
+ TextStringU->MaximumLength,
+ FormatString,
+ Parameters[0],
+ Parameters[1],
+ Parameters[2],
+ Parameters[3]);
+ Status = STATUS_SUCCESS;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Set error and free buffers */
+ Status = _SEH2_GetExceptionCode();
+ RtlFreeHeap(RtlGetProcessHeap(), 0, TextStringU->Buffer);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, CaptionStringU->Buffer);
+ }
+ _SEH2_END
+
+ if (NT_SUCCESS(Status))
+ {
+ TextStringU->Length = wcslen(TextStringU->Buffer) * sizeof(WCHAR);
+ }
+
+ if (FormatA.Buffer) RtlFreeUnicodeString(&FormatU);
+
+ return Status;
+}
+
+static
+ULONG
+CsrpMessageBox(
+ PWSTR Text,
+ PWSTR Caption,
+ ULONG ValidResponseOptions,
+ ULONG Severity)
+{
+ ULONG Type, MessageBoxResponse;
+
+ /* Set the message box type */
+ switch (ValidResponseOptions)
+ {
+ case OptionAbortRetryIgnore:
+ Type = MB_ABORTRETRYIGNORE;
+ break;
+ case OptionOk:
+ Type = MB_OK;
+ break;
+ case OptionOkCancel:
+ Type = MB_OKCANCEL;
+ break;
+ case OptionRetryCancel:
+ Type = MB_RETRYCANCEL;
+ break;
+ case OptionYesNo:
+ Type = MB_YESNO;
+ break;
+ case OptionYesNoCancel:
+ Type = MB_YESNOCANCEL;
+ break;
+ case OptionShutdownSystem:
+ Type = MB_RETRYCANCEL; // FIXME???
+ break;
+ /* Anything else is invalid */
+ default:
+ return ResponseNotHandled;
+ }
+
+ /* Set severity */
+ if (Severity == STATUS_SEVERITY_INFORMATIONAL) Type |= MB_ICONINFORMATION;
+ else if (Severity == STATUS_SEVERITY_WARNING) Type |= MB_ICONWARNING;
+ else if (Severity == STATUS_SEVERITY_ERROR) Type |= MB_ICONERROR;
+
+ Type |= MB_SYSTEMMODAL | MB_SETFOREGROUND;
+
+ DPRINT("Text = '%S', Caption = '%S', Severity = %d, Type = 0x%lx\n",
+ Text, Caption, Severity, Type);
+
+ /* Display a message box */
+ MessageBoxResponse = MessageBoxW(0, Text, Caption, Type);
+
+ /* Return response value */
+ switch (MessageBoxResponse)
+ {
+ case IDOK: return ResponseOk;
+ case IDCANCEL: return ResponseCancel;
+ case IDYES: return ResponseYes;
+ case IDNO: return ResponseNo;
+ case IDABORT: return ResponseAbort;
+ case IDIGNORE: return ResponseIgnore;
+ case IDRETRY: return ResponseRetry;
+ case IDTRYAGAIN: return ResponseTryAgain;
+ case IDCONTINUE: return ResponseContinue;
+ }
+
+ return ResponseNotHandled;
+}
+
+VOID
+WINAPI
+Win32CsrHardError(
+ IN PCSR_THREAD ThreadData,
+ IN PHARDERROR_MSG Message)
+{
+#if DBG
+ PCSR_PROCESS ProcessData = ThreadData->Process;
+#endif
+ ULONG_PTR Parameters[MAXIMUM_HARDERROR_PARAMETERS];
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING TextU, CaptionU;
+ NTSTATUS Status;
+ HANDLE hProcess;
+ ULONG Size;
+
+ /* Default to not handled */
+ ASSERT(ProcessData != NULL);
+ Message->Response = ResponseNotHandled;
+
+ /* Make sure we don't have too many parameters */
+ if (Message->NumberOfParameters > MAXIMUM_HARDERROR_PARAMETERS)
+ Message->NumberOfParameters = MAXIMUM_HARDERROR_PARAMETERS;
+
+ /* Initialize object attributes */
+ InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
+
+ /* Open client process */
+ Status = NtOpenProcess(&hProcess,
+ PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
+ &ObjectAttributes,
+ &Message->h.ClientId);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtOpenProcess failed with code: %lx\n", Status);
+ return;
+ }
+
+ /* Capture all string parameters from the process memory */
+ Status = CsrpCaptureStringParameters(Parameters, &Size, Message, hProcess);
+ if (!NT_SUCCESS(Status))
+ {
+ NtClose(hProcess);
+ return;
+ }
+
+ /* Format the caption and message box text */
+ Status = CsrpFormatMessages(&TextU,
+ &CaptionU,
+ Parameters,
+ Size,
+ Message,
+ hProcess);
+
+ /* Cleanup */
+ CsrpFreeStringParameters(Parameters, Message);
+ NtClose(hProcess);
+
+ if (!NT_SUCCESS(Status))
+ {
+ return;
+ }
+
+ /* Display the message box */
+ Message->Response = CsrpMessageBox(TextU.Buffer,
+ CaptionU.Buffer,
+ Message->ValidResponseOptions,
+ (ULONG)Message->Status >> 30);
+
+ RtlFreeUnicodeString(&TextU);
+ RtlFreeUnicodeString(&CaptionU);
+
+ return;
+}
+
--- /dev/null
+/*
+ * PROJECT: ReactOS CSRSS subsystem
+ * FILE: subsystems/win32/csrss/win32csr/lang/bg-BG.rc
+ * PURPOSE: Bulgarian resource file
+ */
+
+LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Ïðåêðàòÿâàíå íà ïðèëîæåíèå - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Ïðåêðàòÿâàíå íà ïðèëîæåíèåòî... Ïî÷àêàéòå",IDC_STATIC,7,7,186,11
+ CONTROL "Õîä",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Àêî ðåøèòå äà çàòâîðèòå ïðèëîæåíèåòî âåäíàãà, ùå èçãóáèòå âñè÷êè íåçàïèñàíè äàííè. Çà äà ïðåêðàòèòå ïðèëîæåíèåòî âåäíàãà, íàòèñíåòå \84Ïðåêðàòÿâàíå âåäíàãà\84.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "&Ïðåêðàòÿâàíå âåäíàãà",IDC_END_NOW,150,71,60,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Ïðåêðàòÿâàíå íà ïðèëîæåíèå - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Îòêàç",IDCANCEL,142,98,43,17
+ PUSHBUTTON "&Ïðåêðàòÿâàíå âåäíàãà",IDC_END_NOW,150,71,60,17
+ LTEXT "Ïðèëîæåíèåòî íå îòãîâàðÿ",IDC_STATIC,7,7,178,8
+ LTEXT "Çà äà ñå âúðíåòå â ÐåàêòÎÑ è äà ïðîâåðèòå ñúñòîÿíèåòî íà ïðèëîæåíèåòî, íàòèñíåòå \84Îòêàç\93.",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Àêî ðåøèòå äà çàòâîðèòå ïðèëîæåíèåòî âåäíàãà, ùå èçãóáèòå âñè÷êè íåçàïèñàíè äàííè. Çà äà ïðåêðàòèòå ïðèëîæåíèåòî âåäíàãà, íàòèñíåòå \84Ïðåêðàòÿâàíå âåäíàãà\93.",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Îáðàáîòêà"
+ IDS_MARK "Îòáåëÿçâàíå"
+ IDS_COPY "Çàïîìíÿíå\tEnter"
+ IDS_PASTE "Ïîñòàâÿíå"
+ IDS_SELECTALL "Èçáîð íà âñè÷êî"
+ IDS_SCROLL "Ïðåëèñòâàíå"
+ IDS_FIND "Òúðñåíå..."
+ IDS_DEFAULTS "Ïîäðàçáèðàíè"
+ IDS_PROPERTIES "Ñâîéñòâà"
+ IDS_SCROLLHERE "Ïðåëèñòâàíå òóê"
+ IDS_SCROLLTOP "Ïðåëèñòâàíå äî ãîðå"
+ IDS_SCROLLBOTTOM "Ïðåëèñòâàíå äî äîëó"
+ IDS_SCROLLPAGE_UP "Ãîðíà ñòðàíèöà"
+ IDS_SCROLLPAGE_DOWN "Äîëíà ñòðàíèöà"
+ IDS_SCROLLUP "Ïðåëèñòâàíå íàãîðå"
+ IDS_SCROLLDOWN "Ïðåëèñòâàíå íàäîëó"
+
+ IDS_COMMAND_PROMPT "Command Prompt"
+END
--- /dev/null
+/* FILE: subsystems/win32/csrss/win32csr/lang/cs-CZ.rc
+ * TRANSLATOR: Radek Liska aka Black_Fox (radekliska at gmail dot com)
+ * UPDATED: 2011-04-09
+ */
+
+LANGUAGE LANG_CZECH, SUBLANG_DEFAULT
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Ukonèit program - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Probíhá ukonèení programu... Èekejte, prosím",IDC_STATIC,7,7,186,11
+ CONTROL "Progress",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "IPokud zvolíte okam\9eité ukonèení programu, v\9aechna neulo\9eená data budou ztracena. Kliknutím na Ukonèit okam\9eitì ukonèíte program.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "&Ukonèit okam\9eitì",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Ukonèit program - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Storno",IDCANCEL,142,98,43,17
+ PUSHBUTTON "&Ukonèit okam\9eitì",IDC_END_NOW,78,98,43,17
+ LTEXT "Tento program neodpovídá",IDC_STATIC,7,7,178,8
+ LTEXT "Kliknutím na Storno se lze vrátit do systému ReactOS a ovìøit stav programu",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Pokud zvolíte okam\9eité ukonèení programu, v\9aechna neulo\9eená data budou ztracena. Kliknutím na Ukonèit okam\9eitì ukonèíte program.",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Upravit"
+ IDS_MARK "Oznaèit"
+ IDS_COPY "Kopírovat\tEnter"
+ IDS_PASTE "Vlo\9eit"
+ IDS_SELECTALL "Oznaèit v\9ae"
+ IDS_SCROLL "Posunout"
+ IDS_FIND "Najít..."
+ IDS_DEFAULTS "Výchozí"
+ IDS_PROPERTIES "Vlastnosti"
+ IDS_SCROLLHERE "Posunout sem"
+ IDS_SCROLLTOP "Posunout na zaèátek"
+ IDS_SCROLLBOTTOM "Posunout na konec"
+ IDS_SCROLLPAGE_UP "O stránku vý\9ae"
+ IDS_SCROLLPAGE_DOWN "O stránku ní\9ee"
+ IDS_SCROLLUP "Posunout nahoru"
+ IDS_SCROLLDOWN "Posunout dolù"
+
+ IDS_COMMAND_PROMPT "Pøíkazový øádek"
+END
--- /dev/null
+LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Programm beenden - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Programm wird beendet...",IDC_STATIC,7,7,186,11
+ CONTROL "Fortschritt",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Wenn Sie das Programm sofort beenden, werden Sie eventuell ungespeicherte Daten verlieren. Um das Programm zu beenden, wählen Sie Jetzt beenden.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "J&etzt beenden",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Programm beenden - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Abbechen",IDCANCEL,142,98,43,17
+ PUSHBUTTON "J&etzt beenden",IDC_END_NOW,78,98,43,17
+ LTEXT "Das Programm reagiert nicht",IDC_STATIC,7,7,178,8
+ LTEXT "Um zu ReactOS zurückzukehren und den Status der Anwendung zu überprüfen, wählen Sie Abbrechen.",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Wenn Sie das Programm sofort beenden, werden Sie eventuell ungespeicherte Daten verlieren. Um das Programm zu beenden, wählen Sie Jetzt beenden.",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Bearbeiten"
+ IDS_MARK "Markieren"
+ IDS_COPY "Kopieren\tEnter"
+ IDS_PASTE "Einfügen"
+ IDS_SELECTALL "Alles auswählen"
+ IDS_SCROLL "Scrollen"
+ IDS_FIND "Suchen..."
+ IDS_DEFAULTS "Standardwerte"
+ IDS_PROPERTIES "Eigenschaften"
+ IDS_SCROLLHERE "Hier scrollen"
+ IDS_SCROLLTOP "Ganz nach oben scrollen"
+ IDS_SCROLLBOTTOM "Ganz nach unten scrollen"
+ IDS_SCROLLPAGE_UP "Seite nach oben"
+ IDS_SCROLLPAGE_DOWN "Seite nach unten"
+ IDS_SCROLLUP "Nach oben scrollen"
+ IDS_SCROLLDOWN "Nach unten scrollen"
+
+ IDS_COMMAND_PROMPT "Eingabeaufforderung"
+END
--- /dev/null
+LANGUAGE LANG_GREEK, SUBLANG_DEFAULT
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Êëåßóéìï ðñïãñÜììáôïò - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Êëåßóéìï ðñïãñÜììáôïò... Ðáñáêáëþ ðåñéìÝíåôå",IDC_STATIC,7,7,186,11
+ CONTROL "Ðñüïäïò",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Áí êëåßóåôå ôçí åöáñìïãÞ ôþñá , èá ÷Üóåôå üëá ôá ìç áðïèçêåõìÝíá äåäïìÝíá. Ãéá íá êëåßóåôå ôï ðñüãñáììá ôþñá, ðáôÞóôå 'Êëåßóéìï Ôþñá'.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "&Êëåßóéìï Ôþñá",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Êëåßóçìï ðñïãñÜììáôïò - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "¢êõñï",IDCANCEL,142,98,43,17
+ PUSHBUTTON "&Êëåßóéìï Ôþñá",IDC_END_NOW,78,98,43,17
+ LTEXT "Ôï ðñüãñáììá äåí áðïêñßíåôáé",IDC_STATIC,7,7,178,8
+ LTEXT "Ãéá íá åðéóôñÝøåôå óôï ReactOS êáé íá åëÝãîåôå ôçí êáôÜóôáóç ôïõ ðñïãñÜììáôïò, ðáôÞóôå '¢êõñï'",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Áí êëåßóåôå ôçí åöáñìïãÞ ôþñá , èá ÷Üóåôå üëá ôá ìç áðïèçêåõìÝíá äåäïìÝíá. Ãéá íá êëåßóåôå ôï ðñüãñáììá ôþñá, ðáôÞóôå 'Êëåßóéìï Ôþñá'.",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Åðåîåñãáóßá"
+ IDS_MARK "ÌáñêÜñéóìá"
+ IDS_COPY "ÁíôéãñáöÞ\tEnter"
+ IDS_PASTE "Åðéêüëëçóç"
+ IDS_SELECTALL "ÅðéëïãÞ üëùí"
+ IDS_SCROLL "Êýëéóç"
+ IDS_FIND "Åýñåóç..."
+ IDS_DEFAULTS "ÐñïåðéëïãÞ"
+ IDS_PROPERTIES "Éäéüôçôåò"
+ IDS_SCROLLHERE "Êýëéóç åäþ"
+ IDS_SCROLLTOP "Áñ÷Þ"
+ IDS_SCROLLBOTTOM "ÔÝëïò"
+ IDS_SCROLLPAGE_UP "Ðñïçãïýìåíç óåëßäá"
+ IDS_SCROLLPAGE_DOWN "Åðüìåíç óåëßäá"
+ IDS_SCROLLUP "Êýëéóç ðÜíù"
+ IDS_SCROLLDOWN "Êýëéóç êÜôù"
+
+ IDS_COMMAND_PROMPT "Command Prompt"
+END
--- /dev/null
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "End Program - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Ending Program... Please wait",IDC_STATIC,7,7,186,11
+ CONTROL "Progress",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "If you choose to end the program immediately, you will lose any unsaved data. To end the program now, click End Now.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "&End Now",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "End Program - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Cancel",IDCANCEL,142,98,43,17
+ PUSHBUTTON "&End Now",IDC_END_NOW,78,98,43,17
+ LTEXT "This program is not responding",IDC_STATIC,7,7,178,8
+ LTEXT "To return to ReactOS and check the status of the program, click Cancel",
+ IDC_STATIC,7,26,178,16
+ LTEXT "If you choose to end the program immediately, you will lose any unsaved data. To end the program now, click End Now",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Edit"
+ IDS_MARK "Mark"
+ IDS_COPY "Copy\tEnter"
+ IDS_PASTE "Paste"
+ IDS_SELECTALL "Select All"
+ IDS_SCROLL "Scroll"
+ IDS_FIND "Find..."
+ IDS_DEFAULTS "Defaults"
+ IDS_PROPERTIES "Properties"
+ IDS_SCROLLHERE "Scroll here"
+ IDS_SCROLLTOP "Scroll top"
+ IDS_SCROLLBOTTOM "Scroll bottom"
+ IDS_SCROLLPAGE_UP "Page up"
+ IDS_SCROLLPAGE_DOWN "Page down"
+ IDS_SCROLLUP "Scroll up"
+ IDS_SCROLLDOWN "Scroll down"
+
+ IDS_COMMAND_PROMPT "Command Prompt"
+END
--- /dev/null
+/*
+ *Spanish Language resource file
+ * Traducido por: Javier Remacha 2008-26-01
+ */
+
+LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Finalizar programa - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Finalizando programa... Por favor, espere",IDC_STATIC,7,7,186,11
+ CONTROL "Progreso",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Si elige finalizar el programa ahora, perderá todos los datos no guardados. Para finalizar el programa ahora, haga clic en Finalizar ahora.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "&Finalizar ahora",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Finalizar programa - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Cancelar",IDCANCEL,142,98,43,17
+ PUSHBUTTON "&Finalizar ahora",IDC_END_NOW,78,98,43,17
+ LTEXT "Este programa no responde",IDC_STATIC,7,7,178,8
+ LTEXT "Para volver a ReactOS y ver el estado del programa, haga clic en Cancelar",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Si elige finalizar el programa ahora, perderá todos los datos no guardados. Para finalizar el programa ahora, haga clic en Finalizar ahora.",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Editar"
+ IDS_MARK "Marcar"
+ IDS_COPY "Copiar\tIntroducir"
+ IDS_PASTE "Pegar"
+ IDS_SELECTALL "Seleccionar Todo"
+ IDS_SCROLL "Desplazar"
+ IDS_FIND "Buscar..."
+ IDS_DEFAULTS "Por defecto"
+ IDS_PROPERTIES "Propiedades"
+ IDS_SCROLLHERE "Desplazar aquí"
+ IDS_SCROLLTOP "Desplazar hasta arriba"
+ IDS_SCROLLBOTTOM "Desplazar hasta abajo"
+ IDS_SCROLLPAGE_UP "Subir página"
+ IDS_SCROLLPAGE_DOWN "Bajar página"
+ IDS_SCROLLUP "Desplazar arriba"
+ IDS_SCROLLDOWN "Desplazar abajo"
+
+ IDS_COMMAND_PROMPT "Command Prompt"
+END
--- /dev/null
+LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Fin du programme - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Termine le programme... Veuillez patienter",IDC_STATIC,7,7,186,11
+ CONTROL "Avancement",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Si vous choisissez de terminer le programme immédiatement, vous perdrez toutes les données non sauvegardées. Pour terminer le programme maintenant, cliquez sur Terminer maintenant.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "T&erminer maintenant",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Fin du programme - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Annuler",IDCANCEL,142,98,43,17
+ PUSHBUTTON "T&erminer maintenant",IDC_END_NOW,78,98,43,17
+ LTEXT "Ce programme ne répond pas",IDC_STATIC,7,7,178,8
+ LTEXT "Pour retourner à ReactOS et vérifier l'état du programme, cliquez sur Annuler",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Si vous choisissez de terminer le programme immédiatement, vous perdrez toutes les données non sauvegardées. Pour terminer le programme maintenant, cliquez sur Terminer maintenant",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+/* Fixme : Translation could be really improved, with context
+ La traduction pourrait réellement être améliorée grâce au contexte */
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Éditer"
+ IDS_MARK "Marquer"
+ IDS_COPY "Copier\tEntrée"
+ IDS_PASTE "Coller"
+ IDS_SELECTALL "Tout sélectionner"
+ IDS_SCROLL "Défiler"
+ IDS_FIND "Trouver..."
+ IDS_DEFAULTS "Défauts"
+ IDS_PROPERTIES "Propriétés"
+ IDS_SCROLLHERE "Défiler ici"
+ IDS_SCROLLTOP "Défiler tout en haut"
+ IDS_SCROLLBOTTOM "Défiler tout en bas"
+ IDS_SCROLLPAGE_UP "Page précédente"
+ IDS_SCROLLPAGE_DOWN "Page suivante"
+ IDS_SCROLLUP "Défiler en haut"
+ IDS_SCROLLDOWN "Défiler en bas"
+
+ IDS_COMMAND_PROMPT "Command Prompt"
+END
--- /dev/null
+LANGUAGE LANG_HEBREW, SUBLANG_DEFAULT
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "סיום תכנית - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "מסיים תכנית... נא להמתין",IDC_STATIC,7,7,186,11
+ CONTROL "Progress",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "If you choose to end the program immediately, you will lose any unsaved data. To end the program now, click End Now.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "סיים כעת",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "סיום תכנית - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "ביטול",IDCANCEL,142,98,43,17
+ PUSHBUTTON "סיים כעת",IDC_END_NOW,78,98,43,17
+ LTEXT "התכנית אינה מגיבה",IDC_STATIC,7,7,178,8
+ LTEXT "To return to ReactOS and check the status of the program, click Cancel",
+ IDC_STATIC,7,26,178,16
+ LTEXT "If you choose to end the program immediately, you will lose any unsaved data. To end the program now, click End Now",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "ערוך"
+ IDS_MARK "סמן"
+ IDS_COPY "העתק\tEnter"
+ IDS_PASTE "הדבק"
+ IDS_SELECTALL "בחר הכל"
+ IDS_SCROLL "גלול"
+ IDS_FIND "מצא..."
+ IDS_DEFAULTS "ברירת מחדל"
+ IDS_PROPERTIES "מאפיינים"
+ IDS_SCROLLHERE "גלול לכאן"
+ IDS_SCROLLTOP "גלול למעלה"
+ IDS_SCROLLBOTTOM "גלול למטה"
+ IDS_SCROLLPAGE_UP "עמוד מעלה"
+ IDS_SCROLLPAGE_DOWN "עמוד מטה"
+ IDS_SCROLLUP "גלול מעלה"
+ IDS_SCROLLDOWN "גלול מטה"
+
+ IDS_COMMAND_PROMPT "שורת הפקודה"
+END
--- /dev/null
+LANGUAGE LANG_INDONESIAN, SUBLANG_DEFAULT
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Akhir Program - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Mengakhiri Program... Harap menunggu",IDC_STATIC,7,7,186,11
+ CONTROL "Progres",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Jika anda memilih untuk segera mengakhiri program, anda akan kehilangan data yang belum disimpan. Untuk mengakhiri program sekarang, klik Akhiri Sekarang.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "&Akhiri Sekarang",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Mengakhiri Program - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Batal",IDCANCEL,142,98,43,17
+ PUSHBUTTON "&Akhiri Sekarang",IDC_END_NOW,78,98,43,17
+ LTEXT "Program ini tidak merespon",IDC_STATIC,7,7,178,8
+ LTEXT "Untuk kembali ke ReactOS dan memeriksa status program, klik Batal",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Jika anda memilih untuk segera mengakhiri program, anda akan kehilangan data yang belum disimpan. Untuk mengakhiri program sekarang, klik Akhiri Sekarang.",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Edit"
+ IDS_MARK "Tandai"
+ IDS_COPY "Copy\tEnter"
+ IDS_PASTE "Paste"
+ IDS_SELECTALL "Pilih Semua"
+ IDS_SCROLL "Gulung"
+ IDS_FIND "Cari..."
+ IDS_DEFAULTS "Standar"
+ IDS_PROPERTIES "Properti"
+ IDS_SCROLLHERE "Gulung ke Sini"
+ IDS_SCROLLTOP "Gulung ke Atas"
+ IDS_SCROLLBOTTOM "Gulung ke Bawah"
+ IDS_SCROLLPAGE_UP "Halaman Naik"
+ IDS_SCROLLPAGE_DOWN "Halaman Turun"
+ IDS_SCROLLUP "Gulung Naik"
+ IDS_SCROLLDOWN "Gulung Turun"
+
+ IDS_COMMAND_PROMPT "Command Prompt"
+END
--- /dev/null
+/*
+* PROJECT: ReactOS Client/Server Runtime subsystem
+* LICENSE: GPL - See COPYING in the top level directory
+* FILE: subsystems/win32/csrss/win32csr/lang/it-IT.rc
+* PURPOSE: Italian Translation of subsystems/win32/csrss/win32csr/lang/en-US.rc
+* PROGRAMMERS:
+* Copyright (C) 2007 Daniele Forsi (dforsi at gmail.com) Italian Translation
+*/
+
+LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Arresto del programma - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Arresto del programma... Attendere",IDC_STATIC,7,7,186,11
+ CONTROL "Progresso",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Se si sceglie di terminare il programma immediatamente, si perderanno tutti i dati non salvati. Per terminare il programma ora, selezionare Termina ora.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "T&ermina ora",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Arresto del programma - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Annulla",IDCANCEL,142,98,43,17
+ PUSHBUTTON "T&ermina ora",IDC_END_NOW,78,98,43,17
+ LTEXT "Il programma non risponde",IDC_STATIC,7,7,178,8
+ LTEXT "Per tornare a ReactOS e controllare lo stato del programma, selezionare Annulla",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Se si sceglie di terminare il programma immediatamente, si perderanno tutti i dati non salvati. Per terminare il programma ora, selezionare Termina ora.",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Modifica"
+ IDS_MARK "Seleziona"
+ IDS_COPY "Copia\tInvio"
+ IDS_PASTE "Incolla"
+ IDS_SELECTALL "Seleziona tutto"
+ IDS_SCROLL "Scorri"
+ IDS_FIND "Trova..."
+ IDS_DEFAULTS "Impostazioni predefinite"
+ IDS_PROPERTIES "Proprietà"
+ IDS_SCROLLHERE "Scorri qui"
+ IDS_SCROLLTOP "Scorri in cima"
+ IDS_SCROLLBOTTOM "Scorri in fondo"
+ IDS_SCROLLPAGE_UP "Pagina sù"
+ IDS_SCROLLPAGE_DOWN "Pagina giù"
+ IDS_SCROLLUP "Scorri sù"
+ IDS_SCROLLDOWN "Scorri giù"
+
+ IDS_COMMAND_PROMPT "Prompt dei commandi"
+END
--- /dev/null
+LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "\83v\83\8d\83O\83\89\83\80\82Ì\8fI\97¹ - "
+FONT 9, "MS UI Gothic"
+BEGIN
+ LTEXT "\83v\83\8d\83O\83\89\83\80\82ð\8fI\97¹\82µ\82Ä\82¢\82Ü\82·... \82µ\82Î\82ç\82\82¨\91Ò\82¿\82\82¾\82³\82¢",IDC_STATIC,7,7,186,11
+ CONTROL "Progress",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "\83v\83\8d\83O\83\89\83\80\82ð\82·\82®\82É\8fI\97¹\82³\82¹\82é\82æ\82¤\91I\91ð\82µ\82½\8fê\8d\87\81A\95Û\91¶\82³\82ê\82Ä\82¢\82È\82¢\83f\81[\83^\82Í\82·\82×\82Ä\8e¸\82í\82ê\82Ü\82·\81B\83v\83\8d\83O\83\89\83\80\82ð\8fI\97¹\82·\82é\82É\82Í[\82·\82®\82É\8fI\97¹]\82ð\83N\83\8a\83b\83N\82µ\82Ä\82\82¾\82³\82¢\81B",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "\82·\82®\82É\8fI\97¹(&E)",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "\83v\83\8d\83O\83\89\83\80\82Ì\8fI\97¹ - "
+FONT 9, "MS UI Gothic"
+BEGIN
+ DEFPUSHBUTTON "\83L\83\83\83\93\83Z\83\8b",IDCANCEL,142,98,43,17
+ PUSHBUTTON "\82·\82®\82É\8fI\97¹(&E)",IDC_END_NOW,78,98,43,17
+ LTEXT "\82±\82Ì\83v\83\8d\83O\83\89\83\80\82Í\89\9e\93\9a\82µ\82Ä\82¢\82Ü\82¹\82ñ",IDC_STATIC,7,7,178,8
+ LTEXT "ReactOS \82É\96ß\82Á\82Ä\83v\83\8d\83O\83\89\83\80\82Ì\8fó\91Ô\82ð\8am\94F\82·\82é\82É\82Í[\83L\83\83\83\93\83Z\83\8b]\82ð\83N\83\8a\83b\83N\82µ\82Ä\82\82¾\82³\82¢",
+ IDC_STATIC,7,26,178,16
+ LTEXT "\83v\83\8d\83O\83\89\83\80\82ð\82·\82®\82É\8fI\97¹\82³\82¹\82é\82æ\82¤\91I\91ð\82µ\82½\8fê\8d\87\81A\95Û\91¶\82³\82ê\82Ä\82¢\82È\82¢\83f\81[\83^\82Í\82·\82×\82Ä\8e¸\82í\82ê\82Ü\82·\81B\83v\83\8d\83O\83\89\83\80\82ð\92¼\82¿\82É\8fI\97¹\82·\82é\82É\82Í[\82·\82®\82É\8fI\97¹]\82ð\83N\83\8a\83b\83N\82µ\82Ä\82\82¾\82³\82¢",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 9, "MS UI Gothic", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "\95Ò\8fW"
+ IDS_MARK "\94Í\88Í\8ew\92è"
+ IDS_COPY "\83R\83s\81[\tEnter"
+ IDS_PASTE "\93\\\82è\95t\82¯"
+ IDS_SELECTALL "\82·\82×\82Ä\91I\91ð"
+ IDS_SCROLL "\83X\83N\83\8d\81[\83\8b"
+ IDS_FIND "\8c\9f\8dõ..."
+ IDS_DEFAULTS "\8bK\92è\92l"
+ IDS_PROPERTIES "\83v\83\8d\83p\83e\83B"
+ IDS_SCROLLHERE "\82±\82±\82É\83X\83N\83\8d\81[\83\8b"
+ IDS_SCROLLTOP "\88ê\94Ô\8fã\82É\83X\83N\83\8d\81[\83\8b"
+ IDS_SCROLLBOTTOM "\88ê\94Ô\89º\82É\83X\83N\83\8d\81[\83\8b"
+ IDS_SCROLLPAGE_UP "Page up"
+ IDS_SCROLLPAGE_DOWN "Page down"
+ IDS_SCROLLUP "\8fã\82É\83X\83N\83\8d\81[\83\8b"
+ IDS_SCROLLDOWN "\89º\82É\83X\83N\83\8d\81[\83\8b"
+
+ IDS_COMMAND_PROMPT "Command Prompt"
+END
--- /dev/null
+LANGUAGE LANG_NORWEGIAN, SUBLANG_NEUTRAL
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Avslutt program - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Avslutt Program... Vennligst vent",IDC_STATIC,7,7,186,11
+ CONTROL "Progress",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Hvis du velger å avslutte programmet øyeblikkelig, vil du miste alt data som ikke er lagret. For å avslutte programmet nå, Trykk på Avslutt nå.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "&Avslutt nå",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Avslutt program - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Avbryt",IDCANCEL,142,98,43,17
+ PUSHBUTTON "&Avslutt nå",IDC_END_NOW,78,98,43,17
+ LTEXT "Programmet svarer ikke",IDC_STATIC,7,7,178,8
+ LTEXT "For å returnere til ReactOS for å sjekke statusen på programmet, trykk på avbryt",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Hvis du velger å avslutte programmet øyeblikkelig, vil du miste alt data som ikke er lagret. For å avslutte programmet nå, Trykk på Avslutt nå",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Rediger"
+ IDS_MARK "Merk"
+ IDS_COPY "Kopier\tEnter"
+ IDS_PASTE "Lim inn"
+ IDS_SELECTALL "Velg alt"
+ IDS_SCROLL "Rull"
+ IDS_FIND "Finn..."
+ IDS_DEFAULTS "Standard"
+ IDS_PROPERTIES "Egenskaper"
+ IDS_SCROLLHERE "Rull her"
+ IDS_SCROLLTOP "Rull til toppen"
+ IDS_SCROLLBOTTOM "Rull knapp"
+ IDS_SCROLLPAGE_UP "Side opp"
+ IDS_SCROLLPAGE_DOWN "Side ned"
+ IDS_SCROLLUP "Rull opp"
+ IDS_SCROLLDOWN "Rull ned"
+
+ IDS_COMMAND_PROMPT "Command Prompt"
+END
--- /dev/null
+/*
+ * translated by xrogers
+ * xxrogers@users.sourceforge.net
+ * https://sourceforge.net/projects/reactospl
+ * translation update by Olaf Siejka (Caemyr), Apr 2011
+ * UTF-8 conversion by Caemyr (May, 2011)
+ */
+
+LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Zakończ program - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Trwa zamykanie programu... Proszę czekać",IDC_STATIC,7,7,186,11
+ CONTROL "Postęp",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Jeśli zdecydujesz się zamknąć program natychmiastowo, utracisz wszelkie niezapisane dane. Aby zakończyć program, wciśnij Zakończ teraz.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "&Zakończ teraz",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Zakończ program - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Anuluj",IDCANCEL,142,98,43,17
+ PUSHBUTTON "&Zakończ teraz",IDC_END_NOW,78,98,43,17
+ LTEXT "Wybrany program nie odpowiada",IDC_STATIC,7,7,178,8
+ LTEXT "Aby powrócić do ReactOS i sprawdzić status programu, kliknij Anuluj",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Jeśli zdecydujesz się zamknąć program natychmiastowo, utracisz wszelkie niezapisane dane. Aby zakończyć program, wciśnij Zakończ teraz.",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Edytuj"
+ IDS_MARK "Zaznacz"
+ IDS_COPY "Kopiuj\tWejdź"
+ IDS_PASTE "Wklej"
+ IDS_SELECTALL "Zaznacz wszystko"
+ IDS_SCROLL "Przewiń"
+ IDS_FIND "Znajdź..."
+ IDS_DEFAULTS "Ustawienia domyślne"
+ IDS_PROPERTIES "Właściwości"
+ IDS_SCROLLHERE "Przewiń tutaj"
+ IDS_SCROLLTOP "Przewiń na początek"
+ IDS_SCROLLBOTTOM "Przewiń na koniec"
+ IDS_SCROLLPAGE_UP "Poprzednia strona"
+ IDS_SCROLLPAGE_DOWN "Następna strona"
+ IDS_SCROLLUP "Przewiń do góry"
+ IDS_SCROLLDOWN "Przewiń na dół"
+
+ IDS_COMMAND_PROMPT "Wiersz polecenia"
+END
--- /dev/null
+/* Translation and UTF-8 Conversion by mkbu95 <mkbu95@gmail.com> (May, 2012) */
+
+LANGUAGE LANG_PORTUGUESE, SUBLANG_NEUTRAL
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Finalizar Programa - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Finalizando Programa... Por favor aguarde",IDC_STATIC,7,7,186,11
+ CONTROL "Progress",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Se você finalizar o programa imediatamente, você irá perder qualquer alteração não salva. Para finalizar o programa agora, pressione Finalizar Agora.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "&Finalizar Agora",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Finalizar Programa - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Cancelar",IDCANCEL,142,98,43,17
+ PUSHBUTTON "&Finalizar Agora",IDC_END_NOW,78,98,43,17
+ LTEXT "O programa não está respondendo",IDC_STATIC,7,7,178,8
+ LTEXT "Parar retornar ao ReactOS e verificar o estado do programa, pressione Cancelar",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Se você finalizar o programa imediatamente, você irá perder qualquer alteração não salva. Para finalizar o programa agora, pressione Finalizar Agora",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Editar"
+ IDS_MARK "Marcar"
+ IDS_COPY "Copiar\tEnter"
+ IDS_PASTE "Colar"
+ IDS_SELECTALL "Selecionar Tudo"
+ IDS_SCROLL "Rolar"
+ IDS_FIND "Procurar..."
+ IDS_DEFAULTS "Padrões"
+ IDS_PROPERTIES "Propriedades"
+ IDS_SCROLLHERE "Rolar aqui"
+ IDS_SCROLLTOP "Rolar até o topo"
+ IDS_SCROLLBOTTOM "Rolar até o fim"
+ IDS_SCROLLPAGE_UP "Page up"
+ IDS_SCROLLPAGE_DOWN "Page down"
+ IDS_SCROLLUP "Scroll up"
+ IDS_SCROLLDOWN "Scroll down"
+
+ IDS_COMMAND_PROMPT "Prompt de Comando"
+END
--- /dev/null
+/*
+ * FILE: subsystems/win32/csrss/win32csr/lang/ro-RO.rc
+ * ReactOS Project (http://www.reactos.org)
+ * TRANSLATOR: Fulea Ștefan (PM on ReactOS Forum at fulea.stefan)
+ * CHANGE LOG: 2011-10-16 initial translation
+ */
+
+LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Terminare execuție - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Terminare execuție… așteptați",IDC_STATIC,7,7,186,11
+ CONTROL "Progress", IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Dacă alegeți închiderea forțată, riscați pierderi de date. Pentru a forța închiderea, apăsați „Termină forțat”.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "Termină &forțat",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Terminare execuție - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "A&nulează", IDCANCEL,142,98,43,17
+ PUSHBUTTON "Termină &forțat",IDC_END_NOW,78,98,43,17
+ LTEXT "Acest program nu răspunde",IDC_STATIC,7,7,178,8
+ LTEXT "Pentru a vă întoarce în ReactOS și a verifica starea programului, apăsați „Anulează”",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Dacă alegeți închiderea imediată a programului, riscați pierderi de date. Pentru a forța închiderea, apăsați „Termină forțat”.",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Editare"
+ IDS_MARK "Marchează"
+ IDS_COPY "Copiază\tEnter"
+ IDS_PASTE "Lipește"
+ IDS_SELECTALL "Selectează tot"
+ IDS_SCROLL "Derulează"
+ IDS_FIND "Găsire…"
+ IDS_DEFAULTS "Implicite"
+ IDS_PROPERTIES "Proprietăți"
+ IDS_SCROLLHERE "Derulează aici"
+ IDS_SCROLLTOP "Derulează la început"
+ IDS_SCROLLBOTTOM "Derulează la sfârșit"
+ IDS_SCROLLPAGE_UP "Pagina anterioară"
+ IDS_SCROLLPAGE_DOWN "Pagina următoare"
+ IDS_SCROLLUP "Derulează în sus"
+ IDS_SCROLLDOWN "Derulează în jos"
+
+ IDS_COMMAND_PROMPT "Linie de comandă"
+END
--- /dev/null
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Завершение программы - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Завершение программы... Пажалуйста подождите",IDC_STATIC,7,7,186,11
+ CONTROL "Progress",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Если вы завершите программу сейчас, то вы можете потерять несохраненные данные. Чтобы завешить программу сейчас нажмите ""Завершить""",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "&Завешить",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Завершение программы - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Отмена",IDCANCEL,142,98,43,17
+ PUSHBUTTON "&Завершить",IDC_END_NOW,78,98,43,17
+ LTEXT "Эта программа не отвечает",IDC_STATIC,7,7,178,8
+ LTEXT "Для возврата в ReactOS и сохранения данных нажмите ""Отмена""",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Если вы завершите программу сейчас, то вы можете потерять несохраненные данные. Чтобы завешить программу сейчас нажмите ""Завершить""",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Изменить"
+ IDS_MARK "Пометить"
+ IDS_COPY "Копировать\tEnter"
+ IDS_PASTE "Вставить"
+ IDS_SELECTALL "Выделить все"
+ IDS_SCROLL "Прокрутить"
+ IDS_FIND "Искать..."
+ IDS_DEFAULTS "Умолчания"
+ IDS_PROPERTIES "Свойства"
+ IDS_SCROLLHERE "Scroll Here"
+ IDS_SCROLLTOP "Scroll Top"
+ IDS_SCROLLBOTTOM "Прокрутить вниз"
+ IDS_SCROLLPAGE_UP "Вверх страницы"
+ IDS_SCROLLPAGE_DOWN "Вниз страницы"
+ IDS_SCROLLUP "Прокрутить вверх"
+ IDS_SCROLLDOWN "Scroll Down"
+
+ IDS_COMMAND_PROMPT "Command Prompt"
+END
--- /dev/null
+/* TRANSLATOR: Mário Kaèmár /Mario Kacmar/ aka Kario (kario@szm.sk)
+ * DATE OF TR: 29-05-2008
+ * LastChange: 12-04-2011
+ */
+
+LANGUAGE LANG_SLOVAK, SUBLANG_DEFAULT
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Ukonèenie programu - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Ukonèujem program... Poèkajte, prosím.",IDC_STATIC,7,7,186,11
+ CONTROL "Progress",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Ak zvolíte okam\9eité ukonèenie programu, stratíte v\9aetky neulo\9eené údaje. Ak chcete program ukonèi\9d okam\9eite, kliknite na tlaèidlo Ukonèi\9d ihneï.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "&Ukonèi\9d ihneï",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Ukonèenie programu - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Zru\9ai\9d",IDCANCEL,142,98,43,17
+ PUSHBUTTON "&Ukonèi\9d ihneï",IDC_END_NOW,78,98,43,17
+ LTEXT "Tento program neodpovedá.",IDC_STATIC,7,7,178,8
+ LTEXT "Pre návrat do systému ReactOS a overenie stavu programu kliknite na tlaèidlo Zru\9ai\9d.",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Ak zvolíte okam\9eité ukonèenie programu, stratíte v\9aetky neulo\9eené údaje. Ak chcete program ukonèi\9d okam\9eite, kliknite na tlaèidlo Ukonèi\9d ihneï.",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Upravi\9d"
+ IDS_MARK "Oznaèi\9d"
+ IDS_COPY "Kopírova\9d\tEnter"
+ IDS_PASTE "Vlo\9ei\9d"
+ IDS_SELECTALL "Vybra\9d v\9aetko"
+ IDS_SCROLL "Rolova\9d"
+ IDS_FIND "Nájs\9d..." //Find
+ IDS_DEFAULTS "Predvolené" //Defaults
+ IDS_PROPERTIES "Vlastnosti"
+ IDS_SCROLLHERE "Rolova\9d sem"
+ IDS_SCROLLTOP "K hornému okraju"
+ IDS_SCROLLBOTTOM "K dolnému okraju"
+ IDS_SCROLLPAGE_UP "O stránku vy\9a\9aie"
+ IDS_SCROLLPAGE_DOWN "O stránku ni\9e\9aie"
+ IDS_SCROLLUP "Rolova\9d nahor"
+ IDS_SCROLLDOWN "Rolova\9d nadol"
+
+ IDS_COMMAND_PROMPT "Príkazový riadok"
+END
--- /dev/null
+/*
+ * PROJECT: ReactOS CSRSS subsystem
+ * FILE: subsystems/win32/csrss/win32csr/lang/sv-SE.rc
+ * PURPOSE: Swedish resource file
+ * Translation: Jaix Bly
+ */
+
+LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "End Program - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Avsluta Program... Var vänlig vänta",IDC_STATIC,7,7,186,11
+ CONTROL "Progress",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Om du väljer att avsluta programmet omedelbart kommer du att förlora all osparad data. För att avsluta programmet, klicka Avsluta nu.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "&Avsluta Nu",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Avsluta Program - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Avbryt",IDCANCEL,142,98,43,17
+ PUSHBUTTON "&Avsluta Nu",IDC_END_NOW,78,98,43,17
+ LTEXT "Detta programmet svarar inte",IDC_STATIC,7,7,178,8
+ LTEXT "För att återgå till ReactOS och undersöka programmets status klicka Avbryt",
+ IDC_STATIC,7,26,178,16
+ LTEXT "m du väljer att avsluta programmet omedelbart kommer du att förlora all osparad data. För att avsluta programmet, klicka Avsluta nu.",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Redigera"
+ IDS_MARK "Markera"
+ IDS_COPY "Kopiera\tEnter"
+ IDS_PASTE "Klistra in"
+ IDS_SELECTALL "Markera Allt"
+ IDS_SCROLL "Skrolla"
+ IDS_FIND "Sök..."
+ IDS_DEFAULTS "Ursprunglig"
+ IDS_PROPERTIES "Egenskaper"
+ IDS_SCROLLHERE "Skrolla hit"
+ IDS_SCROLLTOP "Skrolla till topp"
+ IDS_SCROLLBOTTOM "Skrolla till botten"
+ IDS_SCROLLPAGE_UP "Sida upp"
+ IDS_SCROLLPAGE_DOWN "Sida ner"
+ IDS_SCROLLUP "Skrolla upp"
+ IDS_SCROLLDOWN "Skrolla ner"
+
+ IDS_COMMAND_PROMPT "Command Prompt"
+END
--- /dev/null
+/*
+ * Turkish resources
+ *
+ * Copyright 2012 Arda Tanrikulu <ardatanrikulu@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Programı Sonlandır - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Program Sonlandırılıyor... Lütfen bekleyin",IDC_STATIC,7,7,186,11
+ CONTROL "İşlem",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Programı hemen kapatmayı seçerseniz, kaydedilmemiş veriyi kaybedersiniz. Programdan şimdi çıkmak için Şimdi Sonlandır'ı tıklatın.",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "&Şimdi Sonlandır",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "End Program - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "İptal",IDCANCEL,142,98,43,17
+ PUSHBUTTON "Şimdi Sonlandır",IDC_END_NOW,78,98,43,17
+ LTEXT "Bu program yanıt vermiyor.",IDC_STATIC,7,7,178,8
+ LTEXT "ReactOS'a dönmek ve programın durumunu denetlemek için İptal'i tıklatın.",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Programı hemen kapatmayı seçerseniz, kaydedilmemiş veriyi kaybedersiniz. Programdan şimdi çıkmak için Şimdi Sonlandır'ı tıklatın.",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Düzenle"
+ IDS_MARK "İşaretle"
+ IDS_COPY "Kopyala\tEnter"
+ IDS_PASTE "Yapıştır"
+ IDS_SELECTALL "Tümünü Seç"
+ IDS_SCROLL "Yuvarla"
+ IDS_FIND "Bul..."
+ IDS_DEFAULTS "Varsayılanlar"
+ IDS_PROPERTIES "Özellikler"
+ IDS_SCROLLHERE "Buraya yuvarla"
+ IDS_SCROLLTOP "Üste yuvarla"
+ IDS_SCROLLBOTTOM "Alta yuvarla"
+ IDS_SCROLLPAGE_UP "Sayfa yukarı"
+ IDS_SCROLLPAGE_DOWN "Sayfa aşağı"
+ IDS_SCROLLUP "Yukarı yuvarla"
+ IDS_SCROLLDOWN "Aşağı yuvarla"
+
+ IDS_COMMAND_PROMPT "Komut İstemi"
+END
--- /dev/null
+/*
+ * PROJECT: ReactOS CSRSS subsystem
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: subsystems/win32/csrss/win32csr/lang/uk-UA.rc
+ * PURPOSE: Ukraianian resource file
+ * TRANSLATOR: Artem Reznikov
+ */
+
+LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Завершення програми - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Завершення програми... Зачекайте",IDC_STATIC,7,7,186,11
+ CONTROL "Прогрес",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Якщо завершити програму негайно, то можна втратити всі незбережені дані. Щоб завершити програму зараз, натисніть 'Завершити зараз'",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "&Завершити зараз",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Завершення програми - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Скасувати",IDCANCEL,142,98,43,17
+ PUSHBUTTON "&Завершити зараз",IDC_END_NOW,78,98,43,17
+ LTEXT "Ця програма не відповідає",IDC_STATIC,7,7,178,8
+ LTEXT "Щоб повернутися у ReactOS і перевірити стан програми, натисніть 'Скасувати'",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Якщо завершити програму негайно, то можна втратити всі незбережені дані. Щоб завершити програму зараз, натисніть 'Завершити зараз'",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "Редагувати"
+ IDS_MARK "Виділити"
+ IDS_COPY "Копіювати\tEnter"
+ IDS_PASTE "Вставити"
+ IDS_SELECTALL "Виділити все"
+ IDS_SCROLL "Прокрутити"
+ IDS_FIND "Знайти..."
+ IDS_DEFAULTS "Замовчування"
+ IDS_PROPERTIES "Властивості"
+ IDS_SCROLLHERE "Прокрутити сюди"
+ IDS_SCROLLTOP "Прокрутити на початок"
+ IDS_SCROLLBOTTOM "Прокрутити на кінець"
+ IDS_SCROLLPAGE_UP "Попередня сотрінка"
+ IDS_SCROLLPAGE_DOWN "Наступна сторінка"
+ IDS_SCROLLUP "Прокрутити догори"
+ IDS_SCROLLDOWN "Прокрутити донизу"
+
+ IDS_COMMAND_PROMPT "Командний рядок"
+END
--- /dev/null
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "ÖÕÖ¹³ÌÐò - "
+FONT 9, "MS Shell Dlg"
+BEGIN
+ LTEXT "ÕýÔÚÖÕÖ¹³ÌÐò... ÇëµÈ´ý",IDC_STATIC,7,7,186,11
+ CONTROL "½ø³Ì",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "Èç¹ûÄúÑ¡ÔñÁ¢¼´ÖÕÖ¹³ÌÐò£¬Äú½«Ê§È¥ËùÓÐδ±£´æµÄÊý¾Ý¡£ÈôÒªÁ¢¼´½áÊø³ÌÐò£¬µ¥»÷¡°Á¢¼´ÖÕÖ¹¡±¡£",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "Á¢¼´ÖÕÖ¹(&E)",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "ÖÕÖ¹³ÌÐò - "
+FONT 9, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "È¡Ïû",IDCANCEL,142,98,43,17
+ PUSHBUTTON "Á¢¼´ÖÕÖ¹(&E)",IDC_END_NOW,78,98,43,17
+ LTEXT "´Ë³ÌÐò²¢Î´ÏìÓ¦",IDC_STATIC,7,7,178,8
+ LTEXT "ÈôÒª·µ»ØÖÁ ReactOS ²¢¼ì²é¸Ã³ÌÐòµÄ״̬£¬Çëµã»÷¡°È¡Ïû¡±¡£",
+ IDC_STATIC,7,26,178,16
+ LTEXT "Èç¹ûÄúÑ¡ÔñÁ¢¼´ÖÕÖ¹³ÌÐò£¬Äú½«Ê§È¥ËùÓÐδ±£´æµÄÊý¾Ý¡£ÈôÒªÁ¢¼´½áÊø³ÌÐò£¬µ¥»÷¡°Á¢¼´ÖÕÖ¹¡±¡£",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 9, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "±à¼"
+ IDS_MARK "񈬀"
+ IDS_COPY "¸´ÖÆ\tEnter"
+ IDS_PASTE "ð¤Ìù"
+ IDS_SELECTALL "È«²¿Ñ¡Ôñ"
+ IDS_SCROLL "¹ö¶¯"
+ IDS_FIND "²éÕÒ..."
+ IDS_DEFAULTS "ĬÈÏ"
+ IDS_PROPERTIES "ÊôÐÔ"
+ IDS_SCROLLHERE "¹ö¶¯µ½´Ë"
+ IDS_SCROLLTOP "¹ö¶¯ÖÁ¶¥¶Ë"
+ IDS_SCROLLBOTTOM "¹ö¶¯ÖÁÄ©¶Ë"
+ IDS_SCROLLPAGE_UP "ÉÏÒ»Ò³"
+ IDS_SCROLLPAGE_DOWN "ÏÂÒ»Ò³"
+ IDS_SCROLLUP "ÏòÉϹö¶¯"
+ IDS_SCROLLDOWN "ÏòϹö¶¯"
+
+ IDS_COMMAND_PROMPT "Command Prompt"
+END
--- /dev/null
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL
+
+IDD_END_NOW DIALOGEX DISCARDABLE 0, 0, 200, 95
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "µ²§ôµ{¦¡"
+FONT 9, "MS Shell Dlg"
+BEGIN
+ LTEXT "¥¿¦bµ²§ôµ{¦¡... ½Ðµyµ¥",IDC_STATIC,7,7,186,11
+ CONTROL "Progress",IDC_PROGRESS,"msctls_progress32",WS_BORDER,
+ 7,20,186,13
+ LTEXT "¦pªG±z¿ï¾Ü¥ß§Yµ²§ôµ{¦¡¡A±z±N¥¢¥h©Ò¦³¥¼Àx¦sªº¸ê®Æ¡CYn¥ß§Yµ²§ôµ{¦¡¡A½Ð«ö¤U¡§¥ß§Yµ²§ô¡¨¡C",
+ IDC_STATIC,7,40,186,26
+ DEFPUSHBUTTON "¥ß§Yµ²§ô(&E)",IDC_END_NOW,150,71,43,17
+END
+
+IDD_NOT_RESPONDING DIALOGEX DISCARDABLE 0, 0, 192, 122
+STYLE DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "µ²§ôµ{¦¡ - "
+FONT 9, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "¨ú®ø",IDCANCEL,142,98,43,17
+ PUSHBUTTON "¥ß§Yµ²§ô(&E) ",IDC_END_NOW,78,98,43,17
+ LTEXT "¦¹µ{¦¡¨Ã¥¼ÅTÀ³",IDC_STATIC,7,7,178,8
+ LTEXT "Ynªð¦^¦Ü ReactOS ¨ÃÀ˵øµ{¦¡ªºª¬ºA¡A½Ð«ö¤U¡§¨ú®ø¡¨",
+ IDC_STATIC,7,26,178,16
+ LTEXT "¦pªG±z¿ï¾Ü¥ß§Yµ²§ôµ{¦¡¡A±z±N¥¢¥h©Ò¦³¥¼Àx¦sªº¸ê®Æ¡CYn¥ß§Yµ²§ôµ{¦¡¡A½Ð«ö¤U¡§¥ß§Yµ²§ô¡¨¡C",
+ IDC_STATIC,7,53,178,26
+END
+
+IDD_SWITCH_APP DIALOGEX 90, 90, 265, 170
+STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+FONT 9, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_CUR_APP,39,139,204,16,SS_SUNKEN,WS_EX_STATICEDGE
+END
+
+STRINGTABLE
+BEGIN
+ IDS_EDIT "½s¿è"
+ IDS_MARK "¼Ð°O"
+ IDS_COPY "½Æ»s\tEnter"
+ IDS_PASTE "ÂH¶K"
+ IDS_SELECTALL "¥þ³¡¿ï¾Ü"
+ IDS_SCROLL "ºu°Ê"
+ IDS_FIND "´M§ä..."
+ IDS_DEFAULTS "¹w³]"
+ IDS_PROPERTIES "ÄÝ©Ê"
+ IDS_SCROLLHERE "ºu°Ê¨ì¦¹ "
+ IDS_SCROLLTOP "ºu°Ê¨ì³»¸m"
+ IDS_SCROLLBOTTOM "ºu°Ê¨ì¥½ºÝ"
+ IDS_SCROLLPAGE_UP "¤W¤@¶"
+ IDS_SCROLLPAGE_DOWN "¤U¤@¶"
+ IDS_SCROLLUP "¦V¤Wºu°Ê"
+ IDS_SCROLLDOWN "¦V¤Uºu°Ê"
+
+ IDS_COMMAND_PROMPT "Command Prompt"
+END
--- /dev/null
+/*
+ * PROJECT: ReactOS CSRSS
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: subsystems/win32/csrss/win32csr/lineinput.c
+ * PURPOSE: Console line input functions
+ * PROGRAMMERS: Jeffrey Morlan
+ */
+
+/* INCLUDES ******************************************************************/
+
+#define NDEBUG
+#include "w32csr.h"
+#include <debug.h>
+
+typedef struct tagHISTORY_BUFFER
+{
+ LIST_ENTRY ListEntry;
+ WORD Position;
+ WORD MaxEntries;
+ WORD NumEntries;
+ PUNICODE_STRING Entries;
+ UNICODE_STRING ExeName;
+} HISTORY_BUFFER, *PHISTORY_BUFFER;
+
+/* FUNCTIONS *****************************************************************/
+
+static PHISTORY_BUFFER
+HistoryCurrentBuffer(PCSRSS_CONSOLE Console)
+{
+ /* TODO: use actual EXE name sent from process that called ReadConsole */
+ UNICODE_STRING ExeName = { 14, 14, L"cmd.exe" };
+ PLIST_ENTRY Entry = Console->HistoryBuffers.Flink;
+ PHISTORY_BUFFER Hist;
+
+ for (; Entry != &Console->HistoryBuffers; Entry = Entry->Flink)
+ {
+ Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
+ if (RtlEqualUnicodeString(&ExeName, &Hist->ExeName, FALSE))
+ return Hist;
+ }
+
+ /* Couldn't find the buffer, create a new one */
+ Hist = HeapAlloc(Win32CsrApiHeap, 0, sizeof(HISTORY_BUFFER) + ExeName.Length);
+ if (!Hist)
+ return NULL;
+ Hist->MaxEntries = Console->HistoryBufferSize;
+ Hist->NumEntries = 0;
+ Hist->Entries = HeapAlloc(Win32CsrApiHeap, 0, Hist->MaxEntries * sizeof(UNICODE_STRING));
+ if (!Hist->Entries)
+ {
+ HeapFree(Win32CsrApiHeap, 0, Hist);
+ return NULL;
+ }
+ Hist->ExeName.Length = Hist->ExeName.MaximumLength = ExeName.Length;
+ Hist->ExeName.Buffer = (PWCHAR)(Hist + 1);
+ memcpy(Hist->ExeName.Buffer, ExeName.Buffer, ExeName.Length);
+ InsertHeadList(&Console->HistoryBuffers, &Hist->ListEntry);
+ return Hist;
+}
+
+static VOID
+HistoryAddEntry(PCSRSS_CONSOLE Console)
+{
+ UNICODE_STRING NewEntry;
+ PHISTORY_BUFFER Hist;
+ INT i;
+
+ NewEntry.Length = NewEntry.MaximumLength = Console->LineSize * sizeof(WCHAR);
+ NewEntry.Buffer = Console->LineBuffer;
+
+ if (!(Hist = HistoryCurrentBuffer(Console)))
+ return;
+
+ /* Don't add blank or duplicate entries */
+ if (NewEntry.Length == 0 || Hist->MaxEntries == 0 ||
+ (Hist->NumEntries > 0 &&
+ RtlEqualUnicodeString(&Hist->Entries[Hist->NumEntries - 1], &NewEntry, FALSE)))
+ {
+ return;
+ }
+
+ if (Console->HistoryNoDup)
+ {
+ /* Check if this line has been entered before */
+ for (i = Hist->NumEntries - 1; i >= 0; i--)
+ {
+ if (RtlEqualUnicodeString(&Hist->Entries[i], &NewEntry, FALSE))
+ {
+ /* Just rotate the list to bring this entry to the end */
+ NewEntry = Hist->Entries[i];
+ memmove(&Hist->Entries[i], &Hist->Entries[i + 1],
+ (Hist->NumEntries - (i + 1)) * sizeof(UNICODE_STRING));
+ Hist->Entries[Hist->NumEntries - 1] = NewEntry;
+ Hist->Position = Hist->NumEntries - 1;
+ return;
+ }
+ }
+ }
+
+ if (Hist->NumEntries == Hist->MaxEntries)
+ {
+ /* List is full, remove oldest entry */
+ RtlFreeUnicodeString(&Hist->Entries[0]);
+ memmove(&Hist->Entries[0], &Hist->Entries[1],
+ --Hist->NumEntries * sizeof(UNICODE_STRING));
+ }
+
+ if (NT_SUCCESS(RtlDuplicateUnicodeString(0, &NewEntry, &Hist->Entries[Hist->NumEntries])))
+ Hist->NumEntries++;
+ Hist->Position = Hist->NumEntries - 1;
+}
+
+static VOID
+HistoryGetCurrentEntry(PCSRSS_CONSOLE Console, PUNICODE_STRING Entry)
+{
+ PHISTORY_BUFFER Hist;
+ if (!(Hist = HistoryCurrentBuffer(Console)) || Hist->NumEntries == 0)
+ Entry->Length = 0;
+ else
+ *Entry = Hist->Entries[Hist->Position];
+}
+
+static PHISTORY_BUFFER
+HistoryFindBuffer(PCSRSS_CONSOLE Console, PUNICODE_STRING ExeName)
+{
+ PLIST_ENTRY Entry = Console->HistoryBuffers.Flink;
+ while (Entry != &Console->HistoryBuffers)
+ {
+ /* For the history APIs, the caller is allowed to give only part of the name */
+ PHISTORY_BUFFER Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
+ if (RtlPrefixUnicodeString(ExeName, &Hist->ExeName, TRUE))
+ return Hist;
+ Entry = Entry->Flink;
+ }
+ return NULL;
+}
+
+VOID FASTCALL
+HistoryDeleteBuffer(PHISTORY_BUFFER Hist)
+{
+ if (!Hist)
+ return;
+ while (Hist->NumEntries != 0)
+ RtlFreeUnicodeString(&Hist->Entries[--Hist->NumEntries]);
+ HeapFree(Win32CsrApiHeap, 0, Hist->Entries);
+ RemoveEntryList(&Hist->ListEntry);
+ HeapFree(Win32CsrApiHeap, 0, Hist);
+}
+
+CSR_API(CsrGetCommandHistoryLength)
+{
+ PCSRSS_CONSOLE Console;
+ NTSTATUS Status;
+ PHISTORY_BUFFER Hist;
+ ULONG Length = 0;
+ INT i;
+
+ if (!Win32CsrValidateBuffer(ProcessData,
+ Request->Data.GetCommandHistoryLength.ExeName.Buffer,
+ Request->Data.GetCommandHistoryLength.ExeName.Length, 1))
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (NT_SUCCESS(Status))
+ {
+ Hist = HistoryFindBuffer(Console, &Request->Data.GetCommandHistory.ExeName);
+ if (Hist)
+ {
+ for (i = 0; i < Hist->NumEntries; i++)
+ Length += Hist->Entries[i].Length + sizeof(WCHAR);
+ }
+ Request->Data.GetCommandHistoryLength.Length = Length;
+ ConioUnlockConsole(Console);
+ }
+ return Status;
+}
+
+CSR_API(CsrGetCommandHistory)
+{
+ PCSRSS_CONSOLE Console;
+ NTSTATUS Status;
+ PHISTORY_BUFFER Hist;
+ PBYTE Buffer = (PBYTE)Request->Data.GetCommandHistory.History;
+ ULONG BufferSize = Request->Data.GetCommandHistory.Length;
+ INT i;
+
+ if (!Win32CsrValidateBuffer(ProcessData, Buffer, BufferSize, 1) ||
+ !Win32CsrValidateBuffer(ProcessData,
+ Request->Data.GetCommandHistory.ExeName.Buffer,
+ Request->Data.GetCommandHistory.ExeName.Length, 1))
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (NT_SUCCESS(Status))
+ {
+ Hist = HistoryFindBuffer(Console, &Request->Data.GetCommandHistory.ExeName);
+ if (Hist)
+ {
+ for (i = 0; i < Hist->NumEntries; i++)
+ {
+ if (BufferSize < (Hist->Entries[i].Length + sizeof(WCHAR)))
+ {
+ Status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+ memcpy(Buffer, Hist->Entries[i].Buffer, Hist->Entries[i].Length);
+ Buffer += Hist->Entries[i].Length;
+ *(PWCHAR)Buffer = L'\0';
+ Buffer += sizeof(WCHAR);
+ }
+ }
+ Request->Data.GetCommandHistory.Length = Buffer - (PBYTE)Request->Data.GetCommandHistory.History;
+ ConioUnlockConsole(Console);
+ }
+ return Status;
+}
+
+CSR_API(CsrExpungeCommandHistory)
+{
+ PCSRSS_CONSOLE Console;
+ PHISTORY_BUFFER Hist;
+ NTSTATUS Status;
+
+ if (!Win32CsrValidateBuffer(ProcessData,
+ Request->Data.ExpungeCommandHistory.ExeName.Buffer,
+ Request->Data.ExpungeCommandHistory.ExeName.Length, 1))
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (NT_SUCCESS(Status))
+ {
+ Hist = HistoryFindBuffer(Console, &Request->Data.ExpungeCommandHistory.ExeName);
+ HistoryDeleteBuffer(Hist);
+ ConioUnlockConsole(Console);
+ }
+ return Status;
+}
+
+CSR_API(CsrSetHistoryNumberCommands)
+{
+ PCSRSS_CONSOLE Console;
+ PHISTORY_BUFFER Hist;
+ NTSTATUS Status;
+ WORD MaxEntries = Request->Data.SetHistoryNumberCommands.NumCommands;
+ PUNICODE_STRING OldEntryList, NewEntryList;
+
+ if (!Win32CsrValidateBuffer(ProcessData,
+ Request->Data.SetHistoryNumberCommands.ExeName.Buffer,
+ Request->Data.SetHistoryNumberCommands.ExeName.Length, 1))
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (NT_SUCCESS(Status))
+ {
+ Hist = HistoryFindBuffer(Console, &Request->Data.SetHistoryNumberCommands.ExeName);
+ if (Hist)
+ {
+ OldEntryList = Hist->Entries;
+ NewEntryList = HeapAlloc(Win32CsrApiHeap, 0,
+ MaxEntries * sizeof(UNICODE_STRING));
+ if (!NewEntryList)
+ {
+ Status = STATUS_NO_MEMORY;
+ }
+ else
+ {
+ /* If necessary, shrink by removing oldest entries */
+ for (; Hist->NumEntries > MaxEntries; Hist->NumEntries--)
+ {
+ RtlFreeUnicodeString(Hist->Entries++);
+ Hist->Position += (Hist->Position == 0);
+ }
+
+ Hist->MaxEntries = MaxEntries;
+ Hist->Entries = memcpy(NewEntryList, Hist->Entries,
+ Hist->NumEntries * sizeof(UNICODE_STRING));
+ HeapFree(Win32CsrApiHeap, 0, OldEntryList);
+ }
+ }
+ ConioUnlockConsole(Console);
+ }
+ return Status;
+}
+
+CSR_API(CsrGetHistoryInfo)
+{
+ PCSRSS_CONSOLE Console;
+ NTSTATUS Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (NT_SUCCESS(Status))
+ {
+ Request->Data.SetHistoryInfo.HistoryBufferSize = Console->HistoryBufferSize;
+ Request->Data.SetHistoryInfo.NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers;
+ Request->Data.SetHistoryInfo.dwFlags = Console->HistoryNoDup;
+ ConioUnlockConsole(Console);
+ }
+ return Status;
+}
+
+CSR_API(CsrSetHistoryInfo)
+{
+ PCSRSS_CONSOLE Console;
+ NTSTATUS Status = ConioConsoleFromProcessData(ProcessData, &Console);
+ if (NT_SUCCESS(Status))
+ {
+ Console->HistoryBufferSize = (WORD)Request->Data.SetHistoryInfo.HistoryBufferSize;
+ Console->NumberOfHistoryBuffers = (WORD)Request->Data.SetHistoryInfo.NumberOfHistoryBuffers;
+ Console->HistoryNoDup = Request->Data.SetHistoryInfo.dwFlags & HISTORY_NO_DUP_FLAG;
+ ConioUnlockConsole(Console);
+ }
+ return Status;
+}
+
+static VOID
+LineInputSetPos(PCSRSS_CONSOLE Console, UINT Pos)
+{
+ if (Pos != Console->LinePos && Console->Mode & ENABLE_ECHO_INPUT)
+ {
+ PCSRSS_SCREEN_BUFFER Buffer = Console->ActiveBuffer;
+ UINT OldCursorX = Buffer->CurrentX;
+ UINT OldCursorY = Buffer->CurrentY;
+ INT XY = OldCursorY * Buffer->MaxX + OldCursorX;
+
+ XY += (Pos - Console->LinePos);
+ if (XY < 0)
+ XY = 0;
+ else if (XY >= Buffer->MaxY * Buffer->MaxX)
+ XY = Buffer->MaxY * Buffer->MaxX - 1;
+
+ Buffer->CurrentX = XY % Buffer->MaxX;
+ Buffer->CurrentY = XY / Buffer->MaxX;
+ ConioSetScreenInfo(Console, Buffer, OldCursorX, OldCursorY);
+ }
+
+ Console->LinePos = Pos;
+}
+
+static VOID
+LineInputEdit(PCSRSS_CONSOLE Console, UINT NumToDelete, UINT NumToInsert, WCHAR *Insertion)
+{
+ UINT Pos = Console->LinePos;
+ UINT NewSize = Console->LineSize - NumToDelete + NumToInsert;
+ INT i;
+
+ /* Make sure there's always enough room for ending \r\n */
+ if (NewSize + 2 > Console->LineMaxSize)
+ return;
+
+ memmove(&Console->LineBuffer[Pos + NumToInsert],
+ &Console->LineBuffer[Pos + NumToDelete],
+ (Console->LineSize - (Pos + NumToDelete)) * sizeof(WCHAR));
+ memcpy(&Console->LineBuffer[Pos], Insertion, NumToInsert * sizeof(WCHAR));
+
+ if (Console->Mode & ENABLE_ECHO_INPUT)
+ {
+ for (i = Pos; i < NewSize; i++)
+ {
+ CHAR AsciiChar;
+ WideCharToMultiByte(Console->OutputCodePage, 0,
+ &Console->LineBuffer[i], 1,
+ &AsciiChar, 1, NULL, NULL);
+ ConioWriteConsole(Console, Console->ActiveBuffer, &AsciiChar, 1, TRUE);
+ }
+ for (; i < Console->LineSize; i++)
+ {
+ ConioWriteConsole(Console, Console->ActiveBuffer, " ", 1, TRUE);
+ }
+ Console->LinePos = i;
+ }
+
+ Console->LineSize = NewSize;
+ LineInputSetPos(Console, Pos + NumToInsert);
+}
+
+static VOID
+LineInputRecallHistory(PCSRSS_CONSOLE Console, INT Offset)
+{
+ PHISTORY_BUFFER Hist;
+
+ if (!(Hist = HistoryCurrentBuffer(Console)) || Hist->NumEntries == 0)
+ return;
+
+ Offset += Hist->Position;
+ Offset = max(Offset, 0);
+ Offset = min(Offset, Hist->NumEntries - 1);
+ Hist->Position = Offset;
+
+ LineInputSetPos(Console, 0);
+ LineInputEdit(Console, Console->LineSize,
+ Hist->Entries[Offset].Length / sizeof(WCHAR),
+ Hist->Entries[Offset].Buffer);
+}
+
+VOID FASTCALL
+LineInputKeyDown(PCSRSS_CONSOLE Console, KEY_EVENT_RECORD *KeyEvent)
+{
+ UINT Pos = Console->LinePos;
+ PHISTORY_BUFFER Hist;
+ UNICODE_STRING Entry;
+ INT HistPos;
+
+ switch (KeyEvent->wVirtualKeyCode)
+ {
+ case VK_ESCAPE:
+ /* Clear entire line */
+ LineInputSetPos(Console, 0);
+ LineInputEdit(Console, Console->LineSize, 0, NULL);
+ return;
+ case VK_HOME:
+ /* Move to start of line. With ctrl, erase everything left of cursor */
+ LineInputSetPos(Console, 0);
+ if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
+ LineInputEdit(Console, Pos, 0, NULL);
+ return;
+ case VK_END:
+ /* Move to end of line. With ctrl, erase everything right of cursor */
+ if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
+ LineInputEdit(Console, Console->LineSize - Pos, 0, NULL);
+ else
+ LineInputSetPos(Console, Console->LineSize);
+ return;
+ case VK_LEFT:
+ /* Move left. With ctrl, move to beginning of previous word */
+ if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
+ {
+ while (Pos > 0 && Console->LineBuffer[Pos - 1] == L' ') Pos--;
+ while (Pos > 0 && Console->LineBuffer[Pos - 1] != L' ') Pos--;
+ }
+ else
+ {
+ Pos -= (Pos > 0);
+ }
+ LineInputSetPos(Console, Pos);
+ return;
+ case VK_RIGHT:
+ case VK_F1:
+ /* Move right. With ctrl, move to beginning of next word */
+ if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
+ {
+ while (Pos < Console->LineSize && Console->LineBuffer[Pos] != L' ') Pos++;
+ while (Pos < Console->LineSize && Console->LineBuffer[Pos] == L' ') Pos++;
+ LineInputSetPos(Console, Pos);
+ return;
+ }
+ else
+ {
+ /* Recall one character (but don't overwrite current line) */
+ HistoryGetCurrentEntry(Console, &Entry);
+ if (Pos < Console->LineSize)
+ LineInputSetPos(Console, Pos + 1);
+ else if (Pos * sizeof(WCHAR) < Entry.Length)
+ LineInputEdit(Console, 0, 1, &Entry.Buffer[Pos]);
+ }
+ return;
+ case VK_INSERT:
+ /* Toggle between insert and overstrike */
+ Console->LineInsertToggle = !Console->LineInsertToggle;
+ ConioSetCursorInfo(Console, Console->ActiveBuffer);
+ return;
+ case VK_DELETE:
+ /* Remove character to right of cursor */
+ if (Pos != Console->LineSize)
+ LineInputEdit(Console, 1, 0, NULL);
+ return;
+ case VK_PRIOR:
+ /* Recall first history entry */
+ LineInputRecallHistory(Console, -((WORD)-1));
+ return;
+ case VK_NEXT:
+ /* Recall last history entry */
+ LineInputRecallHistory(Console, +((WORD)-1));
+ return;
+ case VK_UP:
+ case VK_F5:
+ /* Recall previous history entry. On first time, actually recall the
+ * current (usually last) entry; on subsequent times go back. */
+ LineInputRecallHistory(Console, Console->LineUpPressed ? -1 : 0);
+ Console->LineUpPressed = TRUE;
+ return;
+ case VK_DOWN:
+ /* Recall next history entry */
+ LineInputRecallHistory(Console, +1);
+ return;
+ case VK_F3:
+ /* Recall remainder of current history entry */
+ HistoryGetCurrentEntry(Console, &Entry);
+ if (Pos * sizeof(WCHAR) < Entry.Length)
+ {
+ UINT InsertSize = (Entry.Length / sizeof(WCHAR) - Pos);
+ UINT DeleteSize = min(Console->LineSize - Pos, InsertSize);
+ LineInputEdit(Console, DeleteSize, InsertSize, &Entry.Buffer[Pos]);
+ }
+ return;
+ case VK_F6:
+ /* Insert a ^Z character */
+ KeyEvent->uChar.UnicodeChar = 26;
+ break;
+ case VK_F7:
+ if (KeyEvent->dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
+ HistoryDeleteBuffer(HistoryCurrentBuffer(Console));
+ return;
+ case VK_F8:
+ /* Search for history entries starting with input. */
+ if (!(Hist = HistoryCurrentBuffer(Console)) || Hist->NumEntries == 0)
+ return;
+
+ /* Like Up/F5, on first time start from current (usually last) entry,
+ * but on subsequent times start at previous entry. */
+ if (Console->LineUpPressed)
+ Hist->Position = (Hist->Position ? Hist->Position : Hist->NumEntries) - 1;
+ Console->LineUpPressed = TRUE;
+
+ Entry.Length = Console->LinePos * sizeof(WCHAR);
+ Entry.Buffer = Console->LineBuffer;
+
+ /* Keep going backwards, even wrapping around to the end,
+ * until we get back to starting point */
+ HistPos = Hist->Position;
+ do
+ {
+ if (RtlPrefixUnicodeString(&Entry, &Hist->Entries[HistPos], FALSE))
+ {
+ Hist->Position = HistPos;
+ LineInputEdit(Console, Console->LineSize - Pos,
+ Hist->Entries[HistPos].Length / sizeof(WCHAR) - Pos,
+ &Hist->Entries[HistPos].Buffer[Pos]);
+ /* Cursor stays where it was */
+ LineInputSetPos(Console, Pos);
+ return;
+ }
+ if (--HistPos < 0) HistPos += Hist->NumEntries;
+ } while (HistPos != Hist->Position);
+ return;
+ }
+
+ if (KeyEvent->uChar.UnicodeChar == L'\b' && Console->Mode & ENABLE_PROCESSED_INPUT)
+ {
+ /* backspace handling - if processed input enabled then we handle it here
+ * otherwise we treat it like a normal char. */
+ if (Pos > 0)
+ {
+ LineInputSetPos(Console, Pos - 1);
+ LineInputEdit(Console, 1, 0, NULL);
+ }
+ }
+ else if (KeyEvent->uChar.UnicodeChar == L'\r')
+ {
+ HistoryAddEntry(Console);
+
+ /* TODO: Expand aliases */
+
+ LineInputSetPos(Console, Console->LineSize);
+ Console->LineBuffer[Console->LineSize++] = L'\r';
+ if (Console->Mode & ENABLE_ECHO_INPUT)
+ ConioWriteConsole(Console, Console->ActiveBuffer, "\r", 1, TRUE);
+
+ /* Add \n if processed input. There should usually be room for it,
+ * but an exception to the rule exists: the buffer could have been
+ * pre-filled with LineMaxSize - 1 characters. */
+ if (Console->Mode & ENABLE_PROCESSED_INPUT &&
+ Console->LineSize < Console->LineMaxSize)
+ {
+ Console->LineBuffer[Console->LineSize++] = L'\n';
+ if (Console->Mode & ENABLE_ECHO_INPUT)
+ ConioWriteConsole(Console, Console->ActiveBuffer, "\n", 1, TRUE);
+ }
+ Console->LineComplete = TRUE;
+ Console->LinePos = 0;
+ }
+ else if (KeyEvent->uChar.UnicodeChar != L'\0')
+ {
+ if (KeyEvent->uChar.UnicodeChar < 0x20 &&
+ Console->LineWakeupMask & (1 << KeyEvent->uChar.UnicodeChar))
+ {
+ /* Control key client wants to handle itself (e.g. for tab completion) */
+ Console->LineBuffer[Console->LineSize++] = L' ';
+ Console->LineBuffer[Console->LinePos] = KeyEvent->uChar.UnicodeChar;
+ Console->LineComplete = TRUE;
+ Console->LinePos = 0;
+ }
+ else
+ {
+ /* Normal character */
+ BOOL Overstrike = Console->LineInsertToggle && Console->LinePos != Console->LineSize;
+ LineInputEdit(Console, Overstrike, 1, &KeyEvent->uChar.UnicodeChar);
+ }
+ }
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Win32 subsystem
+ * FILE: subsys/csrss/win32csr/resource.h
+ * PURPOSE: Resource #defines
+ */
+
+#pragma once
+
+#define IDD_END_NOW 10
+#define IDD_NOT_RESPONDING 11
+#define IDD_SWITCH_APP 12
+
+#define IDC_STATIC -1
+#define IDC_PROGRESS 101
+#define IDC_END_NOW 102
+#define IDC_STATIC_CUR_APP 103
+
+
+#define ID_SYSTEM_EDIT_MARK 1001
+#define ID_SYSTEM_EDIT_COPY 1002
+#define ID_SYSTEM_EDIT_PASTE 1003
+#define ID_SYSTEM_EDIT_SELECTALL 1004
+#define ID_SYSTEM_EDIT_SCROLL 1005
+#define ID_SYSTEM_EDIT_FIND 1006
+#define ID_SYSTEM_DEFAULTS 1007
+#define ID_SYSTEM_PROPERTIES 1008
+
+#define NCPOPUP_MENU 103
+
+#define IDS_EDIT 204
+#define IDS_MARK 205
+#define IDS_COPY 206
+#define IDS_PASTE 207
+#define IDS_SELECTALL 208
+#define IDS_SCROLL 209
+#define IDS_FIND 210
+#define IDS_DEFAULTS 211
+#define IDS_PROPERTIES 212
+
+//scrollbar resource ids
+#define IDS_SCROLLHERE 304
+#define IDS_SCROLLTOP 305
+#define IDS_SCROLLBOTTOM 306
+#define IDS_SCROLLPAGE_UP 307
+#define IDS_SCROLLPAGE_DOWN 308
+#define IDS_SCROLLUP 309
+#define IDS_SCROLLDOWN 310
+
+#define IDS_COMMAND_PROMPT 500
+
+/* EOF */
--- /dev/null
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+
+1 ICON DISCARDABLE res/terminal.ico
+
+#ifdef LANGUAGE_BG_BG
+ #include "lang/bg-BG.rc"
+#endif
+#ifdef LANGUAGE_CS_CZ
+ #include "lang/cs-CZ.rc"
+#endif
+#ifdef LANGUAGE_DE_DE
+ #include "lang/de-DE.rc"
+#endif
+#ifdef LANGUAGE_EL_GR
+ #include "lang/el-GR.rc"
+#endif
+#ifdef LANGUAGE_EN_US
+ #include "lang/en-US.rc"
+#endif
+#ifdef LANGUAGE_ES_ES
+ #include "lang/es-ES.rc"
+#endif
+#ifdef LANGUAGE_FR_FR
+ #include "lang/fr-FR.rc"
+#endif
+#ifdef LANGUAGE_ID_ID
+ #include "lang/id-ID.rc"
+#endif
+#ifdef LANGUAGE_IT_IT
+ #include "lang/it-IT.rc"
+#endif
+#ifdef LANGUAGE_JA_JP
+ #include "lang/ja-JP.rc"
+#endif
+#ifdef LANGUAGE_NB_NO
+ #include "lang/no-NO.rc"
+#endif
+#ifdef LANGUAGE_SK_SK
+ #include "lang/sk-SK.rc"
+#endif
+#ifdef LANGUAGE_SV_SE
+ #include "lang/sv-SE.rc"
+#endif
+#ifdef LANGUAGE_ZH_CN
+ #include "lang/zh-CN.rc"
+#endif
+#ifdef LANGUAGE_ZH_TW
+ #include "lang/zh-TW.rc"
+#endif
+
+// UTF-8
+#pragma code_page(65001)
+#ifdef LANGUAGE_HE_IL
+ #include "lang/he-IL.rc"
+#endif
+#ifdef LANGUAGE_PL_PL
+ #include "lang/pl-PL.rc"
+#endif
+#ifdef LANGUAGE_PT_BR
+ #include "lang/pt-BR.rc"
+#endif
+#ifdef LANGUAGE_RO_RO
+ #include "lang/ro-RO.rc"
+#endif
+#ifdef LANGUAGE_RU_RU
+ #include "lang/ru-RU.rc"
+#endif
+#ifdef LANGUAGE_UK_UA
+ #include "lang/uk-UA.rc"
+#endif
+#ifdef LANGUAGE_TR_TR
+ #include "lang/tr-TR.rc"
+#endif
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: subsys/csrss/win32csr/tuiconsole.c
+ * PURPOSE: Implementation of text-mode consoles
+ */
+
+#define NDEBUG
+#include "w32csr.h"
+#include <debug.h>
+
+CRITICAL_SECTION ActiveConsoleLock;
+static COORD PhysicalConsoleSize;
+static HANDLE ConsoleDeviceHandle;
+static PCSRSS_CONSOLE ActiveConsole;
+
+static BOOL ConsInitialized = FALSE;
+
+static LRESULT CALLBACK
+TuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg == WM_ACTIVATE)
+ {
+ if (LOWORD(wParam) != WA_INACTIVE)
+ {
+ SetFocus(hWnd);
+ ConioDrawConsole(ActiveConsole);
+ }
+ }
+ return DefWindowProcW(hWnd, msg, wParam, lParam);
+}
+
+static BOOL FASTCALL
+TuiStartService(LPCWSTR lpServiceName)
+{
+ SC_HANDLE hSCManager = NULL;
+ SC_HANDLE hService = NULL;
+ BOOL ret = FALSE;
+
+ hSCManager = OpenSCManagerW(NULL, NULL, 0);
+ if (hSCManager == NULL)
+ goto cleanup;
+
+ hService = OpenServiceW(hSCManager, lpServiceName, SERVICE_START);
+ if (hService == NULL)
+ goto cleanup;
+
+ ret = StartServiceW(hService, 0, NULL);
+ if (!ret)
+ goto cleanup;
+
+ ret = TRUE;
+
+cleanup:
+ if (hSCManager != NULL)
+ CloseServiceHandle(hSCManager);
+ if (hService != NULL)
+ CloseServiceHandle(hService);
+ return ret;
+}
+
+static BOOL FASTCALL
+TuiInit(DWORD OemCP)
+{
+ CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
+ DWORD BytesReturned;
+ WNDCLASSEXW wc;
+ USHORT TextAttribute = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
+
+ TuiStartService(L"Blue");
+
+ ConsoleDeviceHandle = CreateFileW(L"\\\\.\\BlueScreen", FILE_ALL_ACCESS, 0, NULL,
+ OPEN_EXISTING, 0, NULL);
+ if (INVALID_HANDLE_VALUE == ConsoleDeviceHandle)
+ {
+ DPRINT1("Failed to open BlueScreen.\n");
+ return FALSE;
+ }
+
+ if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_LOADFONT,
+ &OemCP, sizeof(OemCP), NULL, 0,
+ &BytesReturned, NULL))
+ {
+ DPRINT1("Failed to load the font for codepage %d\n", OemCP);
+ /* Let's suppose the font is good enough to continue */
+ }
+
+ if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE,
+ &TextAttribute, sizeof(TextAttribute), NULL, 0,
+ &BytesReturned, NULL))
+ {
+ DPRINT1("Failed to set text attribute\n");
+ }
+
+ ActiveConsole = NULL;
+ InitializeCriticalSection(&ActiveConsoleLock);
+ if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO,
+ NULL, 0, &ScrInfo, sizeof(ScrInfo), &BytesReturned, NULL))
+ {
+ DPRINT1("Failed to get console info\n");
+ return FALSE;
+ }
+ PhysicalConsoleSize = ScrInfo.dwSize;
+
+ RtlZeroMemory(&wc, sizeof(WNDCLASSEXW));
+ wc.cbSize = sizeof(WNDCLASSEXW);
+ wc.lpszClassName = L"TuiConsoleWindowClass";
+ wc.lpfnWndProc = TuiConsoleWndProc;
+ wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
+ if (RegisterClassExW(&wc) == 0)
+ {
+ DPRINT1("Failed to register console wndproc\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static VOID WINAPI
+TuiInitScreenBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buffer)
+{
+ Buffer->DefaultAttrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
+}
+
+static void FASTCALL
+TuiCopyRect(char *Dest, PCSRSS_SCREEN_BUFFER Buff, SMALL_RECT *Region)
+{
+ UINT SrcDelta, DestDelta;
+ LONG i;
+ PBYTE Src, SrcEnd;
+
+ Src = ConioCoordToPointer(Buff, Region->Left, Region->Top);
+ SrcDelta = Buff->MaxX * 2;
+ SrcEnd = Buff->Buffer + Buff->MaxY * Buff->MaxX * 2;
+ DestDelta = ConioRectWidth(Region) * 2;
+ for (i = Region->Top; i <= Region->Bottom; i++)
+ {
+ memcpy(Dest, Src, DestDelta);
+ Src += SrcDelta;
+ if (SrcEnd <= Src)
+ {
+ Src -= Buff->MaxY * Buff->MaxX * 2;
+ }
+ Dest += DestDelta;
+ }
+}
+
+static VOID WINAPI
+TuiDrawRegion(PCSRSS_CONSOLE Console, SMALL_RECT *Region)
+{
+ DWORD BytesReturned;
+ PCSRSS_SCREEN_BUFFER Buff = Console->ActiveBuffer;
+ PCONSOLE_DRAW ConsoleDraw;
+ UINT ConsoleDrawSize;
+
+ if (ActiveConsole != Console)
+ {
+ return;
+ }
+
+ ConsoleDrawSize = sizeof(CONSOLE_DRAW) +
+ (ConioRectWidth(Region) * ConioRectHeight(Region)) * 2;
+ ConsoleDraw = HeapAlloc(Win32CsrApiHeap, 0, ConsoleDrawSize);
+ if (NULL == ConsoleDraw)
+ {
+ DPRINT1("HeapAlloc failed\n");
+ return;
+ }
+ ConsoleDraw->X = Region->Left;
+ ConsoleDraw->Y = Region->Top;
+ ConsoleDraw->SizeX = ConioRectWidth(Region);
+ ConsoleDraw->SizeY = ConioRectHeight(Region);
+ ConsoleDraw->CursorX = Buff->CurrentX;
+ ConsoleDraw->CursorY = Buff->CurrentY;
+
+ TuiCopyRect((char *) (ConsoleDraw + 1), Buff, Region);
+
+ if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_DRAW,
+ NULL, 0, ConsoleDraw, ConsoleDrawSize, &BytesReturned, NULL))
+ {
+ DPRINT1("Failed to draw console\n");
+ HeapFree(Win32CsrApiHeap, 0, ConsoleDraw);
+ return;
+ }
+
+ HeapFree(Win32CsrApiHeap, 0, ConsoleDraw);
+}
+
+static VOID WINAPI
+TuiWriteStream(PCSRSS_CONSOLE Console, SMALL_RECT *Region, LONG CursorStartX, LONG CursorStartY,
+ UINT ScrolledLines, CHAR *Buffer, UINT Length)
+{
+ DWORD BytesWritten;
+ PCSRSS_SCREEN_BUFFER Buff = Console->ActiveBuffer;
+
+ if (ActiveConsole->ActiveBuffer != Buff)
+ {
+ return;
+ }
+
+ if (! WriteFile(ConsoleDeviceHandle, Buffer, Length, &BytesWritten, NULL))
+ {
+ DPRINT1("Error writing to BlueScreen\n");
+ }
+}
+
+static BOOL WINAPI
+TuiSetCursorInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
+{
+ CONSOLE_CURSOR_INFO Info;
+ DWORD BytesReturned;
+
+ if (ActiveConsole->ActiveBuffer != Buff)
+ {
+ return TRUE;
+ }
+
+ Info.dwSize = ConioEffectiveCursorSize(Console, 100);
+ Info.bVisible = Buff->CursorInfo.bVisible;
+
+ if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_CURSOR_INFO,
+ &Info, sizeof(Info), NULL, 0, &BytesReturned, NULL))
+ {
+ DPRINT1( "Failed to set cursor info\n" );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static BOOL WINAPI
+TuiSetScreenInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff, UINT OldCursorX, UINT OldCursorY)
+{
+ CONSOLE_SCREEN_BUFFER_INFO Info;
+ DWORD BytesReturned;
+
+ if (ActiveConsole->ActiveBuffer != Buff)
+ {
+ return TRUE;
+ }
+
+ Info.dwCursorPosition.X = Buff->CurrentX;
+ Info.dwCursorPosition.Y = Buff->CurrentY;
+ Info.wAttributes = Buff->DefaultAttrib;
+
+ if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO,
+ &Info, sizeof(CONSOLE_SCREEN_BUFFER_INFO), NULL, 0,
+ &BytesReturned, NULL))
+ {
+ DPRINT1( "Failed to set cursor position\n" );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static BOOL WINAPI
+TuiUpdateScreenInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
+{
+ return TRUE;
+}
+
+static BOOL WINAPI
+TuiChangeTitle(PCSRSS_CONSOLE Console)
+{
+ return TRUE;
+}
+
+static VOID WINAPI
+TuiCleanupConsole(PCSRSS_CONSOLE Console)
+{
+ DestroyWindow(Console->hWindow);
+
+ EnterCriticalSection(&ActiveConsoleLock);
+
+ /* Switch to next console */
+ if (ActiveConsole == Console)
+ {
+ ActiveConsole = Console->Next != Console ? Console->Next : NULL;
+ }
+
+ if (Console->Next != Console)
+ {
+ Console->Prev->Next = Console->Next;
+ Console->Next->Prev = Console->Prev;
+ }
+ LeaveCriticalSection(&ActiveConsoleLock);
+
+ if (NULL != ActiveConsole)
+ {
+ ConioDrawConsole(ActiveConsole);
+ }
+}
+
+static BOOL WINAPI
+TuiChangeIcon(PCSRSS_CONSOLE Console, HICON hWindowIcon)
+{
+ return TRUE;
+}
+
+static NTSTATUS WINAPI
+TuiResizeBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER ScreenBuffer, COORD Size)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+DWORD WINAPI
+TuiConsoleThread (PVOID Data)
+{
+ PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Data;
+ HWND NewWindow;
+ MSG msg;
+
+ NewWindow = CreateWindowW(L"TuiConsoleWindowClass",
+ Console->Title.Buffer,
+ 0,
+ -32000, -32000, 0, 0,
+ NULL, NULL,
+ (HINSTANCE) GetModuleHandleW(NULL),
+ (PVOID) Console);
+ Console->hWindow = NewWindow;
+ if (NULL == NewWindow)
+ {
+ DPRINT1("CSR: Unable to create console window\n");
+ return 1;
+ }
+
+ SetForegroundWindow(Console->hWindow);
+
+ while (TRUE)
+ {
+ GetMessageW(&msg, 0, 0, 0);
+ DispatchMessage(&msg);
+ TranslateMessage(&msg);
+
+ if (msg.message == WM_CHAR || msg.message == WM_SYSCHAR ||
+ msg.message == WM_KEYDOWN || msg.message == WM_KEYUP ||
+ msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP)
+ {
+ ConioProcessKey(&msg, Console, TRUE);
+ }
+ }
+
+ return 0;
+}
+
+static CSRSS_CONSOLE_VTBL TuiVtbl =
+{
+ TuiInitScreenBuffer,
+ TuiWriteStream,
+ TuiDrawRegion,
+ TuiSetCursorInfo,
+ TuiSetScreenInfo,
+ TuiUpdateScreenInfo,
+ TuiChangeTitle,
+ TuiCleanupConsole,
+ TuiChangeIcon,
+ TuiResizeBuffer,
+};
+
+NTSTATUS FASTCALL
+TuiInitConsole(PCSRSS_CONSOLE Console)
+{
+ HANDLE ThreadHandle;
+
+ if (! ConsInitialized)
+ {
+ ConsInitialized = TRUE;
+ if (! TuiInit(Console->CodePage))
+ {
+ ConsInitialized = FALSE;
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ Console->Vtbl = &TuiVtbl;
+ Console->hWindow = NULL;
+ Console->Size = PhysicalConsoleSize;
+ Console->ActiveBuffer->MaxX = PhysicalConsoleSize.X;
+ Console->ActiveBuffer->MaxY = PhysicalConsoleSize.Y;
+
+ ThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) TuiConsoleThread,
+ Console, 0, NULL);
+ if (NULL == ThreadHandle)
+ {
+ DPRINT1("CSR: Unable to create console thread\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+ CloseHandle(ThreadHandle);
+
+ EnterCriticalSection(&ActiveConsoleLock);
+ if (NULL != ActiveConsole)
+ {
+ Console->Prev = ActiveConsole;
+ Console->Next = ActiveConsole->Next;
+ ActiveConsole->Next->Prev = Console;
+ ActiveConsole->Next = Console;
+ }
+ else
+ {
+ Console->Prev = Console;
+ Console->Next = Console;
+ }
+ ActiveConsole = Console;
+ LeaveCriticalSection(&ActiveConsoleLock);
+
+ return STATUS_SUCCESS;
+}
+
+PCSRSS_CONSOLE FASTCALL
+TuiGetFocusConsole(VOID)
+{
+ return ActiveConsole;
+}
+
+BOOL FASTCALL
+TuiSwapConsole(int Next)
+{
+ static PCSRSS_CONSOLE SwapConsole = NULL; /* console we are thinking about swapping with */
+ DWORD BytesReturned;
+ ANSI_STRING Title;
+ void * Buffer;
+ COORD *pos;
+
+ if (0 != Next)
+ {
+ /* alt-tab, swap consoles */
+ /* move SwapConsole to next console, and print its title */
+ EnterCriticalSection(&ActiveConsoleLock);
+ if (! SwapConsole)
+ {
+ SwapConsole = ActiveConsole;
+ }
+
+ SwapConsole = (0 < Next ? SwapConsole->Next : SwapConsole->Prev);
+ Title.MaximumLength = RtlUnicodeStringToAnsiSize(&SwapConsole->Title);
+ Title.Length = 0;
+ Buffer = HeapAlloc(Win32CsrApiHeap,
+ 0,
+ sizeof(COORD) + Title.MaximumLength);
+ pos = (COORD *)Buffer;
+ Title.Buffer = (PVOID)((ULONG_PTR)Buffer + sizeof( COORD ));
+
+ RtlUnicodeStringToAnsiString(&Title, &SwapConsole->Title, FALSE);
+ pos->Y = PhysicalConsoleSize.Y / 2;
+ pos->X = (PhysicalConsoleSize.X - Title.Length) / 2;
+ /* redraw the console to clear off old title */
+ ConioDrawConsole(ActiveConsole);
+ if (! DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
+ NULL, 0, Buffer, sizeof(COORD) + Title.Length,
+ &BytesReturned, NULL))
+ {
+ DPRINT1( "Error writing to console\n" );
+ }
+ HeapFree(Win32CsrApiHeap, 0, Buffer);
+ LeaveCriticalSection(&ActiveConsoleLock);
+
+ return TRUE;
+ }
+ else if (NULL != SwapConsole)
+ {
+ EnterCriticalSection(&ActiveConsoleLock);
+ if (SwapConsole != ActiveConsole)
+ {
+ /* first remove swapconsole from the list */
+ SwapConsole->Prev->Next = SwapConsole->Next;
+ SwapConsole->Next->Prev = SwapConsole->Prev;
+ /* now insert before activeconsole */
+ SwapConsole->Next = ActiveConsole;
+ SwapConsole->Prev = ActiveConsole->Prev;
+ ActiveConsole->Prev->Next = SwapConsole;
+ ActiveConsole->Prev = SwapConsole;
+ }
+ ActiveConsole = SwapConsole;
+ SwapConsole = NULL;
+ ConioDrawConsole(ActiveConsole);
+ LeaveCriticalSection(&ActiveConsoleLock);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: subsys/csrss/win32csr/tuiconsole.h
+ * PURPOSE: Interface to text-mode consoles
+ */
+
+#include "api.h"
+
+extern NTSTATUS FASTCALL TuiInitConsole(PCSRSS_CONSOLE Console);
+extern PCSRSS_CONSOLE FASTCALL TuiGetFocusConsole(VOID);
+extern BOOL FASTCALL TuiSwapConsole(int Next);
+
+/* EOF */
--- /dev/null
+/* PSDK/NDK Headers */
+#define WIN32_NO_STATUS
+#define _INC_WINDOWS
+#define COM_NO_WINDOWS_H
+#include <stdio.h>
+#include <stdarg.h>
+#include <windef.h>
+#include <winbase.h>
+#include <wingdi.h>
+#include <winnls.h>
+#include <winreg.h>
+#include <winsvc.h>
+#include <wincon.h>
+#define NTOS_MODE_USER
+#include <ndk/iofuncs.h>
+#include <ndk/kefuncs.h>
+#include <ndk/mmfuncs.h>
+#include <ndk/obfuncs.h>
+#include <ndk/umfuncs.h>
+#include <psapi.h>
+
+/* External Winlogon Header */
+#include <winlogon.h>
+
+/* Internal CSRSS Headers */
+#include <conio.h>
+#include <csrplugin.h>
+#include <desktopbg.h>
+#include "guiconsole.h"
+#include "tuiconsole.h"
+
+/* Public Win32K Headers */
+#include <ntuser.h>
+
+#include "resource.h"
+
+/* shared header with console.dll */
+#include "console.h"
+
+VOID
+WINAPI
+Win32CsrHardError(
+ IN PCSR_THREAD ThreadData,
+ IN PHARDERROR_MSG Message);
+
+/* EOF */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * FILE: subsys/csrss/win32csr/win32csr.h
+ * PURPOSE: Interface to win32csr.dll
+ */
+
+#pragma once
+
+#include <objbase.h>
+
+extern HANDLE Win32CsrApiHeap;
+extern HINSTANCE Win32CsrDllHandle;
+
+typedef struct Object_tt
+{
+ LONG Type;
+ struct tagCSRSS_CONSOLE *Console;
+ LONG AccessRead, AccessWrite;
+ LONG ExclusiveRead, ExclusiveWrite;
+ LONG HandleCount;
+} Object_t;
+
+typedef struct _CSRSS_HANDLE
+{
+ Object_t *Object;
+ DWORD Access;
+ BOOL Inheritable;
+ DWORD ShareMode;
+} CSRSS_HANDLE, *PCSRSS_HANDLE;
+
+typedef VOID (WINAPI *CSR_CLEANUP_OBJECT_PROC)(Object_t *Object);
+
+typedef struct tagCSRSS_OBJECT_DEFINITION
+{
+ LONG Type;
+ CSR_CLEANUP_OBJECT_PROC CsrCleanupObjectProc;
+} CSRSS_OBJECT_DEFINITION, *PCSRSS_OBJECT_DEFINITION;
+
+/* handle.c */
+NTSTATUS FASTCALL Win32CsrInsertObject(PCSR_PROCESS ProcessData,
+ PHANDLE Handle,
+ Object_t *Object,
+ DWORD Access,
+ BOOL Inheritable,
+ DWORD ShareMode);
+NTSTATUS FASTCALL Win32CsrLockObject(PCSR_PROCESS ProcessData,
+ HANDLE Handle,
+ Object_t **Object,
+ DWORD Access,
+ long Type);
+VOID FASTCALL Win32CsrUnlockObject(Object_t *Object);
+NTSTATUS FASTCALL Win32CsrReleaseObject(PCSR_PROCESS ProcessData,
+ HANDLE Object);
+VOID WINAPI Win32CsrReleaseConsole(PCSR_PROCESS ProcessData);
+NTSTATUS WINAPI Win32CsrDuplicateHandleTable(PCSR_PROCESS SourceProcessData,
+ PCSR_PROCESS TargetProcessData);
+CSR_API(CsrGetHandle);
+CSR_API(CsrCloseHandle);
+CSR_API(CsrVerifyHandle);
+CSR_API(CsrDuplicateHandle);
+CSR_API(CsrGetInputWaitHandle);
+
+BOOL FASTCALL Win32CsrValidateBuffer(PCSR_PROCESS ProcessData,
+ PVOID Buffer,
+ SIZE_T NumElements,
+ SIZE_T ElementSize);
+NTSTATUS FASTCALL Win32CsrEnumProcesses(CSRSS_ENUM_PROCESS_PROC EnumProc,
+ PVOID Context);
+
+/* exitros.c */
+CSR_API(CsrExitReactos);
+CSR_API(CsrSetLogonNotifyWindow);
+CSR_API(CsrRegisterLogonProcess);
+
+CSR_API(CsrSoundSentry);
+
+/* EOF */
--- /dev/null
+#include <windef.h>
+#include <winuser.h>
+
+#include "resource.h"
+
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "CSRSS subsystem usermode code\0"
+#define REACTOS_STR_INTERNAL_NAME "win32csr\0"
+#define REACTOS_STR_ORIGINAL_FILENAME "win32csr.dll\0"
+#include <reactos/version.rc>
+
+#include "rsrc.rc"
--- /dev/null
+@ stdcall Win32CsrInitialization(ptr)