Synchronize with trunk r58606.
[reactos.git] / ntoskrnl / ps / win32.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/win32.c
5 * PURPOSE: Process Manager: Win32K Initialization and Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ****************************************************************/
10
11 #include <ntoskrnl.h>
12 #include <winerror.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS ******************************************************************/
17
18 PKWIN32_PROCESS_CALLOUT PspW32ProcessCallout = NULL;
19 PKWIN32_THREAD_CALLOUT PspW32ThreadCallout = NULL;
20 PGDI_BATCHFLUSH_ROUTINE KeGdiFlushUserBatch = NULL;
21 extern PKWIN32_PARSEMETHOD_CALLOUT ExpWindowStationObjectParse;
22 extern PKWIN32_DELETEMETHOD_CALLOUT ExpWindowStationObjectDelete;
23 extern PKWIN32_OKTOCLOSEMETHOD_CALLOUT ExpWindowStationObjectOkToClose;
24 extern PKWIN32_OKTOCLOSEMETHOD_CALLOUT ExpDesktopObjectOkToClose;
25 extern PKWIN32_DELETEMETHOD_CALLOUT ExpDesktopObjectDelete;
26 extern PKWIN32_OPENMETHOD_CALLOUT ExpDesktopObjectOpen;
27 extern PKWIN32_CLOSEMETHOD_CALLOUT ExpDesktopObjectClose;
28 extern PKWIN32_POWEREVENT_CALLOUT PopEventCallout;
29
30 /* PRIVATE FUNCTIONS *********************************************************/
31
32 NTSTATUS
33 NTAPI
34 PsConvertToGuiThread(VOID)
35 {
36 ULONG_PTR NewStack;
37 PVOID OldStack;
38 PETHREAD Thread = PsGetCurrentThread();
39 PEPROCESS Process = PsGetCurrentProcess();
40 NTSTATUS Status;
41 PAGED_CODE();
42
43 /* Validate the previous mode */
44 if (KeGetPreviousMode() == KernelMode) return STATUS_INVALID_PARAMETER;
45
46 /* If no win32k, crashes later */
47 ASSERT(PspW32ProcessCallout != NULL);
48
49 /* Make sure win32k is here */
50 if (!PspW32ProcessCallout) return STATUS_ACCESS_DENIED;
51
52 /* Make sure it's not already win32 */
53 if (Thread->Tcb.ServiceTable != KeServiceDescriptorTable)
54 {
55 /* We're already a win32 thread */
56 return STATUS_ALREADY_WIN32;
57 }
58
59 /* Check if we don't already have a kernel-mode stack */
60 if (!Thread->Tcb.LargeStack)
61 {
62 /* We don't create one */
63 NewStack = (ULONG_PTR)MmCreateKernelStack(TRUE, 0);
64 if (!NewStack)
65 {
66 /* Panic in user-mode */
67 NtCurrentTeb()->LastErrorValue = ERROR_NOT_ENOUGH_MEMORY;
68 return STATUS_NO_MEMORY;
69 }
70
71 /* We're about to switch stacks. Enter a guarded region */
72 KeEnterGuardedRegion();
73
74 /* Switch stacks */
75 OldStack = KeSwitchKernelStack((PVOID)NewStack,
76 (PVOID)(NewStack - KERNEL_STACK_SIZE));
77
78 /* Leave the guarded region */
79 KeLeaveGuardedRegion();
80
81 /* Delete the old stack */
82 MmDeleteKernelStack(OldStack, FALSE);
83 }
84
85 /* This check is bizare. Check out win32k later */
86 if (!Process->Win32Process)
87 {
88 /* Now tell win32k about us */
89 Status = PspW32ProcessCallout(Process, TRUE);
90 if (!NT_SUCCESS(Status)) return Status;
91 }
92
93 /* Set the new service table */
94 Thread->Tcb.ServiceTable = KeServiceDescriptorTableShadow;
95 ASSERT(Thread->Tcb.Win32Thread == 0);
96
97 /* Tell Win32k about our thread */
98 Status = PspW32ThreadCallout(Thread, PsW32ThreadCalloutInitialize);
99 if (!NT_SUCCESS(Status))
100 {
101 /* Revert our table */
102 Thread->Tcb.ServiceTable = KeServiceDescriptorTable;
103 }
104
105 /* Return status */
106 return Status;
107 }
108
109 /* PUBLIC FUNCTIONS **********************************************************/
110
111 /*
112 * @implemented
113 */
114 VOID
115 NTAPI
116 PsEstablishWin32Callouts(IN PWIN32_CALLOUTS_FPNS CalloutData)
117 {
118 /* Setup the callback pointers */
119 PspW32ProcessCallout = CalloutData->ProcessCallout;
120 PspW32ThreadCallout = CalloutData->ThreadCallout;
121 ExpWindowStationObjectParse = CalloutData->WindowStationParseProcedure;
122 ExpWindowStationObjectDelete = CalloutData->WindowStationDeleteProcedure;
123 ExpWindowStationObjectOkToClose = CalloutData->WindowStationOkToCloseProcedure;
124 ExpDesktopObjectOkToClose = CalloutData->DesktopOkToCloseProcedure;
125 ExpDesktopObjectDelete = CalloutData->DesktopDeleteProcedure;
126 ExpDesktopObjectOpen = CalloutData->DesktopOpenProcedure;
127 ExpDesktopObjectClose = CalloutData->DesktopCloseProcedure;
128 PopEventCallout = CalloutData->PowerEventCallout;
129 KeGdiFlushUserBatch = CalloutData->BatchFlushRoutine;
130 }
131
132 NTSTATUS
133 NTAPI
134 NtW32Call(IN ULONG RoutineIndex,
135 IN PVOID Argument,
136 IN ULONG ArgumentLength,
137 OUT PVOID* Result,
138 OUT PULONG ResultLength)
139 {
140 PVOID RetResult;
141 ULONG RetResultLength;
142 NTSTATUS Status;
143 ASSERT(KeGetPreviousMode() != KernelMode);
144
145 /* Enter SEH for probing */
146 _SEH2_TRY
147 {
148 /* Probe arguments */
149 ProbeForWritePointer(Result);
150 ProbeForWriteUlong(ResultLength);
151 }
152 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
153 {
154 /* Return the exception code */
155 _SEH2_YIELD(return _SEH2_GetExceptionCode());
156 }
157 _SEH2_END;
158
159 /* Call kernel function */
160 Status = KeUserModeCallback(RoutineIndex,
161 Argument,
162 ArgumentLength,
163 &RetResult,
164 &RetResultLength);
165 if (NT_SUCCESS(Status))
166 {
167 /* Enter SEH for write back */
168 _SEH2_TRY
169 {
170 /* Return results to user mode */
171 *Result = RetResult;
172 *ResultLength = RetResultLength;
173 }
174 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
175 {
176 /* Get the exception code */
177 Status = _SEH2_GetExceptionCode();
178 }
179 _SEH2_END;
180 }
181
182 /* Return the result */
183 return Status;
184 }
185
186 /* EOF */